march-hare 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +491 -211
  2. package/dist/actions/index.d.ts +46 -0
  3. package/dist/{hooks → actions}/utils.d.ts +0 -39
  4. package/dist/app/index.d.ts +132 -0
  5. package/dist/app/types.d.ts +82 -0
  6. package/dist/boundary/components/broadcast/utils.d.ts +1 -1
  7. package/dist/boundary/components/env/index.d.ts +26 -0
  8. package/dist/boundary/components/env/types.d.ts +11 -0
  9. package/dist/boundary/components/env/utils.d.ts +36 -0
  10. package/dist/boundary/components/scope/index.d.ts +1 -39
  11. package/dist/boundary/components/scope/types.d.ts +17 -13
  12. package/dist/boundary/components/scope/utils.d.ts +12 -8
  13. package/dist/boundary/components/sharing/index.d.ts +43 -0
  14. package/dist/boundary/components/tap/index.d.ts +36 -0
  15. package/dist/boundary/components/tap/types.d.ts +150 -0
  16. package/dist/boundary/components/tap/utils.d.ts +14 -0
  17. package/dist/boundary/index.d.ts +10 -10
  18. package/dist/boundary/types.d.ts +46 -14
  19. package/dist/cache/index.d.ts +4 -4
  20. package/dist/coalesce/index.d.ts +57 -0
  21. package/dist/context/index.d.ts +41 -0
  22. package/dist/context/types.d.ts +14 -0
  23. package/dist/error/index.d.ts +1 -1
  24. package/dist/error/types.d.ts +8 -19
  25. package/dist/index.d.ts +9 -13
  26. package/dist/march-hare.js +8 -5
  27. package/dist/march-hare.umd.cjs +1 -1
  28. package/dist/resource/index.d.ts +55 -78
  29. package/dist/resource/types.d.ts +87 -11
  30. package/dist/resource/utils.d.ts +1 -1
  31. package/dist/scope/index.d.ts +63 -0
  32. package/dist/scope/types.d.ts +55 -0
  33. package/dist/types/index.d.ts +108 -58
  34. package/dist/utils/index.d.ts +6 -5
  35. package/dist/with/index.d.ts +111 -0
  36. package/package.json +1 -1
  37. package/dist/boundary/components/store/index.d.ts +0 -41
  38. package/dist/boundary/components/store/types.d.ts +0 -11
  39. package/dist/boundary/components/store/utils.d.ts +0 -64
  40. package/dist/hooks/index.d.ts +0 -83
  41. /package/dist/{hooks → actions}/types.d.ts +0 -0
@@ -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),a=(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");static Name=Symbol("march-hare.brand/Name")}function d(e){const t=Symbol(`march-hare.action.lifecycle/${e}`),n=function(n){return{[f.Action]:t,[f.Payload]:void 0,[f.Channel]:n,[f.Name]:e,channel:n}};return Object.defineProperty(n,f.Action,{value:t,enumerable:!1}),Object.defineProperty(n,f.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(n,f.Name,{value:e,enumerable:!1}),n}const p=Symbol(i("Fault")),h=Symbol(i("Store"));class m{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}),Object.defineProperty(e,f.Name,{value:"Fault",enumerable:!1}),e})();static Store=(()=>{const e={};return Object.defineProperty(e,f.Action,{value:h,enumerable:!1}),Object.defineProperty(e,f.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(e,f.Broadcast,{value:!0,enumerable:!1}),Object.defineProperty(e,f.Name,{value:"Store",enumerable:!1}),e})()}var b=(e=>(e.Unicast="unicast",e.Broadcast="broadcast",e.Multicast="multicast",e))(b||{}),y=(e=>(e.Mounting="mounting",e.Mounted="mounted",e.Unmounting="unmounting",e.Unmounted="unmounted",e))(y||{});const v=e=>"symbol"==typeof e;function g(e){return t.G.isString(e)||v(e)?e:(t.G.isObject(e)||t.G.isFunction(e))&&f.Action in e?e[f.Action]:e}function w(e){if(t.G.isString(e))return e.startsWith(i());if(v(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 j(e){const n=g(e),r=t.G.isString(n)?n:n.description??"";return r.startsWith(a())&&r.slice(r.lastIndexOf("/")+1)||"unknown"}function O(e){return t.G.isObject(e)&&f.Channel in e&&"channel"in e}function S(e){const t=g(e),n=v(t)?t.description??"":t;return n.startsWith(l())&&n.slice(l().length)||null}function P(e){if(t.G.isString(e))return e.startsWith(u());if(v(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 x=(e=>(e[e.Timedout=0]="Timedout",e[e.Supplanted=1]="Supplanted",e[e.Errored=2]="Errored",e))(x||{});class E extends Error{name="AbortError";constructor(e="Aborted"){super(e)}}class M extends Error{name="TimeoutError";constructor(e="Timeout"){super(e)}}let C=(e=21)=>{let t="",n=crypto.getRandomValues(new Uint8Array(e|=0));for(;e--;)t+="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"[63&n[e]];return t};var 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||{}),G=(e=>(e[e.Produce=0]="Produce",e[e.Hydrate=1]="Hydrate",e))(G||{}),k=(e=>(e.Property="property",e.Process="process",e.Value="value",e.Operation="operation",e))(k||{});class N{[n.immerable]=!0;static keys=new Set(Object.values(k));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 _{static immer=(()=>{n.enablePatches();const e=new n.Immer;return e.setAutoFreeze(!1),e})();static tag="κ";static id=C}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 T(e){if(t.G.isNullable(e)||B(e))return e;if(t.G.isArray(e))return e.map(e=>T(e));if(t.G.isObject(e)&&L(e)){const t=Object.entries(e).map(([e,t])=>[e,T(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 L(e){const t=Object.getPrototypeOf(e);return t===Object.prototype||null===t}function B(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 F(e,n,r,o,s,c){return function a(i,u=n.path){if(i instanceof N){const n=R(r,u.join("."));if(Object.entries(i).filter(([e,t])=>!N.keys.has(e)&&t instanceof N).forEach(([e,t])=>a(t,u.concat(e))),B(i.value)){if(e===G.Hydrate)return i.value;const a=u.slice(0,-1),l=a.length>0?R(r,a.join(".")):r;return t.G.isNullable(l)||W(l,i,u.at(-1),o,s,c),n??i.value}if(e===G.Hydrate){const e=T(a(i.value,u));return W(e,i,null,o,s,c),e}const l=n??T(i.value);return W(l,i,null,o,s,c),t.G.isNullable(n)?l:(a(i.value,u),n)}if(t.G.isArray(i))return i.map((e,t)=>a(e,u.concat(t)));if(t.G.isObject(i)&&!L(i))return i;if(t.G.isObject(i)){const t=Object.entries(i).map(([e,t])=>[e,a(t,u.concat(e))]),n=Object.fromEntries(t);if(e===G.Hydrate){const e=T(n);return Object.entries(i).forEach(([t,n])=>{n instanceof N&&B(n.value)&&W(e,n,t,o,s,c)}),e}return n}return i}(n.value)}function W(e,t,n,r,o,s){const c=s(e),a=o.get(c)??[];o.set(c,[t.assign(n,r),...a])}class ${#e={};#t;#n=new Map;#r=new Set;#o=!1;constructor(e=U){this.#t=e}static pk(){return C()}static"κ"=$.pk;annotate(e,t){return new N(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),a=o.slice(0,-1),i=t.A.isNotEmpty(a)?R(e(),a):e();return[...t.G.isObject(c)||t.G.isArray(c)?n.get(r(c))?.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:(a,i)=>"pending"===i?()=>!t.A.isEmpty(c(r)):"remaining"===i?()=>t.A.length(c(r)):"box"===i?()=>({value:R(e(),r),inspect:n(r)}):"is"===i?e=>c(r).some(t=>0!==(t.operation&e)):"draft"===i?()=>t.A.head(c(r))?.value??R(e(),r):"settled"===i?()=>new Promise(n=>{if(t.A.isEmpty(c(r)))return n(R(e(),r));const a=()=>{t.A.isEmpty(c(r))&&(s(a),n(R(e(),r)))};o(a)}):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(G.Hydrate,()=>e)}produce(e){if(!this.#o)throw new Error("State must be hydrated using hydrate() before calling produce()");return this.#s(G.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:F(e,r,t,n,this.#n,this.#t)}]),this.#e),this.#e=T(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 D=new $;function I(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var H,q={exports:{}},z=(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 a=new o(r,s||e,c),i=n?n+t:t;return e._events[i]?e._events[i].fn?e._events[i]=[e._events[i],a]:e._events[i].push(a):(e._events[i]=a,e._eventsCount++),e}function c(e,t){0===--e._eventsCount?e._events=new r:delete e._events[t]}function a(){this._events=new r,this._eventsCount=0}Object.create&&(r.prototype=Object.create(null),(new r).__proto__||(n=!1)),a.prototype.eventNames=function(){var e,r,o=[];if(0===this._eventsCount)return o;for(r in e=this._events)t.call(e,r)&&o.push(n?r.slice(1):r);return Object.getOwnPropertySymbols?o.concat(Object.getOwnPropertySymbols(e)):o},a.prototype.listeners=function(e){var t=this._events[n?n+e:e];if(!t)return[];if(t.fn)return[t.fn];for(var r=0,o=t.length,s=new Array(o);r<o;r++)s[r]=t[r].fn;return s},a.prototype.listenerCount=function(e){var t=this._events[n?n+e:e];return t?t.fn?1:t.length:0},a.prototype.emit=function(e,t,r,o,s,c){var a=n?n+e:e;if(!this._events[a])return!1;var i,u,l=this._events[a],f=arguments.length;if(l.fn){switch(l.once&&this.removeListener(e,l.fn,void 0,!0),f){case 1:return l.fn.call(l.context),!0;case 2:return l.fn.call(l.context,t),!0;case 3:return l.fn.call(l.context,t,r),!0;case 4:return l.fn.call(l.context,t,r,o),!0;case 5:return l.fn.call(l.context,t,r,o,s),!0;case 6:return l.fn.call(l.context,t,r,o,s,c),!0}for(u=1,i=new Array(f-1);u<f;u++)i[u-1]=arguments[u];l.fn.apply(l.context,i)}else{var d,p=l.length;for(u=0;u<p;u++)switch(l[u].once&&this.removeListener(e,l[u].fn,void 0,!0),f){case 1:l[u].fn.call(l[u].context);break;case 2:l[u].fn.call(l[u].context,t);break;case 3:l[u].fn.call(l[u].context,t,r);break;case 4:l[u].fn.call(l[u].context,t,r,o);break;default:if(!i)for(d=1,i=new Array(f-1);d<f;d++)i[d-1]=arguments[d];l[u].fn.apply(l[u].context,i)}}return!0},a.prototype.on=function(e,t,n){return s(this,e,t,n,!1)},a.prototype.once=function(e,t,n){return s(this,e,t,n,!0)},a.prototype.removeListener=function(e,t,r,o){var s=n?n+e:e;if(!this._events[s])return this;if(!t)return c(this,s),this;var a=this._events[s];if(a.fn)a.fn!==t||o&&!a.once||r&&a.context!==r||c(this,s);else{for(var i=0,u=[],l=a.length;i<l;i++)(a[i].fn!==t||o&&!a[i].once||r&&a[i].context!==r)&&u.push(a[i]);u.length?this._events[s]=1===u.length?u[0]:u:c(this,s)}return this},a.prototype.removeAllListeners=function(e){var t;return e?this._events[t=n?n+e:e]&&c(this,t):(this._events=new r,this._eventsCount=0),this},a.prototype.off=a.prototype.removeListener,a.prototype.addListener=a.prototype.on,a.prefixed=n,a.EventEmitter=a,e.exports=a}(q)),q.exports);const J=I(z);class K extends J{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 K);function Q(){return c.useContext(V)}function X({children:e}){const t=c.useMemo(()=>new K,[]);return r.jsx(V.Provider,{value:t,children:e})}const Y=c.createContext(new Set);function Z({children:e}){const t=c.useMemo(()=>new Set,[]);return r.jsx(Y.Provider,{value:t,children:e})}const ee=c.createContext({current:{}});function te(){const e=c.useContext(ee);return c.useMemo(()=>new Proxy({},{get:(t,n)=>Reflect.get(e.current,n),has:(t,n)=>n in e.current,ownKeys:()=>Reflect.ownKeys(e.current),getOwnPropertyDescriptor(t,n){const r=Object.getOwnPropertyDescriptor(e.current,n);if(void 0!==r)return{...r,configurable:!0}},set(){throw new TypeError("Store is read-only outside `context.actions.produce`. Mutate via produce(({ store }) => { store.x = ... }) instead.")}}),[e])}function ne({initial:e,children:t}){const n=c.useRef(e),o=Q();return void 0===o.getCached(h)&&o.setCache(h,n.current),r.jsx(ee.Provider,{value:n,children:t})}const re=c.createContext(null);function oe(){return c.useContext(re)}function se(e,t){return e?.get(t)??null}const ce=Symbol(((e="")=>`march-hare/replay${e}`)());function ae(e,t,...n){e instanceof K&&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 ie(e,t){for(const n of e.keys())if(S(n)===t)return n;return null}const ue=Symbol("march-hare.unset");function le(){const[,e]=c.useReducer(e=>e+1,0);return e}function fe(){return{data:ue,at:null,else:e=>e}}function de(e,t){return{data:e,at:t,else:t=>e}}function pe(e){if(e instanceof Error){if("TimeoutError"===e.name)return x.Timedout;if("AbortError"===e.name)return x.Supplanted}return x.Errored}function he(e){const t=new Map,n=e??{get:e=>t.get(e)??null,set:(e,n)=>{t.set(e,n)},remove:e=>{t.delete(e)},clear:()=>{t.clear()}};return{get(e){try{const t=n.get(e);if(null===t)return fe();const r=JSON.parse(t);return de(r.data,Temporal.Instant.from(r.at))}catch{return fe()}},set(e,t){if(t.data===ue||null===t.at)return!1;try{return n.set(e,JSON.stringify({data:t.data,at:t.at.toString()})),!0}catch{return!1}},remove(e){n.remove(e)},clear(){n.clear()}}}function me(e,t){return new Promise((n,r)=>{if(t?.aborted)return void r(new E);const o=setTimeout(n,e);t?.addEventListener("abort",()=>{clearTimeout(o),r(new E)},{once:!0})})}async function be(e,t,n){if(t?.aborted)throw new E;for(;;){if(await n())return;await me(e,t)}}function ye(e){return e?Boolean(e&&"symbol"!=typeof e):Symbol(`pk.${Date.now()}.${crypto.randomUUID()}`)}const ve=Object.freeze(Object.defineProperty({__proto__:null,pk:ye,poll:be,sleep:me,unset:ue,"ζ":me,"κ":ye,"π":be},Symbol.toStringTag,{value:"Module"})),ge=new WeakMap;function we(e){return JSON.stringify(e)}let je=null;function Oe(){if(null===je)throw new Error("context.actions.resource(...) and context.actions.resource.set(...) must be called with a fresh resource invocation, e.g. context.actions.resource(cat({ id: 5 })).");const e=je;return je=null,e}const Se=c.createContext(new Map);function Pe({action:e,renderer:n}){const r=Q(),o=c.useContext(Se),s=le(),a=c.useMemo(()=>{const t=o.get(e);if(t)return t;const n=new $,s=r.getCached(e);void 0!==s&&n.hydrate({value:s});const c={state:n,listeners:new Set};return o.set(e,c),c},[e,r,o]);c.useLayoutEffect(()=>{function t(e){a.state.hydrate({value:e}),a.listeners.forEach(e=>e())}return a.listeners.add(s),r.on(e,t),()=>{a.listeners.delete(s),r.off(e,t)}},[e,r,a]);const i=a.state.model?.value;return t.G.isNullable(i)?null:n(i,a.state.inspect.value)}e.AbortError=E,e.Action=(e="",t=b.Unicast)=>{const n=t===b.Broadcast?Symbol(i(e)):t===b.Multicast?Symbol(u(e)):Symbol(a(e)),r=function(t){return{[f.Action]:n,[f.Payload]:void 0,[f.Channel]:t,[f.Name]:e,channel:t}};return Object.defineProperty(r,f.Action,{value:n,enumerable:!1}),Object.defineProperty(r,f.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(r,f.Name,{value:e,enumerable:!1}),t===b.Broadcast&&Object.defineProperty(r,f.Broadcast,{value:!0,enumerable:!1}),t===b.Multicast&&Object.defineProperty(r,f.Multicast,{value:!0,enumerable:!1}),r},e.Boundary=function({store:e,children:t}){return r.jsx(X,{children:r.jsx(ne,{initial:e??{},children:r.jsx(Z,{children:t})})})},e.Cache=he,e.Distribution=b,e.Lifecycle=m,e.Op=A,e.Operation=A,e.Reason=x,e.Resource=function(e,t){const n=t??function(e){let t=ge.get(e);return void 0===t&&(t=he(),ge.set(e,t)),t}(e),r=e=>{const t=n.get(we(e));return t.data===ue||null===t.at?{data:ue,at:null}:{data:t.data,at:t.at}},o=(t,r,o)=>e({store:t,controller:r,params:o}).then(e=>(n.set(we(o),de(e,Temporal.Now.instant())),e)),s=(e,t,r)=>{n.set(we(e),de(t,r))};return function(e){const t=e??{};je={run:o,read:r,seed:s,params:t},queueMicrotask(()=>{null!==je&&je.params===t&&(je=null)});const{data:n}=r(t);return n===ue?null:n}},e.State=$,e.TimeoutError=M,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 D.annotate(t,e)},e.useContext=function(){const e=c.useRef(null);return c.useMemo(()=>({actions:{dispatch:function(t,n){const r=e.current;if(!r)throw new Error("march-hare: useContext handle dispatched before its paired context.useActions(...) ran. Call context.actions.dispatch from event handlers, not synchronously during render.");return r(t,n)}},useActions:function(...r){const o=function(...e){const r=t.G.isUndefined(e[0])||t.G.isFunction(e[0])?{}:e[0],o=t.G.isFunction(e[0])?e[0]:e[1]??(()=>({})),s=Q(),a=oe(),i=c.useContext(Y),u=te(),l=c.useContext(ee),f=le(),d=c.useRef(!1),m=c.useRef(null),b=c.useRef(new $);d.current||(d.current=!0,m.current=b.current.hydrate(r));const[v,S]=c.useState(()=>b.current.model),x=function(e){const t=c.useRef(e);return t.current=e,c.useMemo(()=>{return n=t,Object.keys(e).reduce((e,t)=>(Object.defineProperty(e,t,{get:()=>n.current[t],enumerable:!0}),e),{});var n},[e])}(o()),E=c.useMemo(()=>new J,[]),M=c.useRef({handlers:new Map});M.current.handlers=new Map;const C=function(){const e=c.useRef(new Set),t=c.useRef(new Set);return c.useMemo(()=>({broadcast:e.current,multicast:t.current}),[])}(),G=c.useRef(y.Mounting),k=c.useRef(new Set),N=c.useRef(0),_=c.useCallback((e,t,r)=>{const o=new AbortController,c={controller:o,action:e,payload:t};return i.add(c),k.current.add(c),{model:b.current.model,get phase(){return G.current},task:c,data:x,tasks:i,store:u,actions:{produce(e){if(o.signal.aborted)return;const t=l.current,c=b.current.produce(t=>{l.current=n.produce(l.current,n=>{e({model:t,inspect:b.current.inspect,store:n})})});S(b.current.model),l.current!==t&&s.emit(h,l.current),r.processes.add(c),m.current&&(r.processes.add(m.current),m.current=null)},dispatch(e,t){if(o.signal.aborted)return Promise.resolve();const n=g(e),r=O(e)?e.channel:void 0;if(P(e)){const e=se(a,n);return e?ae(e.emitter,n,t,r):Promise.resolve()}return ae(w(e)?s:E,n,t,r)},annotate:(e,t=A.Update)=>b.current.annotate(t,e),get inspect(){return b.current.inspect},resource:Object.assign(function(e){const t=Oe(),n=()=>t.run(l.current,o,t.params);return{then:(e,t)=>n().then(e,t),exceeds:e=>{const{data:r,at:o}=t.read(t.params);if(r!==ue&&null!==o){const t=Temporal.Now.instant().since(o),n=Temporal.Duration.from(e);if(Temporal.Duration.compare(t,n)<=0)return Promise.resolve(r)}return n()}}},{set:(e,t)=>{const n=Oe();n.seed(n.params,t,Temporal.Now.instant())}}),async resolution(e){if(o.signal.aborted)return null;const t=g(e),n=P(e)?se(a,t)?.emitter??null:s;if(!n)return null;if(void 0===n.getCached(t))return null;const r=b.current.inspect;return r.pending()&&await new Promise((e,t)=>{if(o.signal.aborted)return void t(o.signal.reason);const n=()=>t(o.signal.reason);o.signal.addEventListener("abort",n,{once:!0}),r.settled().then(()=>{o.signal.removeEventListener("abort",n),e()})}),n.getCached(t)??null},peek(e){if(o.signal.aborted)return null;const t=g(e),n=P(e)?se(a,t)?.emitter??null:s;return n?n.getCached(t)??null:null}}}},[v]);c.useLayoutEffect(()=>{function e(e,n,r){return function(o,c){const a=r();if(c===ce&&t.G.isNotNullable(a))return;if(t.G.isNotNullable(c)&&c!==ce&&t.G.isNotNullable(a)&&!function(e,t){for(const n of Object.keys(e))if(t[n]!==e[n])return!1;return!0}(c,a))return;const u={processes:new Set},l=Promise.withResolvers(),d=_(e,o,u);function h(t){const n=ie(M.current.handlers,"Error"),r=null!==n,o={reason:pe(t),error:(c=t,c instanceof Error?c:new Error(String(c))),action:j(e),handled:r,tasks:i};var c;s.fire(p,o),r&&n&&E.emit(n,o)}function m(){for(const e of i)if(e===d.task){i.delete(e),k.current.delete(e);break}u.processes.forEach(e=>b.current.prune(e)),u.processes.size>0&&f(),l.resolve()}let y;try{y=n(d,o)}catch(v){return h(v),void m()}if(!function(e){if(!e||"object"!=typeof e)return!1;const t=Object.prototype.toString.call(e);return"[object Generator]"===t||"[object AsyncGenerator]"===t}(y))return Promise.resolve(y).catch(h).finally(m),l.promise;(async()=>{for await(const e of y);})().catch(h).finally(m)}}N.current++;const n=new Set;return M.current.handlers.forEach((t,r)=>{for(const{getChannel:o,handler:c}of t){const t=e(r,c,o);if(P(r)){if(a)for(const e of a.values()){const o=e.emitter;o.on(r,t),n.add(()=>o.off(r,t))}E.on(r,t),C.multicast.add(r),n.add(()=>E.off(r,t))}else w(r)?(s.on(r,t),E.on(r,t),C.broadcast.add(r),n.add(()=>{s.off(r,t),E.off(r,t)})):(E.on(r,t),n.add(()=>E.off(r,t)))}}),()=>{const e=++N.current,t=new Set(n);queueMicrotask(()=>{if(N.current!==e){for(const e of t)e();return}for(const e of k.current)e.controller.abort(),i.delete(e);k.current.clear(),G.current=y.Unmounting;const n=ie(M.current.handlers,"Unmount");n&&E.emit(n),G.current=y.Unmounted;for(const e of t)e()})}},[E]),function({unicast:e,broadcast:n,dispatchers:r,scope:o,phase:s,data:a,handlers:i}){const u=c.useRef(null);c.useLayoutEffect(()=>{if(s.current===y.Mounted)return;s.current=y.Mounting;const c=ie(i,"Mount");c&&e.emit(c),r.broadcast.forEach(r=>{const o=n.getCached(r);t.G.isNullable(o)||e.emit(r,o,ce)}),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,ce)}}),s.current=y.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,a);if(t.A.isNotEmpty(Object.keys(n))){const t=ie(i,"Update");t&&e.emit(t,n)}}u.current=a},[a,e])}({unicast:E,broadcast:s,dispatchers:C,scope:a,phase:G,data:o(),handlers:M.current.handlers});const R=c.useMemo(()=>({dispatch(e,t){const n=g(e),r=O(e)?e.channel:void 0;if(P(e)){const e=se(a,n);return e?ae(e.emitter,n,t,r):Promise.resolve()}return ae(w(e)?s:E,n,t,r)},get inspect(){return b.current.inspect},stream:(e,t)=>c.createElement(Pe,{action:g(e),renderer:t})}),[v,E]),T=c.useMemo(()=>[v,R,x],[v,R,x]);return T.useAction=(e,t)=>{!function(e,t,n){const r=c.useRef(n);c.useLayoutEffect(()=>{r.current=n});const o=c.useRef(t);c.useLayoutEffect(()=>{o.current=t});const s=c.useCallback((e,t)=>r.current(e,t),[]),a=c.useCallback(()=>O(o.current)?o.current.channel:void 0,[]),i=g(t),u=e.current.handlers.get(i)??new Set;0===u.size&&e.current.handlers.set(i,u),u.add({getChannel:a,handler:s})}(M,e,t)},T.dispatch=T[1].dispatch,T}(...r);return e.current=o.dispatch,o}}),[])},e.useStore=te,e.utils=ve,e.withScope=function(e,t){const n=`Scoped${t.displayName||t.name||"Component"}`,o=g(e);return{[n](e){const n=oe(),s=c.useMemo(()=>({action:o,emitter:new K}),[]),a=c.useMemo(()=>{const e=new Map(n??[]);return e.set(o,s),e},[n,s]);return r.jsx(re.Provider,{value:a,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 c=s(n);function a(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var i,u={exports:{}},l=(i||(i=1,function(e){var t=Object.prototype.hasOwnProperty,n="~";function r(){}function o(e,t,n){this.fn=e,this.context=t,this.once=n||!1}function s(e,t,r,s,c){if("function"!=typeof r)throw new TypeError("The listener must be a function");var a=new o(r,s||e,c),i=n?n+t:t;return e._events[i]?e._events[i].fn?e._events[i]=[e._events[i],a]:e._events[i].push(a):(e._events[i]=a,e._eventsCount++),e}function c(e,t){0===--e._eventsCount?e._events=new r:delete e._events[t]}function a(){this._events=new r,this._eventsCount=0}Object.create&&(r.prototype=Object.create(null),(new r).__proto__||(n=!1)),a.prototype.eventNames=function(){var e,r,o=[];if(0===this._eventsCount)return o;for(r in e=this._events)t.call(e,r)&&o.push(n?r.slice(1):r);return Object.getOwnPropertySymbols?o.concat(Object.getOwnPropertySymbols(e)):o},a.prototype.listeners=function(e){var t=this._events[n?n+e:e];if(!t)return[];if(t.fn)return[t.fn];for(var r=0,o=t.length,s=new Array(o);r<o;r++)s[r]=t[r].fn;return s},a.prototype.listenerCount=function(e){var t=this._events[n?n+e:e];return t?t.fn?1:t.length:0},a.prototype.emit=function(e,t,r,o,s,c){var a=n?n+e:e;if(!this._events[a])return!1;var i,u,l=this._events[a],f=arguments.length;if(l.fn){switch(l.once&&this.removeListener(e,l.fn,void 0,!0),f){case 1:return l.fn.call(l.context),!0;case 2:return l.fn.call(l.context,t),!0;case 3:return l.fn.call(l.context,t,r),!0;case 4:return l.fn.call(l.context,t,r,o),!0;case 5:return l.fn.call(l.context,t,r,o,s),!0;case 6:return l.fn.call(l.context,t,r,o,s,c),!0}for(u=1,i=new Array(f-1);u<f;u++)i[u-1]=arguments[u];l.fn.apply(l.context,i)}else{var d,p=l.length;for(u=0;u<p;u++)switch(l[u].once&&this.removeListener(e,l[u].fn,void 0,!0),f){case 1:l[u].fn.call(l[u].context);break;case 2:l[u].fn.call(l[u].context,t);break;case 3:l[u].fn.call(l[u].context,t,r);break;case 4:l[u].fn.call(l[u].context,t,r,o);break;default:if(!i)for(d=1,i=new Array(f-1);d<f;d++)i[d-1]=arguments[d];l[u].fn.apply(l[u].context,i)}}return!0},a.prototype.on=function(e,t,n){return s(this,e,t,n,!1)},a.prototype.once=function(e,t,n){return s(this,e,t,n,!0)},a.prototype.removeListener=function(e,t,r,o){var s=n?n+e:e;if(!this._events[s])return this;if(!t)return c(this,s),this;var a=this._events[s];if(a.fn)a.fn!==t||o&&!a.once||r&&a.context!==r||c(this,s);else{for(var i=0,u=[],l=a.length;i<l;i++)(a[i].fn!==t||o&&!a[i].once||r&&a[i].context!==r)&&u.push(a[i]);u.length?this._events[s]=1===u.length?u[0]:u:c(this,s)}return this},a.prototype.removeAllListeners=function(e){var t;return e?this._events[t=n?n+e:e]&&c(this,t):(this._events=new r,this._eventsCount=0),this},a.prototype.off=a.prototype.removeListener,a.prototype.addListener=a.prototype.on,a.prefixed=n,a.EventEmitter=a,e.exports=a}(u)),u.exports);const f=a(l);class d extends f{cache=new Map;emit(e,...t){return this.cache.set(e,t[0]),super.emit(e,...t)}setCache(e,t){this.cache.set(e,t)}getCached(e){return this.cache.get(e)}fire(e,...t){return super.emit(e,...t)}}const p=c.createContext(new d);function h(){return c.useContext(p)}function m({children:e}){const n=c.useMemo(()=>new d,[]);return t.jsx(p.Provider,{value:n,children:e})}const b=c.createContext(new Set);function y({children:e}){const n=c.useMemo(()=>new Set,[]);return t.jsx(b.Provider,{value:n,children:e})}const v=c.createContext({current:{}});function g(){const e=c.useContext(v);return c.useMemo(()=>new Proxy({},{get:(t,n)=>Reflect.get(e.current,n),has:(t,n)=>n in e.current,ownKeys:()=>Reflect.ownKeys(e.current),getOwnPropertyDescriptor(t,n){const o=Object.getOwnPropertyDescriptor(e.current,n);if(!r.G.isUndefined(o))return{...o,configurable:!0}},set(){throw new TypeError("Env is read-only outside `context.actions.produce`. Mutate via produce(({ env }) => { env.x = ... }) instead.")}}),[e])}const w=(e="")=>`march-hare.action/${e}`,j=(e="")=>`march-hare.action/broadcast/${e}`,x=(e="")=>`march-hare.action/multicast/${e}`,O=(e="")=>`march-hare.action.lifecycle/${e}`;class P{static Payload=Symbol("march-hare.brand/Payload");static Broadcast=Symbol("march-hare.brand/Broadcast");static Multicast=Symbol("march-hare.brand/Multicast");static Action=Symbol("march-hare.brand/Action");static Channel=Symbol("march-hare.brand/Channel");static Name=Symbol("march-hare.brand/Name")}function S(e){const t=Symbol(`march-hare.action.lifecycle/${e}`),n=function(n){return{[P.Action]:t,[P.Payload]:void 0,[P.Channel]:n,[P.Name]:e,channel:n}};return Object.defineProperty(n,P.Action,{value:t,enumerable:!1}),Object.defineProperty(n,P.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(n,P.Name,{value:e,enumerable:!1}),n}const C=Symbol(j("Fault")),E=Symbol(j("Env"));class G{static Mount(){return S("Mount")}static Unmount(){return S("Unmount")}static Error(){return S("Error")}static Update(){return S("Update")}static Fault=(()=>{const e={};return Object.defineProperty(e,P.Action,{value:C,enumerable:!1}),Object.defineProperty(e,P.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(e,P.Broadcast,{value:!0,enumerable:!1}),Object.defineProperty(e,P.Name,{value:"Fault",enumerable:!1}),e})();static Env=(()=>{const e={};return Object.defineProperty(e,P.Action,{value:E,enumerable:!1}),Object.defineProperty(e,P.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(e,P.Broadcast,{value:!0,enumerable:!1}),Object.defineProperty(e,P.Name,{value:"Env",enumerable:!1}),e})()}var A=(e=>(e.Unicast="unicast",e.Broadcast="broadcast",e.Multicast="multicast",e))(A||{}),M=(e=>(e.Mounting="mounting",e.Mounted="mounted",e.Unmounting="unmounting",e.Unmounted="unmounted",e))(M||{});function k({initial:e,children:n}){const o=c.useRef(e),s=h();return r.G.isUndefined(s.getCached(E))&&s.setCache(E,o.current),t.jsx(v.Provider,{value:o,children:n})}const N=c.createContext(new WeakMap);function R({children:e}){const n=c.useMemo(()=>new WeakMap,[]);return t.jsx(N.Provider,{value:n,children:e})}const _=c.createContext(()=>{});function U({tap:e,children:n}){const r=c.useRef(e);c.useLayoutEffect(()=>{r.current=e},[e]);const o=c.useMemo(()=>e=>r.current?.(e),[]);return t.jsx(_.Provider,{value:o,children:n})}function L({env:e,tap:n,children:r}){return t.jsx(m,{children:t.jsx(k,{initial:e??{},children:t.jsx(y,{children:t.jsx(U,{tap:n,children:t.jsx(R,{children:r})})})})})}const T=e=>"symbol"==typeof e;function W(e){return r.G.isString(e)||T(e)?e:(r.G.isObject(e)||r.G.isFunction(e))&&P.Action in e?e[P.Action]:e}function B(e){if(r.G.isString(e))return e.startsWith(j());if(T(e))return e.description?.startsWith(j())??!1;if(r.G.isObject(e)||r.G.isFunction(e)){if(P.Broadcast in e&&e[P.Broadcast])return!0;if(P.Action in e){const t=e[P.Action];return t.description?.startsWith(j())??!1}}return!1}function $(e){return r.G.isObject(e)&&P.Channel in e&&"channel"in e}function F(e){const t=W(e),n=T(t)?t.description??"":t;return n.startsWith(O())&&n.slice(O().length)||null}function D(e){if(r.G.isString(e))return e.startsWith(x());if(T(e))return e.description?.startsWith(x())??!1;if(r.G.isObject(e)||r.G.isFunction(e)){if(P.Multicast in e&&e[P.Multicast])return!0;if(P.Action in e){const t=e[P.Action];return t.description?.startsWith(x())??!1}}return!1}const I=Symbol(((e="")=>`march-hare/replay${e}`)());function H(e,t,...n){e instanceof d&&e.setCache(t,n[0]);const r=e.listeners(t);return 0===r.length?Promise.resolve():Promise.all(r.map(e=>Promise.resolve(e(...n)))).then(()=>{})}function q(e,t){for(const n of e.keys())if(F(n)===t)return n;return null}const z=Symbol("march-hare.unset");function J(){const[,e]=c.useReducer(e=>e+1,0);return e}function K(){return{data:z,at:null,else:e=>e}}function V(e,t){return{data:e,at:t,else:t=>e}}var Q=(e=>(e[e.Aborted=0]="Aborted",e[e.Errored=1]="Errored",e))(Q||{});class X extends Error{name="AbortError";constructor(e="Aborted"){super(e)}}const Y=c.createContext(null);function Z(e){const t=new Map,n=e??{get:e=>t.get(e)??null,set:(e,n)=>{t.set(e,n)},remove:e=>{t.delete(e)},clear:()=>{t.clear()}};return{get(e){try{const t=n.get(e);if(r.G.isNull(t))return K();const o=JSON.parse(t);return V(o.data,Temporal.Instant.from(o.at))}catch{return K()}},set(e,t){if(t.data===z||r.G.isNull(t.at))return!1;try{return n.set(e,JSON.stringify({data:t.data,at:t.at.toString()})),!0}catch{return!1}},remove(e){n.remove(e)},clear(){n.clear()}}}function ee(e,t){return new Promise((n,r)=>{if(t?.aborted)return void r(new X);const o=setTimeout(n,e);t?.addEventListener("abort",()=>{clearTimeout(o),r(new X)},{once:!0})})}async function te(e,t,n){if(t?.aborted)throw new X;for(;;){if(await n())return;await ee(e,t)}}function ne(e){return e?Boolean(e&&"symbol"!=typeof e):Symbol(`pk.${Date.now()}.${crypto.randomUUID()}`)}const re=Object.freeze(Object.defineProperty({__proto__:null,pk:ne,poll:te,sleep:ee,unset:z,"ζ":ee,"κ":ne,"π":te},Symbol.toStringTag,{value:"Module"})),oe=new WeakMap;function se(e){return JSON.stringify(e)}let ce=null;function ae(){if(r.G.isNull(ce))throw new Error("context.actions.resource(...) and context.actions.resource.set(...) must be called with a fresh resource invocation, e.g. context.actions.resource(resource.cat({ id: 5 })).");const e=ce;return ce=null,e}function ie(e,t){const n=e=>{const n=t.get(se(e));return n.data===z||r.G.isNull(n.at)?{data:z,at:null}:{data:n.data,at:n.at}},o=(n,r,o,s)=>e({env:n,controller:r,params:o,dispatch:s}).then(e=>(t.set(se(o),V(e,Temporal.Now.instant())),e)),s=(e,n,r)=>{t.set(se(e),V(n,r))};return function(e){const t=e??{};ce={run:o,read:n,seed:s,params:t},queueMicrotask(()=>{r.G.isNotNullable(ce)&&ce.params===t&&(ce=null)});const{data:c}=n(t);return c===z?null:c}}function ue(e){return ie(e,function(e){let t=oe.get(e);return r.G.isUndefined(t)&&(t=Z(),oe.set(e,t)),t}(e))}(ue||(ue={})).Cachable=function(e,t){return ie(t,e)};const le=Symbol("march-hare.coalesce/default");function fe(e,t){return new Promise((n,r)=>{if(t.aborted)return void r(t.reason);const o=()=>r(t.reason);t.addEventListener("abort",o,{once:!0}),e.then(e=>{t.removeEventListener("abort",o),n(e)},e=>{t.removeEventListener("abort",o),r(e)})})}let de=(e=21)=>{let t="",n=crypto.getRandomValues(new Uint8Array(e|=0));for(;e--;)t+="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"[63&n[e]];return t};var pe=(e=>(e[e.Add=1]="Add",e[e.Remove=2]="Remove",e[e.Update=4]="Update",e[e.Move=8]="Move",e[e.Replace=16]="Replace",e[e.Sort=32]="Sort",e[e.Create=64]="Create",e[e.Fetch=128]="Fetch",e[e.Clone=256]="Clone",e[e.Archive=512]="Archive",e[e.Restore=1024]="Restore",e[e.Merge=2048]="Merge",e[e.Reorder=4096]="Reorder",e[e.Sync=8192]="Sync",e[e.Publish=16384]="Publish",e[e.Link=32768]="Link",e[e.Unlink=65536]="Unlink",e[e.Lock=131072]="Lock",e[e.Unlock=262144]="Unlock",e[e.Import=524288]="Import",e[e.Export=1048576]="Export",e[e.Transfer=2097152]="Transfer",e))(pe||{}),he=(e=>(e[e.Produce=0]="Produce",e[e.Hydrate=1]="Hydrate",e))(he||{}),me=(e=>(e.Property="property",e.Process="process",e.Value="value",e.Operation="operation",e))(me||{});class be{[o.immerable]=!0;static keys=new Set(Object.values(me));property=null;process=null;value;operation;constructor(e,t){this.value=e,this.operation=t}assign(e,t){const n=new be(this.value,this.operation);return n.property=e,n.process=t,n}}class ye{static immer=(()=>{o.enablePatches();const e=new o.Immer;return e.setAutoFreeze(!1),e})();static tag="κ";static id=de}function ve(e,t){const n="string"==typeof t?""===t?[]:t.split("."):t;let r=e;for(const o of n){if(null==r)return;r=r[o]}return r}function ge(e){if(r.G.isNullable(e)||xe(e))return e;if(r.G.isArray(e))return e.map(e=>ge(e));if(r.G.isObject(e)&&je(e)){const t=Object.entries(e).map(([e,t])=>[e,ge(t)]);return{...Object.fromEntries(t),[ye.tag]:e[ye.tag]??ye.id()}}return e}function we(e){if(Array.isArray(e))return e.filter(e=>ye.tag in e).map(e=>e[ye.tag]??"").join(",");const t=e[ye.tag];if(t)return t;try{return JSON.stringify(e)}catch{return`[unserializable:${typeof e}]`}}function je(e){const t=Object.getPrototypeOf(e);return t===Object.prototype||null===t}function xe(e){return r.G.isNullable(e)||r.G.isString(e)||r.G.isNumber(e)||r.G.isBoolean(e)||"symbol"==typeof e||"bigint"==typeof e}function Oe(e,t,n,o,s,c){return function a(i,u=t.path){if(i instanceof be){const t=ve(n,u.join("."));if(Object.entries(i).filter(([e,t])=>!be.keys.has(e)&&t instanceof be).forEach(([e,t])=>a(t,u.concat(e))),xe(i.value)){if(e===he.Hydrate)return i.value;const a=u.slice(0,-1),l=a.length>0?ve(n,a.join(".")):n;return r.G.isNullable(l)||Pe(l,i,u.at(-1),o,s,c),t??i.value}if(e===he.Hydrate){const e=ge(a(i.value,u));return Pe(e,i,null,o,s,c),e}const l=t??ge(i.value);return Pe(l,i,null,o,s,c),r.G.isNullable(t)?l:(a(i.value,u),t)}if(r.G.isArray(i))return i.map((e,t)=>a(e,u.concat(t)));if(r.G.isObject(i)&&!je(i))return i;if(r.G.isObject(i)){const t=Object.entries(i).map(([e,t])=>[e,a(t,u.concat(e))]),n=Object.fromEntries(t);if(e===he.Hydrate){const e=ge(n);return Object.entries(i).forEach(([t,n])=>{n instanceof be&&xe(n.value)&&Pe(e,n,t,o,s,c)}),e}return n}return i}(t.value)}function Pe(e,t,n,r,o,s){const c=s(e),a=o.get(c)??[];o.set(c,[t.assign(n,r),...a])}class Se{#e={};#t;#n=new Map;#r=new Set;#o=!1;constructor(e=we){this.#t=e}static pk(){return de()}static"κ"=Se.pk;annotate(e,t){return new be(t,e)}"δ"=this.annotate;get model(){return this.#e}get inspect(){return function(e,t,n,o,s){function c(o){const s=o.at(-1),c=ve(e(),o),a=o.slice(0,-1),i=r.A.isNotEmpty(a)?ve(e(),a):e();return[...r.G.isObject(c)||r.G.isArray(c)?t.get(n(c))?.filter(e=>r.G.isNullable(e.property))??[]:[],...r.G.isObject(i)?t.get(n(i))?.filter(e=>e.property===s)??[]:[]]}return function t(n){return new Proxy(()=>{},{get:(a,i)=>"pending"===i?()=>!r.A.isEmpty(c(n)):"remaining"===i?()=>r.A.length(c(n)):"box"===i?()=>({value:ve(e(),n),inspect:t(n)}):"is"===i?e=>c(n).some(t=>0!==(t.operation&e)):"draft"===i?()=>r.A.head(c(n))?.value??ve(e(),n):"settled"===i?()=>new Promise(t=>{if(r.A.isEmpty(c(n)))return t(ve(e(),n));const a=()=>{r.A.isEmpty(c(n))&&(s(a),t(ve(e(),n)))};o(a)}):t([...n,String(i)])})}([])}(()=>this.#e,this.#n,this.#t,e=>this.#r.add(e),e=>this.#r.delete(e))}hydrate(e){return this.#o=!0,this.#s(he.Hydrate,()=>e)}produce(e){if(!this.#o)throw new Error("State must be hydrated using hydrate() before calling produce()");return this.#s(he.Produce,e)}#s(e,t){const n=Symbol("process"),[,r]=ye.immer.produceWithPatches(this.#e,t);return this.#e=r.reduce((t,r)=>ye.immer.applyPatches(t,[{...r,value:Oe(e,r,t,n,this.#n,this.#t)}]),this.#e),this.#e=ge(this.#e),this.#c(),n}prune(e){this.#n.forEach((t,n)=>{const o=t.filter(t=>t.process!==e);r.A.isEmpty(o)?this.#n.delete(n):this.#n.set(n,o)}),this.#c()}#c(){this.#r.forEach(e=>e())}observe(e){const t=()=>e(this.#e);return this.#r.add(t),()=>this.#r.delete(t)}}const Ce=c.createContext(new Map);function Ee({action:e,renderer:t}){const n=h(),o=c.useContext(Ce),s=J(),a=c.useMemo(()=>{const t=o.get(e);if(t)return t;const s=new Se,c=n.getCached(e);r.G.isNotNullable(c)&&s.hydrate({value:c});const a={state:s,listeners:new Set};return o.set(e,a),a},[e,n,o]);c.useLayoutEffect(()=>{function t(e){a.state.hydrate({value:e}),a.listeners.forEach(e=>e())}return a.listeners.add(s),n.on(e,t),()=>{a.listeners.delete(s),n.off(e,t)}},[e,n,a]);const i=a.state.model?.value;return r.G.isNullable(i)?null:t(i,a.state.inspect.value)}function Ge(e,t){const n=t.split(".");let r=e;for(let o=0;o<n.length-1;o++)r=r[n[o]];return{cursor:r,key:n[n.length-1]}}function Ae(e,t,n){const{cursor:r,key:o}=Ge(e,t);r[o]=n}function Me(e){return(t,n)=>{t.actions.produce(t=>{Ae(t.model,e,n)})}}function ke(e){return t=>{t.actions.produce(t=>{!function(e,t){const{cursor:n,key:r}=Ge(e,t);n[r]=!n[r]}(t.model,e)})}}function Ne(e,t){return n=>{n.actions.produce(n=>{Ae(n.model,e,t)})}}const Re={Update:e=>Me(e),Invert:e=>ke(e),Always:(e,t)=>Ne(e,t)};function _e(){const e=c.useRef(null);return c.useMemo(()=>({actions:{dispatch:function(t,n){const r=e.current;if(!r)throw new Error("march-hare: useContext handle dispatched before its paired context.useActions(...) ran. Call context.actions.dispatch from event handlers, not synchronously during render.");return r(t,n)}},useActions:function(...t){const n=function(...e){const t=r.G.isUndefined(e[0])||r.G.isFunction(e[0])?{}:e[0],n=r.G.isFunction(e[0])?e[0]:e[1]??(()=>({})),s=h(),a=c.useContext(Y),i=c.useContext(b),u=g(),l=c.useContext(v),d=c.useContext(N),p=c.useContext(_),m=J(),y=c.useRef(!1),j=c.useRef(null),x=c.useRef(new Se);y.current||(y.current=!0,j.current=x.current.hydrate(t));const[O,P]=c.useState(()=>x.current.model),S=function(e){const t=c.useRef(e);return t.current=e,c.useMemo(()=>{return n=t,Object.keys(e).reduce((e,t)=>(Object.defineProperty(e,t,{get:()=>n.current[t],enumerable:!0}),e),{});var n},[e])}(n()),G=c.useMemo(()=>new f,[]),A=c.useRef({handlers:new Map});A.current.handlers=new Map;const k=function(){const e=c.useRef(new Set),t=c.useRef(new Set);return c.useMemo(()=>({broadcast:e.current,multicast:t.current}),[])}(),R=c.useRef(M.Mounting),U=c.useRef(new Set),L=c.useRef(0),T=c.useCallback((e,t,n)=>{const c=new AbortController,f={controller:c,action:e,payload:t};return i.add(f),U.current.add(f),{model:x.current.model,get phase(){return R.current},task:f,data:S,tasks:i,env:u,actions:{produce(e){if(c.signal.aborted)return;const t=l.current,r=x.current.produce(t=>{l.current=o.produce(l.current,n=>{e({model:t,inspect:x.current.inspect,env:n})})});P(x.current.model),l.current!==t&&s.emit(E,l.current),n.processes.add(r),j.current&&(n.processes.add(j.current),j.current=null)},dispatch(e,t){if(c.signal.aborted)return Promise.resolve();const n=W(e),r=$(e)?e.channel:void 0;return D(e)?a?H(a.emitter,n,t,r):Promise.resolve():H(B(e)?s:G,n,t,r)},annotate:(e,t=pe.Update)=>x.current.annotate(t,e),get inspect(){return x.current.inspect},resource:Object.assign(function(e){const t=ae(),n=(e,t)=>{if(c.signal.aborted)return Promise.resolve();const n=e,r=W(n);return D(n)?a?H(a.emitter,r,t,void 0):Promise.resolve():B(n)?H(s,r,t,void 0):Promise.resolve()},o={exceedsWindow:null,coalesceToken:void 0},i={then:(e,s)=>(()=>{if(r.G.isNotNullable(o.exceedsWindow)){const{data:e,at:n}=t.read(t.params);if(e!==z&&r.G.isNotNullable(n)){const t=Temporal.Now.instant().since(n),r=Temporal.Duration.from(o.exceedsWindow);if(Temporal.Duration.compare(t,r)<=0)return Promise.resolve(e)}}if(r.G.isUndefined(o.coalesceToken))return t.run(u,c,t.params,n);let e=d.get(t.run);r.G.isUndefined(e)&&(e=new Map,d.set(t.run,e));const s=e,a=`${JSON.stringify(t.params)}|${function(e){switch(typeof e){case"string":return`s:${e}`;case"number":return`n:${e}`;case"bigint":return`i:${e.toString()}`;case"boolean":return`b:${e}`;case"symbol":return`y:${e.description??String(e)}`;default:return`o:${JSON.stringify(e)}`}}(o.coalesceToken)}`,i=s.get(a);if(i)return fe(i,c.signal);const l=new AbortController,f=t.run(u,l,t.params,n).finally(()=>{s.delete(a)});return s.set(a,f),fe(f,c.signal)})().then(e,s),exceeds:e=>(o.exceedsWindow=e,i),coalesce:e=>(o.coalesceToken=e??le,i)};return i},{set:(e,t)=>{const n=ae();n.seed(n.params,t,Temporal.Now.instant())}}),async final(e){if(c.signal.aborted)return null;const t=W(e),n=D(e)?a?.emitter??null:s;if(!n)return null;const o=n.getCached(t);if(r.G.isUndefined(o))return null;const i=x.current.inspect;return i.pending()&&await new Promise((e,t)=>{if(c.signal.aborted)return void t(c.signal.reason);const n=()=>t(c.signal.reason);c.signal.addEventListener("abort",n,{once:!0}),i.settled().then(()=>{c.signal.removeEventListener("abort",n),e()})}),n.getCached(t)??null},peek(e){if(c.signal.aborted)return null;const t=W(e),n=D(e)?a?.emitter??null:s;return n?n.getCached(t)??null:null}}}},[O]);c.useLayoutEffect(()=>{function e(e,t,n){return function(o,c){const a=n();if(c===I&&r.G.isNotNullable(a))return;if(r.G.isNotNullable(c)&&c!==I&&r.G.isNotNullable(a)&&!function(e,t){for(const n of Object.keys(e))if(t[n]!==e[n])return!1;return!0}(c,a))return;const u={processes:new Set},f=Promise.withResolvers(),d=T(e,o,u),h=function(e){const t=W(e),n=r.G.isString(t)?t:t.description??"";return n.startsWith(w())&&n.slice(n.lastIndexOf("/")+1)||"unknown"}(e),b=performance.now(),y=x.current.model,v=l.current;let g,j=!1;function O(){const e=x.current.model,t=l.current;return{model:y===e?null:{before:y,after:e},env:v===t?null:{before:v,after:t}}}function P(e){j=!0;const t=q(A.current.handlers,"Error"),n=r.G.isNotNullable(t),c=function(e){return e instanceof Error&&"AbortError"===e.name?Q.Aborted:Q.Errored}(e),a=function(e){return e instanceof Error?e:new Error(String(e))}(e),u={reason:c,error:a,action:h,handled:n,tasks:i};s.fire(C,u),n&&t&&G.emit(t,u),p({stage:"end",result:"error",action:{name:h,payload:o},details:{task:d.task,elapsed:performance.now()-b,mutations:O(),error:a,reason:c}})}function S(){for(const e of i)if(e===d.task){i.delete(e),U.current.delete(e);break}u.processes.forEach(e=>x.current.prune(e)),u.processes.size>0&&m(),j||p({stage:"end",result:"success",action:{name:h,payload:o},details:{task:d.task,elapsed:performance.now()-b,mutations:O()}}),f.resolve()}p({stage:"start",action:{name:h,payload:o},details:{task:d.task}});try{g=t(d,o)}catch(E){return P(E),S(),f.promise}return function(e){if(!e||"object"!=typeof e)return!1;const t=Object.prototype.toString.call(e);return"[object Generator]"===t||"[object AsyncGenerator]"===t}(g)?((async()=>{for await(const e of g);})().catch(P).finally(S),f.promise):(Promise.resolve(g).catch(P).finally(S),f.promise)}}L.current++;const t=new Set;return A.current.handlers.forEach((n,r)=>{for(const{getChannel:o,handler:c}of n){const n=e(r,c,o);if(D(r)){if(a){const e=a.emitter;e.on(r,n),t.add(()=>e.off(r,n))}G.on(r,n),k.multicast.add(r),t.add(()=>G.off(r,n))}else B(r)?(s.on(r,n),G.on(r,n),k.broadcast.add(r),t.add(()=>{s.off(r,n),G.off(r,n)})):(G.on(r,n),t.add(()=>G.off(r,n)))}}),()=>{const e=++L.current,n=new Set(t);queueMicrotask(()=>{if(L.current!==e){for(const e of n)e();return}for(const e of U.current)e.controller.abort(),i.delete(e);U.current.clear(),R.current=M.Unmounting;const t=q(A.current.handlers,"Unmount");t&&G.emit(t),R.current=M.Unmounted;for(const e of n)e()})}},[G]),function({unicast:e,broadcast:t,dispatchers:n,scope:o,phase:s,data:a,handlers:i}){const u=c.useRef(null);c.useLayoutEffect(()=>{if(s.current===M.Mounted)return;s.current=M.Mounting;const c=q(i,"Mount");c&&e.emit(c),n.broadcast.forEach(n=>{const o=t.getCached(n);r.G.isNullable(o)||e.emit(n,o,I)}),o&&n.multicast.forEach(t=>{const n=o.emitter.getCached(t);r.G.isNullable(n)||e.emit(t,n,I)}),s.current=M.Mounted},[]),c.useLayoutEffect(()=>{if(r.G.isNotNullable(u.current)){const t=function(e,t){return Object.keys(t).reduce((n,r)=>e[r]!==t[r]?{...n,[r]:t[r]}:n,{})}(u.current,a);if(r.A.isNotEmpty(Object.keys(t))){const n=q(i,"Update");n&&e.emit(n,t)}}u.current=a},[a,e])}({unicast:G,broadcast:s,dispatchers:k,scope:a,phase:R,data:n(),handlers:A.current.handlers});const F=c.useMemo(()=>({dispatch(e,t){const n=W(e),r=$(e)?e.channel:void 0;return D(e)?a?H(a.emitter,n,t,r):Promise.resolve():H(B(e)?s:G,n,t,r)},get inspect(){return x.current.inspect},stream:(e,t)=>c.createElement(Ee,{action:W(e),renderer:t})}),[O,G]),K=c.useMemo(()=>[O,F,S],[O,F,S]);return K.useAction=(e,t)=>{!function(e,t,n){const r=c.useRef(n);c.useLayoutEffect(()=>{r.current=n});const o=c.useRef(t);c.useLayoutEffect(()=>{o.current=t});const s=c.useCallback((e,t)=>r.current(e,t),[]),a=c.useCallback(()=>$(o.current)?o.current.channel:void 0,[]),i=W(t),u=e.current.handlers.get(i)??new Set;0===u.size&&e.current.handlers.set(i,u),u.add({getChannel:a,handler:s})}(A,e,t)},K.dispatch=K[1].dispatch,K}(...t);return e.current=n.dispatch,n},with:{update:e=>Me(e),invert:e=>ke(e),always:(e,t)=>Ne(e,t)}}),[])}const Ue=new Se;e.Aborted=X,e.Action=(e="",t=A.Unicast)=>{const n=t===A.Broadcast?Symbol(j(e)):t===A.Multicast?Symbol(x(e)):Symbol(w(e)),r=function(t){return{[P.Action]:n,[P.Payload]:void 0,[P.Channel]:t,[P.Name]:e,channel:t}};return Object.defineProperty(r,P.Action,{value:n,enumerable:!1}),Object.defineProperty(r,P.Payload,{value:void 0,enumerable:!1}),Object.defineProperty(r,P.Name,{value:e,enumerable:!1}),t===A.Broadcast&&Object.defineProperty(r,P.Broadcast,{value:!0,enumerable:!1}),t===A.Multicast&&Object.defineProperty(r,P.Multicast,{value:!0,enumerable:!1}),r},e.App=function(e){return{Boundary:function({env:n,tap:r,children:o}){return t.jsx(L,{env:n??e?.env,tap:r??e?.tap,children:o})},useContext:function(){return _e()},useEnv:function(){return g()},Resource:Object.assign(function(e){return ue(e)},{Cachable:(e,t)=>ue.Cachable(e,t)}),Scope:()=>({Boundary:function({children:e}){const n=c.useMemo(()=>({id:Symbol("march-hare.scope/instance"),emitter:new d}),[]);return t.jsx(Y.Provider,{value:n,children:e})},useContext:function(){return _e()},useEnv:function(){return g()},Resource:Object.assign(function(e){return ue(e)},{Cachable:(e,t)=>ue.Cachable(e,t)})})}},e.Boundary=L,e.Cache=Z,e.Distribution=A,e.Lifecycle=G,e.Op=pe,e.Operation=pe,e.Reason=Q,e.Resource=ue,e.State=Se,e.With=Re,e.annotate=function(e,t=pe.Update){return Ue.annotate(t,e)},e.utils=re,Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})},"object"==typeof exports&&"undefined"!=typeof module?factory(exports,require("react/jsx-runtime"),require("react"),require("@mobily/ts-belt"),require("immer")):"function"==typeof define&&define.amd?define(["exports","react/jsx-runtime","react","@mobily/ts-belt","immer"],factory):factory((global="undefined"!=typeof globalThis?globalThis:global||self).MarchHare={},global.jsxRuntime,global.React,global.TsBelt,global.Immer);
@@ -1,53 +1,15 @@
1
- import { Fetcher } from './types';
1
+ import { Fetcher, PendingCall, ResourceHandle } from './types';
2
2
  import { Cache } from './utils';
3
- import { Store } from '../boundary/components/store/index';
4
- export type { Fetcher } from './types';
5
- /**
6
- * Snapshot of the most recent resource invocation. `cat(params)` writes
7
- * one of these into a module-scope slot; the next
8
- * `context.actions.resource(...)` / `.set(...)` call consumes it via
9
- * {@link consumePending}.
10
- *
11
- * @internal
12
- */
13
- export type PendingCall = {
14
- readonly run: (store: Store, controller: AbortController, params: object) => Promise<unknown>;
15
- readonly read: (params: object) => {
16
- data: unknown;
17
- at: Temporal.Instant | null;
18
- };
19
- readonly seed: (params: object, data: unknown, at: Temporal.Instant) => void;
20
- readonly params: object;
21
- };
3
+ export type { Coalesce, Fetcher, PendingCall, ResourceHandle, } from './types';
22
4
  /**
23
5
  * Reads and clears the slot populated by the most recent resource
24
6
  * invocation. Throws when the slot is empty &mdash; the public
25
- * `.resource(...)` shape requires a fresh `cat(params)` call as its
26
- * argument.
7
+ * `.resource(...)` shape requires a fresh `resource.cat(params)` call
8
+ * as its argument.
27
9
  *
28
10
  * @internal
29
11
  */
30
12
  export declare function consumePending(): PendingCall;
31
- /**
32
- * Resource handle returned by `Resource(...)`. Call it with `params` to
33
- * read the per-params cache slot synchronously and prime the slot
34
- * consumed by `context.actions.resource(...)` for a follow-up fetch or
35
- * `context.actions.resource.set(...)` for an out-of-band write.
36
- *
37
- * ```ts
38
- * // Sync cache read in a model literal.
39
- * { cat: cat({ id: 5 }) }
40
- *
41
- * // Fetch with `.exceeds(...)` for cache-aware refresh.
42
- * await context.actions.resource(cat({ id: 5 })).exceeds({ minutes: 5 });
43
- *
44
- * // Write through to the per-params cache slot.
45
- * context.actions.resource.set(cat({ id: 5 }), data);
46
- * ```
47
- */
48
- export type Resource<T, P extends object = Record<never, never>> = [
49
- keyof P
50
- ] extends [never] ? (params?: P) => T | null : (params: P) => T | null;
51
13
  /**
52
14
  * Defines a remote resource &mdash; declared at module scope and used
53
15
  * directly. Calling the returned handle with `params` returns the sync
@@ -55,48 +17,63 @@ export type Resource<T, P extends object = Record<never, never>> = [
55
17
  * `context.actions.resource(...)` / `.set(...)` for fetch and write
56
18
  * paths.
57
19
  *
58
- * The fetcher receives a single args object `{ store, controller, params }`:
59
- *
60
- * - `store` &ndash; snapshot of the per-`<Boundary>` Store (session,
61
- * locale, feature flags, etc.). Reads only; writes go through
62
- * `context.actions.produce(({ store }) => ...)` in handlers.
63
- * - `controller` &ndash; the `AbortController` auto-threaded from the
64
- * calling handler's `context.task.controller`. Pass `controller.signal`
65
- * to `fetch`/`ky`, or call `controller.abort()` to fail fast.
66
- * - `params` &ndash; the call-site params object (defaults to `{}`).
20
+ * The fetcher receives a single `context` argument carrying `env`,
21
+ * `controller`, `params`, and a broadcast/multicast-only `dispatch`.
22
+ * `env` is a live handle &mdash; dot reads inside the fetcher
23
+ * always see the latest per-`<Boundary>` Env, even after `await`
24
+ * boundaries. Every successful fetch writes through to a per-resource
25
+ * in-memory cache; pair with {@link Resource.Cachable} to persist
26
+ * across reloads.
67
27
  *
68
- * Resources do **not** carry any callbacks &ndash; side-effects
69
- * (broadcasting, logging, model updates) belong in the `useAction`
70
- * handler that awaited `context.actions.resource(...)`.
71
- *
72
- * Every successful fetch writes through to the per-fetcher {@link Cache}
73
- * (in-memory by default, persistent when an adapter is supplied via the
74
- * second argument).
28
+ * Concurrent calls fire fresh requests by default. Opt in to in-flight
29
+ * sharing per call via `.coalesce(key)` on the thenable returned from
30
+ * `context.actions.resource(...)`.
75
31
  *
76
32
  * @example
77
33
  * ```ts
78
- * import { Resource, Cache } from "march-hare";
34
+ * import { Resource } from "march-hare";
79
35
  *
80
- * export const user = Resource<User, { id: number }>(
81
- * ({ store, controller, params }) =>
82
- * ky.get(`users/${params.id}`, {
83
- * headers: store.session
84
- * ? { Authorization: `Bearer ${store.session.accessToken}` }
36
+ * export const user = Resource<User, { id: number }>((context) =>
37
+ * ky
38
+ * .get(`users/${context.params.id}`, {
39
+ * headers: context.env.session
40
+ * ? { Authorization: `Bearer ${context.env.session.accessToken}` }
85
41
  * : {},
86
- * signal: controller.signal,
87
- * }).json<User>(),
42
+ * signal: context.controller.signal,
43
+ * })
44
+ * .json<User>(),
88
45
  * );
89
- *
90
- * // Sync cache read at module scope or in the model literal.
91
- * const cached: User | null = user({ id: 5 });
92
- *
93
- * // Fetch inside a handler — controller and Store auto-threaded.
94
- * actions.useAction(Actions.Mount, async (context) => {
95
- * const data = await context.actions
96
- * .resource(user({ id: 5 }))
97
- * .exceeds({ minutes: 5 });
98
- * context.actions.produce(({ model }) => void (model.user = data));
99
- * });
100
46
  * ```
101
47
  */
102
- export declare function Resource<T, P extends object = Record<never, never>>(fetcher: Fetcher<T, P>, cache?: Cache): Resource<T, P>;
48
+ export declare function Resource<T, P extends object = Record<never, never>>(ƒ: Fetcher<T, P>): ResourceHandle<T, P>;
49
+ export declare namespace Resource {
50
+ /**
51
+ * Cache-aware variant of {@link Resource}. The supplied {@link Cache}
52
+ * is the **first** argument &mdash; persistence is the headline of
53
+ * this form, the fetcher is the operation. Every successful fetch
54
+ * writes through to the cache; first reads via the call form
55
+ * auto-seed from the cache's adapter.
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * import { Cache, Resource } from "march-hare";
60
+ *
61
+ * const cache = Cache({
62
+ * get: (key) => localStorage.getItem(key),
63
+ * set: (key, value) => localStorage.setItem(key, value),
64
+ * remove: (key) => localStorage.removeItem(key),
65
+ * clear: () => localStorage.clear(),
66
+ * });
67
+ *
68
+ * export const cat = Resource.Cachable(cache, async (context) =>
69
+ * ky
70
+ * .get("https://api.thecatapi.com/v1/images/search", {
71
+ * signal: context.controller.signal,
72
+ * })
73
+ * .json<Cat[]>()
74
+ * .then((cats) => cats[0]),
75
+ * );
76
+ * ```
77
+ */
78
+ function Cachable<T, P extends object = Record<never, never>>(cache: Cache, ƒ: Fetcher<T, P>): ResourceHandle<T, P>;
79
+ }
@@ -1,27 +1,103 @@
1
- import { Store } from '../boundary/components/store/index';
1
+ import { Env } from '../boundary/components/env/index';
2
+ import { Cache } from '../cache/index';
3
+ import { BroadcastPayload, MulticastPayload, Filter } from '../types/index';
2
4
  /**
3
- * Args object passed to every {@link Fetcher}. The fetcher destructures
4
- * whatever it needs; unused fields can be omitted.
5
+ * Dispatch surface exposed on a Resource fetcher's `context`. Restricted
6
+ * to broadcast and multicast actions &mdash; unicast targets the calling
7
+ * component, which a Resource fetcher does not have.
8
+ */
9
+ export type Dispatch = {
10
+ <C extends Filter = never>(action: BroadcastPayload<never, C> | MulticastPayload<never, C>): Promise<void>;
11
+ <P, C extends Filter = never>(action: BroadcastPayload<P, C> | MulticastPayload<P, C>, payload: P): Promise<void>;
12
+ };
13
+ /**
14
+ * `context` object passed to every {@link Fetcher}.
5
15
  *
6
- * - `store` &mdash; snapshot of the per-`<Boundary>` Store at the
7
- * moment the fetcher is invoked.
16
+ * - `env` &mdash; live read-only handle to the per-`<Boundary>` Env.
17
+ * Dot reads always reflect the latest value, even across `await`
18
+ * boundaries inside the fetcher &mdash; the handle is a `Proxy`
19
+ * that delegates property access to the live ref, identical to
20
+ * the `context.env` exposed to action handlers.
8
21
  * - `controller` &mdash; the `AbortController` auto-threaded from the
9
22
  * calling handler's `context.task.controller`. Pass
10
23
  * `controller.signal` to `fetch`/`ky`/`EventSource`, or call
11
24
  * `controller.abort()` to fail fast.
12
25
  * - `params` &mdash; the call-site params object. Defaults to `{}`.
26
+ * - `dispatch` &mdash; fire broadcast or multicast actions from inside
27
+ * the fetcher. Unicast is rejected at compile time.
13
28
  *
14
29
  * @internal
15
30
  */
16
31
  export type Args<P extends object = Record<never, never>> = {
17
- readonly store: Store;
32
+ readonly env: Env;
18
33
  readonly controller: AbortController;
19
34
  readonly params: P;
35
+ readonly dispatch: Dispatch;
20
36
  };
21
37
  /**
22
- * Fetcher signature accepted by `Resource`. Receives the args object
23
- * `{ store, controller, params }`. Side-effects (dispatching broadcasts,
24
- * analytics, etc.) belong in the calling `useAction` handler, not
25
- * inside the fetcher.
38
+ * Fetcher signature accepted by `Resource`. Receives a single `context`
39
+ * argument carrying a live Env handle, the abort controller, params,
40
+ * and a broadcast/multicast-only `dispatch`.
41
+ */
42
+ export type Fetcher<T, P extends object = Record<never, never>> = (context: Args<P>) => Promise<T>;
43
+ /**
44
+ * Per-call coalescing token. Two callers with the same Resource, same
45
+ * structural params, and equal `Coalesce` value share a single in-flight
46
+ * promise; different tokens (or different params) fire independent
47
+ * fetches. Primitives compose naturally via stringification; objects
48
+ * are serialised with `JSON.stringify`.
49
+ */
50
+ export type Coalesce = string | number | bigint | boolean | symbol | object;
51
+ /**
52
+ * Config form accepted by `Resource`. The fetcher shorthand
53
+ * `Resource(fetcher)` is equivalent to `Resource({ fetch: fetcher })`.
54
+ *
55
+ * - `fetch` &mdash; the fetcher.
56
+ * - `cache` &mdash; persist successful payloads via a {@link Cache}
57
+ * wired to an `Adapter` (localStorage, MMKV, etc). Omit for an
58
+ * in-memory cache scoped to this Resource.
59
+ */
60
+ export type Config<T, P extends object = Record<never, never>> = {
61
+ readonly fetch: Fetcher<T, P>;
62
+ readonly cache?: Cache;
63
+ };
64
+ /**
65
+ * Snapshot of the most recent resource invocation. `resource.cat(params)`
66
+ * writes one of these into a module-scope slot; the next
67
+ * `context.actions.resource(...)` / `.set(...)` call consumes it via
68
+ * `consumePending` and then clears the slot.
69
+ *
70
+ * @internal
71
+ */
72
+ export type PendingCall = {
73
+ readonly run: (env: Env, controller: AbortController, params: object, dispatch: Dispatch) => Promise<unknown>;
74
+ readonly read: (params: object) => {
75
+ data: unknown;
76
+ at: Temporal.Instant | null;
77
+ };
78
+ readonly seed: (params: object, data: unknown, at: Temporal.Instant) => void;
79
+ readonly params: object;
80
+ };
81
+ /**
82
+ * Resource handle returned by `Resource(...)` or `Resource.Cachable(...)`.
83
+ * Call it with `params` to read the per-params cache slot synchronously
84
+ * and prime the slot consumed by `context.actions.resource(...)` for a
85
+ * follow-up fetch or `context.actions.resource.set(...)` for an
86
+ * out-of-band write.
87
+ *
88
+ * ```ts
89
+ * // Sync cache read in a model literal.
90
+ * { cat: resource.cat({ id: 5 }) }
91
+ *
92
+ * // Fetch with `.exceeds(...)` for cache-aware refresh.
93
+ * await context.actions
94
+ * .resource(resource.cat({ id: 5 }))
95
+ * .exceeds({ minutes: 5 });
96
+ *
97
+ * // Write through to the per-params cache slot.
98
+ * context.actions.resource.set(resource.cat({ id: 5 }), data);
99
+ * ```
26
100
  */
27
- export type Fetcher<T, P extends object = Record<never, never>> = (args: Args<P>) => Promise<T>;
101
+ export type ResourceHandle<T, P extends object = Record<never, never>> = [
102
+ keyof P
103
+ ] extends [never] ? (params?: P) => T | null : (params: P) => T | null;
@@ -20,7 +20,7 @@ export declare function defaultCache(fetcher: object): Cache;
20
20
  /**
21
21
  * Stable string key derived from the call-site `params`. Two calls with
22
22
  * the same logical params (same key order, same primitive values) hit
23
- * the same slot. JSON.stringify is sufficient for the Chizu params
23
+ * the same slot. JSON.stringify is sufficient for the March Hare params
24
24
  * convention (primitive-leaf objects); callers who need order-stable
25
25
  * keying should normalise the object before passing it in.
26
26
  *
@@ -0,0 +1,63 @@
1
+ import { AppContextHandle, AppResource } from '../app/types';
2
+ import { Actions, Model, Props } from '../types/index';
3
+ import * as React from "react";
4
+ /**
5
+ * Handle returned by `app.Scope<MulticastActions>()`. Mirrors the {@link App}
6
+ * surface (`Boundary`, `useContext`, `useEnv`, `Resource`) but typed
7
+ * against a specific multicast action surface `MulticastActions` and the
8
+ * enclosing App's Env shape `S`.
9
+ *
10
+ * Notably absent: a nested `Scope` method. Nesting scopes is supported
11
+ * at the React-tree level &mdash; just render two `<scope.Boundary>`s
12
+ * &mdash; but each scope must come from a distinct
13
+ * `app.Scope<MulticastActions>()` call so that its multicast surface is
14
+ * declared up-front.
15
+ *
16
+ * @template S The enclosing App's Env shape.
17
+ * @template MulticastActions The multicast Actions class (or union of
18
+ * classes) this scope's `useContext().actions.dispatch` is allowed
19
+ * to fire.
20
+ */
21
+ export type Scope<S extends object, MulticastActions> = {
22
+ /**
23
+ * Boundary component. Wrap a subtree to open a fresh multicast scope
24
+ * &mdash; every `Distribution.Multicast` action dispatched inside this
25
+ * subtree routes through this boundary's emitter, and every handler
26
+ * subscribed via `scope.useContext().useActions(...)` on that subtree
27
+ * receives the event.
28
+ *
29
+ * Each render of `<scope.Boundary>` opens a distinct scope instance;
30
+ * unmounting tears the emitter down.
31
+ */
32
+ readonly Boundary: React.FC<{
33
+ children: React.ReactNode;
34
+ }>;
35
+ /**
36
+ * Hook returning a stable `Context` handle. Identical to
37
+ * `app.useContext` except `actions.dispatch` accepts the multicast
38
+ * surface `MulticastActions` in addition to the local `AC` &mdash; mirroring
39
+ * the way `Actions.Broadcast = BroadcastActions` already widens the
40
+ * dispatch surface for broadcasts.
41
+ */
42
+ readonly useContext: <LocalModel extends Model | void = void, AC extends Actions | void = void, D extends Props = Props>() => AppContextHandle<LocalModel, MulticastActions extends Actions ? AC extends Actions ? AC & MulticastActions : MulticastActions : AC, D, S>;
43
+ /**
44
+ * Read-only Proxy over the enclosing App's Env. Identical to
45
+ * `app.useEnv` &mdash; the Scope does not introduce its own Env;
46
+ * scopes are about multicast routing, not ambient state.
47
+ */
48
+ readonly useEnv: () => Readonly<S>;
49
+ /**
50
+ * Resource factory bound to the enclosing App's Env. Identical to
51
+ * `app.Resource`; provided on the scope handle for convenience so a
52
+ * scoped feature can keep all its primitives in one place.
53
+ */
54
+ readonly Resource: AppResource<S>;
55
+ };
56
+ /**
57
+ * Internal constructor for a {@link Scope} handle. Called from inside
58
+ * `App<S>()` so the enclosing Env shape `S` is captured at the type
59
+ * level.
60
+ *
61
+ * @internal
62
+ */
63
+ export declare function createScope<S extends object, MulticastActions>(): Scope<S, MulticastActions>;
@@ -0,0 +1,55 @@
1
+ import { AppContextHandle, AppResource } from '../app/types';
2
+ import { Actions, Model, Props } from '../types/index';
3
+ import type * as React from "react";
4
+ /**
5
+ * Handle returned by `app.Scope<MulticastActions>()`. Mirrors the
6
+ * `App` surface (`Boundary`, `useContext`, `useEnv`, `Resource`) but
7
+ * typed against a specific multicast action surface `MulticastActions`
8
+ * and the enclosing App's Env shape `S`.
9
+ *
10
+ * Notably absent: a nested `Scope` method. Nesting scopes is supported
11
+ * at the React-tree level &mdash; just render two `<scope.Boundary>`s
12
+ * &mdash; but each scope must come from a distinct
13
+ * `app.Scope<MulticastActions>()` call so that its multicast surface is
14
+ * declared up-front.
15
+ *
16
+ * @template S The enclosing App's Env shape.
17
+ * @template MulticastActions The multicast Actions class (or union of
18
+ * classes) this scope's `useContext().actions.dispatch` is allowed
19
+ * to fire.
20
+ */
21
+ export type Scope<S extends object, MulticastActions> = {
22
+ /**
23
+ * Boundary component. Wrap a subtree to open a fresh multicast scope
24
+ * &mdash; every `Distribution.Multicast` action dispatched inside this
25
+ * subtree routes through this boundary's emitter, and every handler
26
+ * subscribed via `scope.useContext().useActions(...)` on that subtree
27
+ * receives the event.
28
+ *
29
+ * Each render of `<scope.Boundary>` opens a distinct scope instance;
30
+ * unmounting tears the emitter down.
31
+ */
32
+ readonly Boundary: React.FC<{
33
+ children: React.ReactNode;
34
+ }>;
35
+ /**
36
+ * Hook returning a stable `Context` handle. Identical to
37
+ * `app.useContext` except `actions.dispatch` accepts the multicast
38
+ * surface `MulticastActions` in addition to the local `AC` &mdash;
39
+ * mirroring the way `Actions.Broadcast = BroadcastActions` already
40
+ * widens the dispatch surface for broadcasts.
41
+ */
42
+ readonly useContext: <LocalModel extends Model | void = void, AC extends Actions | void = void, D extends Props = Props>() => AppContextHandle<LocalModel, MulticastActions extends Actions ? AC extends Actions ? AC & MulticastActions : MulticastActions : AC, D, S>;
43
+ /**
44
+ * Read-only Proxy over the enclosing App's Env. Identical to
45
+ * `app.useEnv` &mdash; the Scope does not introduce its own Env;
46
+ * scopes are about multicast routing, not ambient state.
47
+ */
48
+ readonly useEnv: () => Readonly<S>;
49
+ /**
50
+ * Resource factory bound to the enclosing App's Env. Identical to
51
+ * `app.Resource`; provided on the scope handle for convenience so a
52
+ * scoped feature can keep all its primitives in one place.
53
+ */
54
+ readonly Resource: AppResource<S>;
55
+ };