@yoltra/core 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.es.md +322 -143
- package/README.md +85 -76
- package/dist/types/store/Store.d.ts +5 -52
- package/dist/types/store/matching.d.ts +49 -0
- package/dist/types/store/paths.d.ts +39 -0
- package/dist/types/store/performCall.d.ts +15 -0
- package/dist/types/store/rejection.d.ts +2 -2
- package/dist/types/types.d.ts +4 -4
- package/dist/yoltra.cjs +3 -8
- package/dist/yoltra.cjs.map +1 -1
- package/dist/yoltra.mjs +898 -938
- package/dist/yoltra.mjs.map +1 -1
- package/dist/yoltra.umd.js +3 -8
- package/dist/yoltra.umd.js.map +1 -1
- package/package.json +4 -3
package/dist/types/types.d.ts
CHANGED
|
@@ -251,8 +251,8 @@ export interface EmitOptions {
|
|
|
251
251
|
* Use this exact id for the event instead of generating one.
|
|
252
252
|
*
|
|
253
253
|
* @remarks
|
|
254
|
-
* Intended for **idempotent re-emission**: a caller replaying an event from elsewhere (
|
|
255
|
-
*
|
|
254
|
+
* Intended for **idempotent re-emission**: a caller replaying an event from elsewhere (another
|
|
255
|
+
* store, a durable log) can preserve the original id so the same logical event keeps
|
|
256
256
|
* one identity everywhere, which makes it traceable across systems and in DevTools.
|
|
257
257
|
*
|
|
258
258
|
* The store does **not** enforce uniqueness — supplying a duplicate id does not dedupe the
|
|
@@ -674,8 +674,8 @@ export interface StoreInstance<R extends string = string, S extends Record<R, an
|
|
|
674
674
|
*
|
|
675
675
|
* @remarks
|
|
676
676
|
* Awaitable for the terminal reply, async-iterable for progress. See the implementation on
|
|
677
|
-
* {@link Store.call} for the full contract
|
|
678
|
-
* is a local primitive
|
|
677
|
+
* {@link Store.call} for the full contract: correlation, backpressure, timeouts, and why it
|
|
678
|
+
* is a local primitive.
|
|
679
679
|
*/
|
|
680
680
|
call<C extends keyof EM & string, T extends keyof EM[C] & string>(channel: C, type: T, payload: EM[C][T], opts: CallOptions<EM>): CallHandle<EventUnion<EM>, EventUnion<EM>>;
|
|
681
681
|
/**
|
package/dist/yoltra.cjs
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @yoltra/core v0.
|
|
2
|
+
* @yoltra/core v0.7.0
|
|
3
3
|
* (c) 2026 Manu Ramirez <@pixerael>
|
|
4
|
-
* License: MIT
|
|
5
|
-
* Homepage: https://yoltra.dev
|
|
6
|
-
*
|
|
7
|
-
* This source code is licensed under the MIT license found in the
|
|
8
|
-
* LICENSE file in the root directory of this source tree
|
|
9
|
-
*/
|
|
10
|
-
"use strict";var G=Object.defineProperty;var J=(c,e,t)=>e in c?G(c,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):c[e]=t;var p=(c,e,t)=>J(c,typeof e!="symbol"?e+"":e,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class B{constructor(){p(this,"handlers",new Map)}on(e,t,s){let n=this.handlers.get(e);n||(n=new Map,this.handlers.set(e,n));let r=n.get(t);return r||(r=new Set,n.set(t,r)),r.add(s),()=>this.off(e,t,s)}off(e,t,s){const n=this.handlers.get(e);if(!n)return;const r=n.get(t);r&&(r.delete(s),r.size===0&&n.delete(t),n.size===0&&this.handlers.delete(e))}emit(e,t,s,n){const r=this.handlers.get(e);if(!r)return;const o=r.get(t);if(!(!o||o.size===0))for(const d of[...o])try{d(s,n)}catch(i){console.error("EventBus handler error:",i)}}clear(){this.handlers.clear()}}class H{constructor(){p(this,"handlers",new Map);p(this,"patternHandlers",new Map);p(this,"patternIndex",new Map)}on(e,t,s){const n=String(t);if(this.isPattern(n)){const r=n;this.patternHandlers.has(e)||this.patternHandlers.set(e,new Map);const o=this.patternHandlers.get(e);return o.has(r)||(o.set(r,[]),this.indexPattern(e,r)),o.get(r).push(s),()=>this.offPattern(e,r,s)}else{const r=this.normalizeTypeKey(n);this.handlers.has(e)||this.handlers.set(e,new Map);const o=this.handlers.get(e);return o.has(r)||o.set(r,[]),o.get(r).push(s),()=>this.offExactNormalized(e,r,s)}}off(e,t,s){const n=this.normalizeTypeKey(String(t));this.offExactNormalized(e,n,s)}offExactNormalized(e,t,s){const n=this.handlers.get(e);if(!n)return;const r=n.get(t);if(!r)return;const o=r.indexOf(s);o!==-1&&r.splice(o,1),r.length===0&&n.delete(t),n.size===0&&this.handlers.delete(e)}offPattern(e,t,s){const n=this.patternHandlers.get(e);if(!n)return;const r=n.get(t);if(!r)return;const o=r.indexOf(s);o!==-1&&r.splice(o,1),r.length===0&&(n.delete(t),this.unindexPattern(e,t)),n.size===0&&(this.patternHandlers.delete(e),this.patternIndex.delete(e))}emit(e,t,s){const n=String(t),r=this.normalizeTypeKey(n),o=this.handlers.get(e)?.get(r)??[],d=this.matchingPatternHandlers(e,n),i=new Set,a=l=>{for(const u of[...l])if(!i.has(u)){i.add(u);try{u(s)}catch(f){console.error(f);continue}}};a(o);for(const l of d)a(l)}emitWith(e,t,s){const n=String(t),r=this.normalizeTypeKey(n),o=this.handlers.get(e)?.get(r)??[],d=this.matchingPatternHandlers(e,n);if(o.length===0&&d.length===0)return;const i=s(),a=new Set,l=u=>{for(const f of[...u])if(!a.has(f)){a.add(f);try{f(i)}catch(m){console.error(m);continue}}};l(o);for(const u of d)l(u)}isPattern(e){return e.includes("*")}normalizeTypeKey(e){return e.replace(/^\./,"")}splitPath(e){return this.normalizeTypeKey(e).split(".").filter(Boolean)}indexPattern(e,t){let s=this.patternIndex.get(e);s===void 0&&(s={byHead:new Map,anyHead:[]},this.patternIndex.set(e,s));const n=this.splitPath(t),r={pattern:t,segments:n},o=n[0];if(o===void 0||o==="*"||o==="**"){s.anyHead.push(r);return}const d=s.byHead.get(o);d===void 0?s.byHead.set(o,[r]):d.push(r)}unindexPattern(e,t){const s=this.patternIndex.get(e);if(s===void 0)return;const n=this.splitPath(t)[0],r=n===void 0||n==="*"||n==="**"?s.anyHead:s.byHead.get(n);if(r===void 0)return;const o=r.findIndex(d=>d.pattern===t);o!==-1&&r.splice(o,1),r.length===0&&r!==s.anyHead&&n!==void 0&&s.byHead.delete(n)}matchingPatternHandlers(e,t){const s=this.patternHandlers.get(e),n=this.patternIndex.get(e);if(s===void 0||s.size===0||n===void 0)return[];const r=this.splitPath(t),o=[],d=a=>{for(const l of a){if(!this.matchSegments(l.segments,r))continue;const u=s.get(l.pattern);u!==void 0&&o.push(u)}},i=r[0];if(i!==void 0){const a=n.byHead.get(i);a!==void 0&&d(a)}return d(n.anyHead),o}matchSegments(e,t){let s=0,n=0,r=-1,o=0;for(;n<t.length;)if(s<e.length&&(e[s]==="*"||e[s]===t[n]))s++,n++;else if(s<e.length&&e[s]==="**")r=s,o=n,s++;else if(r!==-1)s=r+1,n=++o;else return!1;for(;s<e.length&&e[s]==="**";)s++;return s===e.length}clear(){this.handlers.clear(),this.patternHandlers.clear(),this.patternIndex.clear()}__introspect(){const e=[];for(const[t,s]of this.handlers)for(const[n,r]of s)r.length>0&&e.push({channel:t,type:n,count:r.length});for(const[t,s]of this.patternHandlers)for(const[n,r]of s)r.length>0&&e.push({channel:t,type:n,count:r.length});return e}}class W{constructor(e){p(this,"_reduce");this._reduce=e}reduce(e,t){return this._reduce(e,t)}}const D=new Set;function x(c,e){const t=c?`${c}.${e}`:e;D.has(t)||(D.add(t),console.warn(`[yoltra] State key "${e}"${c?` under "${c}"`:""} contains a dot. Paths are dotted, so this key is indistinguishable from nested objects of the same name: a subscription to "${t}" may match the wrong value, and DevTools patches for it will address the wrong node. Rename the key, or nest it.`))}function T(c,e,t="",s=new Map){const n=[];return R(c,e,t,s,n),n}function R(c,e,t,s,n){if(c===e)return;if(typeof c!="object"||typeof e!="object"||c===null||e===null){if(typeof c=="number"&&Number.isNaN(c)&&Number.isNaN(e))return;n.push(t);return}if(c instanceof Date&&e instanceof Date){c.getTime()!==e.getTime()&&n.push(t);return}if(c instanceof RegExp&&e instanceof RegExp){(c.source!==e.source||e.flags!==c.flags)&&n.push(t);return}if(c instanceof Map||e instanceof Map){n.push(t);return}if(c instanceof Set||e instanceof Set){n.push(t);return}const r=c,o=e,d=s.get(r);if(d?.has(o))return;const i=d??new Set;i.add(o),d||s.set(r,i);try{const a=Array.isArray(c),l=Array.isArray(e);if(a!==l){n.push(t);return}if(a){const h=c,y=e;h.length!==y.length&&t&&n.push(t);const g=Math.min(h.length,y.length);for(let E=0;E<g;E++)h[E]!==y[E]&&R(h[E],y[E],t?`${t}.${E}`:`${E}`,s,n);for(let E=g;E<Math.max(h.length,y.length);E++)n.push(t?`${t}.${E}`:`${E}`);return}const u=Object.keys(c),f=Object.keys(e);if(u.length===0&&f.length===0){n.push(t);return}let m=u.length===f.length;if(m){for(let h=0;h<f.length;h++)if(!Object.prototype.hasOwnProperty.call(c,f[h])){m=!1;break}}if(m){for(const h of f)c[h]!==e[h]&&(process.env.NODE_ENV!=="production"&&h.includes(".")&&x(t,h),R(c[h],e[h],t?`${t}.${h}`:h,s,n));return}for(const h of f){const y=Object.prototype.hasOwnProperty.call(c,h);if(y&&c[h]===e[h])continue;process.env.NODE_ENV!=="production"&&h.includes(".")&&x(t,h);const g=t?`${t}.${h}`:h;if(!y){n.push(g);continue}R(c[h],e[h],g,s,n)}for(const h of u)Object.prototype.hasOwnProperty.call(e,h)||(process.env.NODE_ENV!=="production"&&h.includes(".")&&x(t,h),n.push(t?`${t}.${h}`:h))}finally{i.delete(o),i.size===0&&s.delete(r)}}function k(c,e=new WeakSet,t){if(c===null||typeof c!="object"||e.has(c)||(t!==void 0&&c===t.watch&&t.onFound(),Object.isFrozen(c)))return c;if(e.add(c),Array.isArray(c)){const s=c;for(let n=0;n<s.length;n++)s[n]=k(s[n],e,t);return Object.freeze(s)}for(const s of Object.getOwnPropertyNames(c)){const n=Object.getOwnPropertyDescriptor(c,s);!n||!("value"in n)||(c[s]=k(c[s],e,t))}for(const s of Object.getOwnPropertySymbols(c)){const n=Object.getOwnPropertyDescriptor(c,s);!n||!("value"in n)||(c[s]=k(c[s],e,t))}return Object.freeze(c)}const K=Symbol.for("yoltra.rejected");function q(c){return{[K]:!0,reason:c}}function F(c){return typeof c=="object"&&c!==null&&c[K]===!0}class Y{constructor(e){p(this,"highWaterMark");p(this,"buffer",[]);p(this,"takers",[]);p(this,"putters",[]);p(this,"consuming",!1);p(this,"ended",!1);p(this,"closed",!1);p(this,"dropped",0);this.highWaterMark=e}get droppedCount(){return this.dropped}beginConsuming(){this.consuming=!0}put(e){if(this.closed||this.ended)return Promise.resolve();const t=this.takers.shift();return t!==void 0?(t({value:e,done:!1}),Promise.resolve()):this.buffer.length<this.highWaterMark?(this.buffer.push(e),Promise.resolve()):this.consuming?new Promise(s=>{this.putters.push({item:e,release:s})}):(this.dropped++,Promise.resolve())}take(){this.consuming=!0;const e=this.buffer.shift();if(e!==void 0){const s=this.putters.shift();return s!==void 0&&(this.buffer.push(s.item),s.release()),Promise.resolve({value:e,done:!1})}const t=this.putters.shift();return t!==void 0?(t.release(),Promise.resolve({value:t.item,done:!1})):this.closed||this.ended?Promise.resolve({value:void 0,done:!0}):new Promise(s=>{this.takers.push(s)})}end(){if(this.ended||this.closed)return;this.ended=!0;let e=this.putters.shift();for(;e!==void 0;)this.buffer.push(e.item),e.release(),e=this.putters.shift();let t=this.takers.shift();for(;t!==void 0;){const s=this.buffer.shift();t(s!==void 0?{value:s,done:!1}:{value:void 0,done:!0}),t=this.takers.shift()}}close(){if(this.closed)return;this.closed=!0,this.buffer.length=0;let e=this.takers.shift();for(;e!==void 0;)e({value:void 0,done:!0}),e=this.takers.shift();let t=this.putters.shift();for(;t!==void 0;)t.release(),t=this.putters.shift()}}class U extends Error{constructor(t,s,n){super(`[yoltra] call to "${t}/${s}" saw no correlated reply for ${n}ms. The timeout is idle rather than total, so this means the responder went quiet, not that it was slow. Check that something handles "${t}/${s}" and that its reply is emitted through the \`emit\` it was handed — a reply emitted from an unrelated context carries no causal link, and needs an explicit correlationId instead.`);p(this,"channel");p(this,"type");p(this,"idleMs");this.name="CallTimeoutError",this.channel=t,this.type=s,this.idleMs=n}}class I extends Error{constructor(e){super(`[yoltra] call aborted: ${e}`),this.name="CallAbortedError"}}function X(c){const[e,t]=c;if(t===void 0)return{channel:e,isTerminal:()=>!0};if(typeof t=="string")return{channel:e,isTerminal:n=>n===t};const s=new Set(t);return{channel:e,isTerminal:n=>s.has(n)}}function Z(c,e,t){return c.parentId===e?!0:t===void 0?!1:c.meta?.correlationId===t}function ee(c,e){try{return structuredClone(e)}catch(t){throw new Error(`[yoltra] Initial state for slice "${String(c)}" could not be copied: ${t instanceof Error?t.message:String(t)}. State must be structured-cloneable — functions, class instances and DOM nodes are not. Keep behaviour out of state and store plain data.`)}}function O(c,e){return process.env.NODE_ENV==="production"?c:k(c,new WeakSet,e)}const z=100,te=64,A=16,ne=3e4,se=16,$=Object.freeze({committed:!1,written:!1}),re=Object.freeze({committed:!0,written:!1}),ie=Object.freeze({committed:!0,written:!0}),j=()=>typeof performance<"u"&&typeof performance.now=="function"?performance.now():Date.now();class P{constructor(e){p(this,"name");p(this,"middleware");p(this,"reducers");p(this,"state");p(this,"reducerBus");p(this,"connectorBus");p(this,"listeners",new Set);p(this,"effects",new Map);p(this,"patternEffects",new Set);p(this,"committedEventSubscribers",new Map);p(this,"uncommittedEventSubscribers",new Map);p(this,"writtenEventSubscribers",new Map);p(this,"allEventSubscribers",new Map);p(this,"sliceUnsubs",new Map);p(this,"patternReducers",new Map);p(this,"replayEnabled");p(this,"idFactory");p(this,"onEffectError");p(this,"onReducerError");p(this,"warnedPayloadAliases",new Set);p(this,"reduceQueue",[]);p(this,"isReducing",!1);p(this,"currentEvent",null);p(this,"transitionsThisDrain",0);p(this,"maxReduceDepth");p(this,"maxTransitionsPerDrain");p(this,"onCascade");p(this,"onRejected");p(this,"instrumentObservers",new Set);p(this,"changedPathSink",null);p(this,"stagingSink",null);p(this,"stagedRejection",null);p(this,"stagedRejectedBy","");p(this,"inFlightEffects",0);p(this,"processedEvents",new Map);p(this,"dedupCount",0);p(this,"effectMeta",new WeakMap);p(this,"dedupConfig");p(this,"eventCleanupTimer",null);if(this.name=e.name??"yoltra Store",this.reducerBus=new B,this.connectorBus=new H,this.middleware=[...e.middleware??[]],this.reducers={},this.state={},this.replayEnabled=e.devtools?.allowReplay??!1,this.idFactory=e.idFactory??(()=>crypto.randomUUID()),this.onEffectError=e.onEffectError,this.onReducerError=e.onReducerError,this.maxReduceDepth=e.maxReduceDepth??te,this.maxTransitionsPerDrain=e.maxTransitionsPerDrain??1/0,this.onCascade=e.onCascade,this.onRejected=e.onRejected,this.dedupConfig={windowMs:e.dedupWindowMs??0,maxCacheSize:1e3},Object.entries(e.reducer).forEach(([t,s])=>{this.mountSlice(t,s,{preserveState:!1})}),e.effects?.length)for(const t of e.effects)this.registerEffect(t);this.dispose=this.dispose.bind(this),this.notifyEffects=this.notifyEffects.bind(this),this.__applyExternalState=this.__applyExternalState.bind(this),this.__replayEvents=this.__replayEvents.bind(this),this.__devtoolsIntrospect=this.__devtoolsIntrospect.bind(this),this.mountSlice=this.mountSlice.bind(this),this.unmountSlice=this.unmountSlice.bind(this),this.getAtPath=this.getAtPath.bind(this),this.emit=this.emit.bind(this),this.subscribe=this.subscribe.bind(this),this.connect=this.connect.bind(this),this.onEffect=this.onEffect.bind(this),this.onEvent=this.onEvent.bind(this),this.getState=this.getState.bind(this),this.registerEffect=this.registerEffect.bind(this),this.registerMiddleware=this.registerMiddleware.bind(this),this.registerReducer=this.registerReducer.bind(this),this.replaceMiddleware=this.replaceMiddleware.bind(this),this.replaceEffects=this.replaceEffects.bind(this),this.replaceReducers=this.replaceReducers.bind(this),this.hotReplace=this.hotReplace.bind(this)}dispose(){this.eventCleanupTimer&&(clearInterval(this.eventCleanupTimer),this.eventCleanupTimer=null),this.processedEvents.clear(),this.effects.clear(),this.patternEffects.clear(),this.effectMeta=new WeakMap,this.warnedPayloadAliases.clear(),this.listeners.clear(),this.committedEventSubscribers.clear(),this.uncommittedEventSubscribers.clear(),this.writtenEventSubscribers.clear(),this.allEventSubscribers.clear(),this.instrumentObservers.clear(),this.connectorBus.clear(),this.reducerBus.clear(),this.patternReducers.clear(),this.sliceUnsubs.clear(),this.changedPathSink=null}fingerprint(e,t,s){const n=`${e}::${t}`;try{if(s==null)return`${n}::null`;if(typeof s!="object")return`${n}::${String(s)}`;const r=JSON.stringify(s);return`${n}::${r}`}catch{return`${n}::${Date.now()}::${Math.random()}`}}shouldDedupe(e,t){const s=Date.now(),n=this.processedEvents.get(e);return n!==void 0&&s-n<t?(this.dedupCount++,!0):(this.processedEvents.set(e,s),this.ensureCleanupTimer(),this.processedEvents.size>this.dedupConfig.maxCacheSize&&this.pruneProcessedEvents(s),!1)}ensureCleanupTimer(){this.eventCleanupTimer===null&&(this.eventCleanupTimer=setInterval(()=>{this.pruneProcessedEvents(Date.now())},5e3),this.eventCleanupTimer.unref?.())}pruneProcessedEvents(e){const t=Math.max(this.dedupConfig.windowMs,z),s=e-t*2;for(const[n,r]of this.processedEvents)r<s&&this.processedEvents.delete(n);this.processedEvents.size===0&&this.eventCleanupTimer!==null&&(clearInterval(this.eventCleanupTimer),this.eventCleanupTimer=null)}reportCascade(e,t,s,n,r){console.error(`[yoltra] Cascade stopped: "${s.channel}/${s.type}" would exceed ${e} (${t}). This event was refused and the chain ends here. A chain this long is almost always two consumers emitting into each other — check what reacts to "${s.channel}/${s.type}" and what that emits in turn.`+(r.length>0?` Recent causal chain: ${r.join(" → ")} → (refused).`:""));try{this.onCascade?.({limit:e,limitValue:t,event:s,depth:n,chain:r})}catch(o){console.error("onCascade handler error:",o)}}matchesWhen(e,t){return!e||"any"in e&&e.any===!0?!0:"keys"in e?e.keys.some(([s,n])=>t.channel===s&&t.type===n):"channel"in e?t.channel===e.channel:"channels"in e?e.channels.includes(t.channel):!1}getMiddlewareFunction(e){return typeof e=="function"?e:e.middleware}getMiddlewareWhen(e){if(typeof e!="function")return e.when}async notifyEffects(e){const t=this.scopedEmit(e),s=`${String(e.channel)}::${String(e.type)}`,n=this.effects.get(s);if(n&&n.size>0)for(const r of[...n])try{await r(e,this.getState,t)}catch(o){console.error("Effect error:",o),this.onEffectError?.(o,e)}for(const{effect:r,when:o}of this.patternEffects)if(this.matchesWhen(o,e))try{await r(e,this.getState,t)}catch(d){console.error("Effect error:",d),this.onEffectError?.(d,e)}}scopedEmit(e){const t={id:e.id,depth:e.depth??0,chain:[...this.currentEvent?.chain??[],e.id].slice(-A)};return((s,n,r,o)=>this.emitCaused(t,s,n,r,o))}notifyEventSubscribers(e,t){const s=`${String(e.channel)}::${String(e.type)}`,r=(t==="committed"?this.committedEventSubscribers:t==="written"?this.writtenEventSubscribers:this.uncommittedEventSubscribers).get(s);if(r?.size)for(const d of[...r])this.invokeEventSubscriber(d,e,t);if(t==="written")return;const o=this.allEventSubscribers.get(s);if(o?.size)for(const d of[...o])this.invokeEventSubscriber(d,e,t)}invokeEventSubscriber(e,t,s){try{const n=e(t,this.getState,this.emit,s);n&&typeof n.then=="function"&&n.catch(r=>console.error("Event subscription error:",r))}catch(n){console.error("Event subscription error:",n)}}stageSliceGuarded(e,t,s){try{return this.stageSlice(e,t,s)}catch(n){return console.error(`Reducer error in slice "${e}":`,n),this.onReducerError?.(n,t,e),null}}stageSlice(e,t,s){const n=this.state[e],r=this.reducers[e].reduce(n,t);if(F(r))return r;if(n===r)return null;const o=T(n,r);if(o.length===0)return null;const d=t.payload,i=process.env.NODE_ENV!=="production"&&d!==null&&typeof d=="object"?{watch:d,onFound:()=>{const a=`${e}:${t.channel}:${t.type}`;this.warnedPayloadAliases.has(a)||(this.warnedPayloadAliases.add(a),console.warn(`[yoltra] Slice "${e}" stored the payload of "${t.channel}/${t.type}" by reference. It is now frozen along with the rest of the state, so the emitter mutating it later will throw in development and silently corrupt state in production. Copy the payload in the reducer instead.`))}}:void 0;return s.push({name:e,prev:n,frozen:O(r,i),leafPaths:o}),null}commitStaged(e,t){if(e.length===0)return!1;const s={...this.state};for(const n of e)s[n.name]=n.frozen;if(this.state=s,this.changedPathSink)for(const n of e)for(const r of n.leafPaths)this.changedPathSink.push(r?`${n.name}.${r}`:n.name);for(const n of e){const r=new Set;for(const o of n.leafPaths){if(o===""){r.add("");continue}for(const d of P.buildAncestorPaths(o))r.add(d)}for(const o of r)this.connectorBus.emitWith(n.name,o,()=>({oldValue:this.getAtPath(n.prev,o),newValue:this.getAtPath(n.frozen,o),path:o,eventId:t.id,channel:t.channel,type:t.type}))}return!0}__devtoolsIntrospect(){const e=Object.keys(this.reducers).map(d=>{const i=this.patternReducers.get(d);return{name:d,when:i}}),t=[];for(const[d,i]of this.effects){if(i.size===0)continue;const[a,l]=d.split("::");for(const u of i){const f=this.effectMeta.get(u);t.push({channel:a,type:l,name:f?.name,description:f?.description})}}for(const d of this.patternEffects){const i=this.effectMeta.get(d.effect);t.push({channel:"*",type:"*",name:i?.name,description:i?.description})}const s=[];for(const d of this.middleware)typeof d=="function"?s.push({name:d.name||void 0}):s.push({name:d.meta?.name,description:d.meta?.description,when:d.when});const n=[];for(const d of this.connectorBus.__introspect())for(let i=0;i<d.count;i++)n.push({reducer:d.channel,property:d.type});const r=[];for(const[d,i]of this.committedEventSubscribers){if(i.size===0)continue;const[a,l]=d.split("::");for(let u=0;u<i.size;u++)r.push({channel:a,type:l,phase:"committed"})}for(const[d,i]of this.uncommittedEventSubscribers){if(i.size===0)continue;const[a,l]=d.split("::");for(let u=0;u<i.size;u++)r.push({channel:a,type:l,phase:"uncommitted"})}for(const[d,i]of this.allEventSubscribers){if(i.size===0)continue;const[a,l]=d.split("::");for(let u=0;u<i.size;u++)r.push({channel:a,type:l,phase:"all"})}const o=this.listeners.size;return{reducers:e,effects:t,middleware:s,atomic:n,event:r,coarse:o,dedupHits:this.dedupCount,queueDepth:this.reduceQueue.length+this.inFlightEffects}}__applyExternalState(e){if(!this.replayEnabled)throw new Error("[yoltra] External state apply (time-travel) is disabled. Enable it with createStore({ devtools: { allowReplay: true } })");const t=this.state,s=e,n={...this.state};let r=!1;Object.keys(this.reducers).forEach(o=>{const d=t?.[o],i=s?.[o];if(i===void 0){process.env.NODE_ENV!=="production"&&console.warn(`[yoltra] External state is missing slice "${String(o)}"; retaining its current value. Time-travel snapshots should contain all slices.`);return}if(d===i)return;const a=O(i);n[o]=a,r=!0;const l=T(d,i);if(l.length===0)return;const u=new Set;for(const f of l){if(f===""){u.add("");continue}for(const m of P.buildAncestorPaths(f))u.add(m)}for(const f of u){const m=this.getAtPath(d,f),h=this.getAtPath(a,f);this.connectorBus.emit(o,f,{oldValue:m,newValue:h,path:f})}}),r&&(this.state=n),r&&this.listeners.forEach(o=>o())}__replayEvents(e,t){if(!this.replayEnabled)throw new Error("[yoltra] Event replay is disabled. Enable it with createStore({ devtools: { allowReplay: true } })");this.__applyExternalState(e);for(const s of t){const n=s,r=[];this.stagingSink=r;let o=null;try{this.reducerBus.emit(n.channel,n.type,n.payload,n),o=this.stagedRejection;for(const[i,a]of this.patternReducers){if(o!==null)break;if(this.matchesWhen(a,n)){const l=this.stageSliceGuarded(i,n,r);l!==null&&(o=l)}}}finally{this.stagingSink=null,this.stagedRejection=null,this.stagedRejectedBy=""}const d=o===null&&this.commitStaged(r,n);this.notifyEventSubscribers(n,"committed"),d&&(this.notifyEventSubscribers(n,"written"),this.listeners.forEach(i=>i()))}}async emit(e,t,s,n){return this.emitCaused(null,e,t,s,n)}async emitCaused(e,t,s,n,r){const o=r?.dedupKey,d=this.dedupConfig.windowMs;if(r?.skipDedup!==!0&&(d>0||o!==void 0)){const m=o!==void 0&&d<=0?z:d,h=o!==void 0?`${t}::${s}::#${o}`:this.fingerprint(t,s,n);if(this.shouldDedupe(h,m))return $}const i=r?.id??this.idFactory(),a=this.currentEvent??e,l=a===null?0:a.depth+1;if(a!==null&&l>this.maxReduceDepth)return this.reportCascade("maxReduceDepth",this.maxReduceDepth,{channel:t,type:s,payload:n,id:i,...r?.meta!==void 0?{meta:r.meta}:{},parentId:a.id,depth:l},l,a.chain),$;let u;const f=new Promise(m=>{u=m});return this.reduceQueue.push({channel:t,type:s,payload:n,id:i,meta:r?.meta,resolve:u,...a!==null?{parentId:a.id,depth:l,chain:a.chain}:{}}),this.drainReduce(),f}drainReduce(){if(!this.isReducing){this.isReducing=!0,this.transitionsThisDrain=0;try{for(;this.reduceQueue.length>0;){const e=this.reduceQueue.shift(),{channel:t,type:s,payload:n,id:r,meta:o,resolve:d,parentId:i,depth:a,chain:l}=e,u={channel:t,type:s,payload:n,id:r,...o!==void 0?{meta:o}:{},...i!==void 0?{parentId:i,depth:a}:{}};if(i!==void 0&&++this.transitionsThisDrain>this.maxTransitionsPerDrain){this.reportCascade("maxTransitionsPerDrain",this.maxTransitionsPerDrain,u,a,l),d($);continue}this.currentEvent={id:r,depth:a??0,chain:[...l??[],r].slice(-A)};const f=this.instrumentObservers.size>0,m=f?this.state:void 0,h=f?[]:void 0;h!==void 0&&(this.changedPathSink=h);const y=f?j():0;let g=$;try{g=this.applyEventSync(u)}catch(E){console.error("Emit reduce error:",E)}finally{f&&(this.changedPathSink=null),this.currentEvent=null}f&&this.emitInstrumentation(u,g,h??[],m,j()-y),this.runEventEffects(u,g,d)}}finally{this.isReducing=!1}}}applyEventSync(e){for(const o of this.middleware){const d=this.getMiddlewareWhen(o);if(!this.matchesWhen(d,e))continue;const i=this.getMiddlewareFunction(o);let a;try{a=i(this.state,e,this.emit),process.env.NODE_ENV!=="production"&&typeof a?.then=="function"&&console.error(`[yoltra] Middleware for "${e.channel}/${e.type}" returned a Promise. Middleware is synchronous: a Promise is truthy, so this event was allowed without waiting and a "return false" inside it can never veto. Do the check synchronously, and put anything that must await in an effect.`)}catch(l){console.error("Middleware error:",l),a=!1}if(!a)return this.notifyEventSubscribers(e,"uncommitted"),$}const t=[];this.stagingSink=t;let s=null,n="";try{this.reducerBus.emit(e.channel,e.type,e.payload,e),s=this.stagedRejection,n=this.stagedRejectedBy;for(const[o,d]of this.patternReducers){if(s!==null)break;if(this.matchesWhen(d,e)){const i=this.stageSliceGuarded(o,e,t);i!==null&&(s=i,n=o)}}}finally{this.stagingSink=null,this.stagedRejection=null,this.stagedRejectedBy=""}if(s!==null)return this.onRejected?.(s,e,n),this.notifyEventSubscribers(e,"committed"),{committed:!0,written:!1,rejected:s};const r=this.commitStaged(t,e);return this.notifyEventSubscribers(e,"committed"),r&&(this.notifyEventSubscribers(e,"written"),this.listeners.forEach(o=>o())),r?ie:re}async runEventEffects(e,t,s){this.inFlightEffects++;try{t.committed&&await this.notifyEffects(e)}catch(n){console.error("Effect error:",n)}finally{this.inFlightEffects--,s(t)}}instrument(e){return this.instrumentObservers.add(e),()=>{this.instrumentObservers.delete(e)}}emitInstrumentation(e,t,s,n,r){const o={},d={};for(const a of s)o[a]=this.getAtPath(n,a),d[a]=this.getAtPath(this.state,a);const i={event:{id:e.id,channel:e.channel,type:e.type,payload:e.payload,...e.meta!==void 0?{meta:e.meta}:{}},committed:t.committed,changedPaths:s,prevValues:o,nextValues:d,reduceTimeMs:r,...t.rejected!==void 0?{rejected:t.rejected}:{}};for(const a of[...this.instrumentObservers])try{a(i)}catch(l){console.error("Instrumentation observer error:",l)}}connect(e,t,s){const n=this.connectorBus.on(e.reducer,e.property,t);if(s?.immediate===!0){const r=this.state[e.reducer],o=e.property.includes("*")?"":e.property;t({oldValue:void 0,newValue:this.getAtPath(r,o),path:o})}return n}onEvent(e,t,s,n="committed"){const r=`${e}::${String(t)}`,o=n==="committed"?this.committedEventSubscribers:n==="uncommitted"?this.uncommittedEventSubscribers:n==="written"?this.writtenEventSubscribers:this.allEventSubscribers;return o.has(r)||o.set(r,new Set),o.get(r).add(s),()=>{const d=o.get(r);d&&(d.delete(s),d.size===0&&o.delete(r))}}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}getState(){return this.state}registerMiddleware(e){return this.middleware.push(e),()=>{const t=this.middleware.indexOf(e);t!==-1&&this.middleware.splice(t,1)}}registerReducer(e,t){if(Object.prototype.hasOwnProperty.call(this.reducers,e))throw new Error(`Reducer ${e} already exists`);return this.mountSlice(e,t,{preserveState:!1}),this.listeners.forEach(s=>s()),()=>{this.unmountSlice(e,{deleteState:!0}),this.listeners.forEach(s=>s())}}call(e,t,s,n){const{channel:r,isTerminal:o}=X(n.reply),d=n.timeoutMs??ne,i=new Y(n.highWaterMark??se),a=this.idFactory();let l,u,f=!1;const m=new Promise((b,S)=>{l=b,u=S});m.catch(()=>{});let h=null,y=null;const g=(b,S=!1)=>{f||(f=!0,h!==null&&clearTimeout(h),h=null,y?.(),y=null,S?i.end():i.close(),n.signal?.removeEventListener("abort",E),b())};function E(){g(()=>u(new I(String(n.signal?.reason??"signal aborted"))))}const M=()=>{h!==null&&clearTimeout(h),h=setTimeout(()=>{g(()=>u(new U(e,t,d)))},d),h.unref?.()};return y=this.registerEffect({when:{channel:r},effect:async b=>{if(!f&&Z(b,a,n.correlationId)){if(M(),o(String(b.type))){g(()=>l(b),!0);return}await i.put(b)}}}),n.signal!==void 0&&(n.signal.aborted?E():n.signal.addEventListener("abort",E,{once:!0})),M(),this.emit(e,t,s,{id:a,...n.correlationId!==void 0?{meta:{correlationId:n.correlationId}}:{}}),{then:(b,S)=>m.then(b,S),catch:b=>m.catch(b),finally:b=>m.finally(b),get dropped(){return i.droppedCount},cancel:(b="cancelled")=>{g(()=>u(new I(b)))},[Symbol.asyncIterator]:()=>(i.beginConsuming(),{next:()=>i.take(),return:async()=>(i.close(),{value:void 0,done:!0})})}}registerEffect(e){const{effect:t,meta:s,when:n}=e,r=[];if(s&&this.effectMeta.set(t,s),n&&("any"in n&&n.any===!0||"channel"in n||"channels"in n)){const i={effect:t,when:n};return this.patternEffects.add(i),()=>{this.patternEffects.delete(i)}}const d=this.normalizeEventKeys(e);if(d.length===0&&!n){const i={effect:t,when:{any:!0}};return this.patternEffects.add(i),()=>{this.patternEffects.delete(i)}}for(const[i,a]of d){const l=`${String(i)}::${String(a)}`;this.effects.has(l)||this.effects.set(l,new Set),this.effects.get(l).add(t),r.push(()=>{const u=this.effects.get(l);u&&(u.delete(t),u.size===0&&this.effects.delete(l))})}return()=>{for(const i of r)i()}}onEffect(e,t,s){const n=async(r,o,d)=>{if(r.channel!==e||r.type!==t)return;const i=r;return s(i.payload,o,d,i)};return this.registerEffect({when:{keys:[[e,t]]},effect:n})}replaceMiddleware(e){this.middleware.length=0;for(const t of e)this.middleware.push(t)}replaceEffects(e){this.effects.clear(),this.patternEffects.clear();for(const t of e)this.registerEffect(t)}replaceReducers(e,t={}){const s=t.preserveState!==!1,n=new Set(Object.keys(this.reducers)),r=Object.entries(e),o=new Set(r.map(([d])=>d));for(const d of n)o.has(d)||this.unmountSlice(d,{deleteState:!0});for(const[d,i]of r)n.has(d)?(this.unmountSlice(d,{deleteState:!1}),this.mountSlice(d,i,{preserveState:s})):this.mountSlice(d,i,{preserveState:!1})}hotReplace(e){e.middleware&&this.replaceMiddleware(e.middleware),e.effects&&this.replaceEffects(e.effects),e.reducer&&this.replaceReducers(e.reducer,{preserveState:e.preserveState})}mountSlice(e,t,s){const n=e,{reducer:r,state:o,when:d}=t;if(this.reducers[e]=new W(r),(!s.preserveState||this.state[n]===void 0)&&(this.state={...this.state,[n]:O(ee(n,o))}),d&&("any"in d&&d.any===!0||"channel"in d||"channels"in d)){this.patternReducers.set(e,d),this.sliceUnsubs.set(n,[]);return}const a=this.normalizeEventKeys(t);if(a.length===0&&!d){this.patternReducers.set(e,{any:!0}),this.sliceUnsubs.set(n,[]);return}const l=[];for(const[u,f]of a){const m=this.reducerBus.on(u,f,(h,y)=>{const g=y??{channel:u,type:f,payload:h,id:this.idFactory()};if(this.stagingSink===null)return;const E=this.stageSliceGuarded(e,g,this.stagingSink);E!==null&&this.stagedRejection===null&&(this.stagedRejection=E,this.stagedRejectedBy=e)});l.push(m)}this.sliceUnsubs.set(n,l)}unmountSlice(e,t){const s=e;this.patternReducers.delete(e);const n=this.sliceUnsubs.get(s);if(n){for(const r of n)try{r()}catch(o){console.error(`[Store error]: ${o}`)}this.sliceUnsubs.delete(s)}if(delete this.reducers[e],t.deleteState){const{[s]:r,...o}=this.state;this.state=o}}normalizeEventKeys(e){if(e.when){const t=e.when;if("keys"in t)return t.keys}return[]}getAtPath(e,t){if(!t)return e;const n=(t[0]==="."?t.slice(1):t).split(".");let r=e;for(const o of n){if(r==null)return;r=r[o]}return r}static buildAncestorPaths(e){if(!e)return[];const s=(e[0]==="."?e.slice(1):e).split("."),n=[];for(let r=0;r<s.length;r++)n.push(s.slice(0,r+1).join("."));return n}}function oe(c){return new P({...c,reducer:c.reducer??{},middleware:c.middleware??[],effects:c.effects??[]})}const ce=c=>(e,t)=>t.map(s=>[e,s]),ae=()=>c=>c,_=new Set;function de(c){const e=String(c);_.has(e)||(_.add(e),console.warn(`[yoltra] Entity id "${e}" contains a dot. Paths are dotted, so a subscription to "entities.${e}" is indistinguishable from one to a nested object of the same name. Use ids without dots.`))}function le(c,e){if(c.length!==e.length)return e;for(let t=0;t<c.length;t++)if(c[t]!==e[t])return e;return c}function ue(c={}){const e=c.selectId??(i=>i.id),{sortComparer:t}=c,s=(i,a)=>{if(t===void 0)return a;const l=[...a].sort((u,f)=>{const m=i.entities[u],h=i.entities[f];return m===void 0||h===void 0?0:t(m,h)});return le(a,l)},n=(i,a,l)=>{const u={...i,entities:a,ids:l};return{...u,ids:s(u,l)}},r=(i,a,l)=>{let u=null,f=null;for(const m of a){const h=e(m);process.env.NODE_ENV!=="production"&&String(h).includes(".")&&de(h);const y=(u??i.entities)[h];if(y!==void 0&&l==="add")continue;const g=y!==void 0&&l==="upsert"?{...y,...m}:m;u??(u={...i.entities}),u[h]=g,y===void 0&&(f??(f=[...i.ids]),f.push(h))}return u===null?i:n(i,u,f??i.ids)},o=(i,a)=>{let l=null;for(const{id:u,changes:f}of a){const m=(l??i.entities)[u];m!==void 0&&(l??(l={...i.entities}),l[u]={...m,...f})}return l===null?i:n(i,l,i.ids)},d=(i,a)=>{const l=new Set(a.filter(f=>i.entities[f]!==void 0));if(l.size===0)return i;const u={...i.entities};for(const f of l)delete u[f];return n(i,u,i.ids.filter(f=>!l.has(f)))};return{getInitialState(i){const a={ids:[],entities:{}};return i===void 0?a:{...a,...i}},addOne:(i,a)=>r(i,[a],"add"),addMany:(i,a)=>r(i,a,"add"),setOne:(i,a)=>r(i,[a],"set"),setMany:(i,a)=>r(i,a,"set"),setAll:(i,a)=>{const l={},u=[];for(const f of a){const m=e(f);l[m]===void 0&&u.push(m),l[m]=f}return n(i,l,u)},updateOne:(i,a)=>o(i,[a]),updateMany:(i,a)=>o(i,a),upsertOne:(i,a)=>r(i,[a],"upsert"),upsertMany:(i,a)=>r(i,a,"upsert"),removeOne:(i,a)=>d(i,[a]),removeMany:(i,a)=>d(i,a),removeAll:i=>i.ids.length===0?i:n(i,{},[]),selectIds:i=>i.ids,selectEntities:i=>i.entities,selectAll:i=>i.ids.map(a=>i.entities[a]),selectById:(i,a)=>i.entities[a],selectTotal:i=>i.ids.length,idsPath:"ids",pathTo:(i,a)=>a===void 0?`entities.${i}`:`entities.${i}.${a}`,anyField:i=>`entities.*.${i}`}}const w="$yoltra";function C(c,e={}){const t=e.maxNodes??1e5,s=e.sanitize,n=[],r=new Map;let o=0,d=!1;function i(l,u){if(s!==void 0&&(l=s(u,l)),o+=1,o>t)return d=!0,{[w]:"unsupported",kind:"truncated"};switch(typeof l){case"undefined":return{[w]:"undefined"};case"bigint":return{[w]:"bigint",value:l.toString()};case"number":return Number.isNaN(l)?{[w]:"nan"}:l===1/0?{[w]:"infinity",sign:1}:l===-1/0?{[w]:"infinity",sign:-1}:l;case"function":case"symbol":return n.push(u),{[w]:"unsupported",kind:typeof l};case"string":case"boolean":return l}if(l===null)return null;const f=l,m=r.get(f);if(m!==void 0)return{[w]:"ref",path:m};if(r.set(f,u),l instanceof Date)return{[w]:"date",iso:l.toISOString()};if(l instanceof RegExp)return{[w]:"regexp",source:l.source,flags:l.flags};if(l instanceof Error)return{[w]:"error",name:l.name,message:l.message};if(l instanceof Map){const y=[];let g=0;for(const[E,M]of l)y.push([i(E,`${u}/@k${g}`),i(M,`${u}/${g}`)]),g+=1;return{[w]:"map",entries:y}}if(l instanceof Set){const y=[];let g=0;for(const E of l)y.push(i(E,`${u}/${g}`)),g+=1;return{[w]:"set",values:y}}if(Array.isArray(l))return l.map((y,g)=>i(y,`${u}/${g}`));const h={};for(const[y,g]of Object.entries(l))h[y]=i(g,`${u}/${V(y)}`);return w in h?{[w]:"escaped",value:h}:h}return{value:i(c,""),report:{truncated:d,unsupported:n}}}function L(c){const e=new Map,t=[];function s(o,d){if(o===null||typeof o!="object")return o;if(Array.isArray(o)){const a=[];return e.set(d,a),o.forEach((l,u)=>{if(N(l)){t.push({target:a,key:u,path:l.path}),a[u]=void 0;return}a[u]=s(l,`${d}/${u}`)}),a}if(typeof o[w]=="string"){const a=o;switch(a[w]){case"undefined":return;case"nan":return Number.NaN;case"infinity":return a.sign===1?1/0:-1/0;case"bigint":return BigInt(a.value);case"date":return new Date(a.iso);case"regexp":return new RegExp(a.source,a.flags);case"error":{const l=new Error(a.message);return l.name=a.name,l}case"unsupported":return;case"ref":return;case"map":{const l=new Map;return e.set(d,l),a.entries.forEach(([u,f],m)=>{l.set(s(u,`${d}/@k${m}`),s(f,`${d}/${m}`))}),l}case"set":{const l=new Set;return e.set(d,l),a.values.forEach((u,f)=>l.add(s(u,`${d}/${f}`))),l}case"escaped":return n(a.value,d);default:return}}return n(o,d)}function n(o,d){const i={};e.set(d,i);for(const[a,l]of Object.entries(o)){const u=`${d}/${V(a)}`;if(N(l)){t.push({target:i,key:a,path:l.path}),i[a]=void 0;continue}i[a]=s(l,u)}return i}const r=s(c,"");e.set("",r);for(const{target:o,key:d,path:i}of t)o[d]=e.get(i);return r}function N(c){return c!==null&&typeof c=="object"&&c[w]==="ref"&&typeof c.path=="string"}function V(c){return c.replace(/~/g,"~0").replace(/\//g,"~1")}function fe(c,e,t={}){let s=t.maxNodes??1e5;for(let n=0;n<8;n+=1){const{value:r,report:o}=C(c,{...t,maxNodes:s});let d;try{d=JSON.stringify(r)?.length??0}catch{d=Number.POSITIVE_INFINITY}if(d<=e)return o.truncated?{value:r,truncated:!0,note:`State was too large to send in full; parts beyond ${s} nodes are omitted.`}:{value:r,truncated:!1};const i=Math.floor(s*e*.8/d);if(s=Math.max(1,Math.min(i,s-1)),s<=1&&n>0)break}return{value:{[w]:"unsupported",kind:"truncated"},truncated:!0,note:`State exceeds the ${e}-byte transport limit and could not be reduced to fit.`}}function v(c,e,t){c.onError?.(e,t)}async function he(c){const e={slices:{},restored:!1};let t;try{t=c.source??await c.adapter.read(c.key)}catch(n){return v(c,n,"read"),e}if(t==null||t==="")return e;let s;try{s=L(JSON.parse(t))}catch(n){return v(c,n,"decode"),e}if(s===null||typeof s!="object"||typeof s.version!="number")return v(c,new Error("persisted payload is not a recognisable envelope"),"decode"),e;if(s.version!==c.version){if(c.migrate===void 0)return v(c,new Error(`persisted state is version ${s.version}, this build expects ${c.version}, and no migrate was supplied`),"migrate"),e;try{const n=c.migrate(s.slices,s.version);return n===null?e:{slices:n,restored:!0}}catch(n){return v(c,n,"migrate"),e}}return{slices:s.slices??{},restored:!0}}function pe(c,e){if(!e.restored)return c;const t={};for(const[s,n]of Object.entries(c)){const r=e.slices[s];t[s]=r===void 0?n:{...n,state:r}}return t}function Q(c,e){const t=c??{},s=e.slices===void 0?t:Object.fromEntries(e.slices.filter(n=>n in t).map(n=>[n,t[n]]));return JSON.stringify(C({version:e.version,slices:s}).value)}function me(c,e){const t=e.throttleMs??250,s=e.slices;let n=null,r=!1;const o=()=>{if(r){r=!1;try{const a=e.adapter.write(e.key,Q(c.getState(),e));a instanceof Promise&&a.catch(l=>v(e,l,"write"))}catch(a){v(e,a,"write")}}},d=()=>{if(r=!0,t<=0){o();return}n===null&&(n=setTimeout(()=>{n=null,o()},t),n.unref?.())},i=c.instrument(a=>{if(s===void 0){d();return}(a.changedPaths??[]).some(u=>s.some(f=>u===f||u.startsWith(`${f}.`)))&&d()});return()=>{i(),n!==null&&(clearTimeout(n),n=null),o()}}function ye(c,e){return Q(c.getState(),e)}function ge(c){return{read:e=>c.getItem(e),write:(e,t)=>c.setItem(e,t),remove:e=>c.removeItem(e)}}function Ee(c){const e=new Map(Object.entries(c??{}));return{read:t=>e.get(t)??null,write:(t,s)=>{e.set(t,s)},remove:t=>{e.delete(t)}}}exports.CallAbortedError=I;exports.CallTimeoutError=U;exports.EventBus=B;exports.LooseEventBus=H;exports.Reducer=W;exports.Rejected=q;exports.Store=P;exports.createEntityAdapter=ue;exports.createMemoryAdapter=Ee;exports.createStore=oe;exports.createWebStorageAdapter=ge;exports.decodeState=L;exports.dehydrate=ye;exports.detectChangedProps=T;exports.encodeState=C;exports.encodeStateBounded=fe;exports.eventKeys=ae;exports.freezeState=k;exports.hydrate=he;exports.isRejected=F;exports.persist=me;exports.typedEvents=ce;exports.withHydration=pe;
|
|
4
|
+
* License: MIT */
|
|
5
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class H{handlers=new Map;on(e,t,s){let n=this.handlers.get(e);n||(n=new Map,this.handlers.set(e,n));let r=n.get(t);return r||(r=new Set,n.set(t,r)),r.add(s),()=>this.off(e,t,s)}off(e,t,s){const n=this.handlers.get(e);if(!n)return;const r=n.get(t);r&&(r.delete(s),r.size===0&&n.delete(t),n.size===0&&this.handlers.delete(e))}emit(e,t,s,n){const r=this.handlers.get(e);if(!r)return;const c=r.get(t);if(!(!c||c.size===0))for(const d of[...c])try{d(s,n)}catch(i){console.error("EventBus handler error:",i)}}clear(){this.handlers.clear()}}class K{handlers=new Map;patternHandlers=new Map;patternIndex=new Map;on(e,t,s){const n=String(t);if(this.isPattern(n)){const r=n;this.patternHandlers.has(e)||this.patternHandlers.set(e,new Map);const c=this.patternHandlers.get(e);return c.has(r)||(c.set(r,[]),this.indexPattern(e,r)),c.get(r).push(s),()=>this.offPattern(e,r,s)}else{const r=this.normalizeTypeKey(n);this.handlers.has(e)||this.handlers.set(e,new Map);const c=this.handlers.get(e);return c.has(r)||c.set(r,[]),c.get(r).push(s),()=>this.offExactNormalized(e,r,s)}}off(e,t,s){const n=this.normalizeTypeKey(String(t));this.offExactNormalized(e,n,s)}offExactNormalized(e,t,s){const n=this.handlers.get(e);if(!n)return;const r=n.get(t);if(!r)return;const c=r.indexOf(s);c!==-1&&r.splice(c,1),r.length===0&&n.delete(t),n.size===0&&this.handlers.delete(e)}offPattern(e,t,s){const n=this.patternHandlers.get(e);if(!n)return;const r=n.get(t);if(!r)return;const c=r.indexOf(s);c!==-1&&r.splice(c,1),r.length===0&&(n.delete(t),this.unindexPattern(e,t)),n.size===0&&(this.patternHandlers.delete(e),this.patternIndex.delete(e))}emit(e,t,s){const n=String(t),r=this.normalizeTypeKey(n),c=this.handlers.get(e)?.get(r)??[],d=this.matchingPatternHandlers(e,n),i=new Set,a=l=>{for(const u of[...l])if(!i.has(u)){i.add(u);try{u(s)}catch(h){console.error(h);continue}}};a(c);for(const l of d)a(l)}emitWith(e,t,s){const n=String(t),r=this.normalizeTypeKey(n),c=this.handlers.get(e)?.get(r)??[],d=this.matchingPatternHandlers(e,n);if(c.length===0&&d.length===0)return;const i=s(),a=new Set,l=u=>{for(const h of[...u])if(!a.has(h)){a.add(h);try{h(i)}catch(p){console.error(p);continue}}};l(c);for(const u of d)l(u)}isPattern(e){return e.includes("*")}normalizeTypeKey(e){return e.replace(/^\./,"")}splitPath(e){return this.normalizeTypeKey(e).split(".").filter(Boolean)}indexPattern(e,t){let s=this.patternIndex.get(e);s===void 0&&(s={byHead:new Map,anyHead:[]},this.patternIndex.set(e,s));const n=this.splitPath(t),r={pattern:t,segments:n},c=n[0];if(c===void 0||c==="*"||c==="**"){s.anyHead.push(r);return}const d=s.byHead.get(c);d===void 0?s.byHead.set(c,[r]):d.push(r)}unindexPattern(e,t){const s=this.patternIndex.get(e);if(s===void 0)return;const n=this.splitPath(t)[0],r=n===void 0||n==="*"||n==="**"?s.anyHead:s.byHead.get(n);if(r===void 0)return;const c=r.findIndex(d=>d.pattern===t);c!==-1&&r.splice(c,1),r.length===0&&r!==s.anyHead&&n!==void 0&&s.byHead.delete(n)}matchingPatternHandlers(e,t){const s=this.patternHandlers.get(e),n=this.patternIndex.get(e);if(s===void 0||s.size===0||n===void 0)return[];const r=this.splitPath(t),c=[],d=a=>{for(const l of a){if(!this.matchSegments(l.segments,r))continue;const u=s.get(l.pattern);u!==void 0&&c.push(u)}},i=r[0];if(i!==void 0){const a=n.byHead.get(i);a!==void 0&&d(a)}return d(n.anyHead),c}matchSegments(e,t){let s=0,n=0,r=-1,c=0;for(;n<t.length;)if(s<e.length&&(e[s]==="*"||e[s]===t[n]))s++,n++;else if(s<e.length&&e[s]==="**")r=s,c=n,s++;else if(r!==-1)s=r+1,n=++c;else return!1;for(;s<e.length&&e[s]==="**";)s++;return s===e.length}clear(){this.handlers.clear(),this.patternHandlers.clear(),this.patternIndex.clear()}__introspect(){const e=[];for(const[t,s]of this.handlers)for(const[n,r]of s)r.length>0&&e.push({channel:t,type:n,count:r.length});for(const[t,s]of this.patternHandlers)for(const[n,r]of s)r.length>0&&e.push({channel:t,type:n,count:r.length});return e}}class W{_reduce;constructor(e){this._reduce=e}reduce(e,t){return this._reduce(e,t)}}const D=new Set;function x(o,e){const t=o?`${o}.${e}`:e;D.has(t)||(D.add(t),console.warn(`[yoltra] State key "${e}"${o?` under "${o}"`:""} contains a dot. Paths are dotted, so this key is indistinguishable from nested objects of the same name: a subscription to "${t}" may match the wrong value, and DevTools patches for it will address the wrong node. Rename the key, or nest it.`))}function T(o,e,t="",s=new Map){const n=[];return R(o,e,t,s,n),n}function R(o,e,t,s,n){if(o===e)return;if(typeof o!="object"||typeof e!="object"||o===null||e===null){if(typeof o=="number"&&Number.isNaN(o)&&Number.isNaN(e))return;n.push(t);return}if(o instanceof Date&&e instanceof Date){o.getTime()!==e.getTime()&&n.push(t);return}if(o instanceof RegExp&&e instanceof RegExp){(o.source!==e.source||e.flags!==o.flags)&&n.push(t);return}if(o instanceof Map||e instanceof Map){n.push(t);return}if(o instanceof Set||e instanceof Set){n.push(t);return}const r=o,c=e,d=s.get(r);if(d?.has(c))return;const i=d??new Set;i.add(c),d||s.set(r,i);try{const a=Array.isArray(o),l=Array.isArray(e);if(a!==l){n.push(t);return}if(a){const f=o,m=e;f.length!==m.length&&t&&n.push(t);const y=Math.min(f.length,m.length);for(let g=0;g<y;g++)f[g]!==m[g]&&R(f[g],m[g],t?`${t}.${g}`:`${g}`,s,n);for(let g=y;g<Math.max(f.length,m.length);g++)n.push(t?`${t}.${g}`:`${g}`);return}const u=Object.keys(o),h=Object.keys(e);if(u.length===0&&h.length===0){n.push(t);return}let p=u.length===h.length;if(p){for(let f=0;f<h.length;f++)if(!Object.prototype.hasOwnProperty.call(o,h[f])){p=!1;break}}if(p){for(const f of h)o[f]!==e[f]&&(process.env.NODE_ENV!=="production"&&f.includes(".")&&x(t,f),R(o[f],e[f],t?`${t}.${f}`:f,s,n));return}for(const f of h){const m=Object.prototype.hasOwnProperty.call(o,f);if(m&&o[f]===e[f])continue;process.env.NODE_ENV!=="production"&&f.includes(".")&&x(t,f);const y=t?`${t}.${f}`:f;if(!m){n.push(y);continue}R(o[f],e[f],y,s,n)}for(const f of u)Object.prototype.hasOwnProperty.call(e,f)||(process.env.NODE_ENV!=="production"&&f.includes(".")&&x(t,f),n.push(t?`${t}.${f}`:f))}finally{i.delete(c),i.size===0&&s.delete(r)}}function $(o,e=new WeakSet,t){if(o===null||typeof o!="object"||e.has(o)||(t!==void 0&&o===t.watch&&t.onFound(),Object.isFrozen(o)))return o;if(e.add(o),Array.isArray(o)){const s=o;for(let n=0;n<s.length;n++)s[n]=$(s[n],e,t);return Object.freeze(s)}for(const s of Object.getOwnPropertyNames(o)){const n=Object.getOwnPropertyDescriptor(o,s);!n||!("value"in n)||(o[s]=$(o[s],e,t))}for(const s of Object.getOwnPropertySymbols(o)){const n=Object.getOwnPropertyDescriptor(o,s);!n||!("value"in n)||(o[s]=$(o[s],e,t))}return Object.freeze(o)}const F=Symbol.for("yoltra.rejected");function J(o){return{[F]:!0,reason:o}}function U(o){return typeof o=="object"&&o!==null&&o[F]===!0}class L extends Error{channel;type;idleMs;constructor(e,t,s){super(`[yoltra] call to "${e}/${t}" saw no correlated reply for ${s}ms. The timeout is idle rather than total, so this means the responder went quiet, not that it was slow. Check that something handles "${e}/${t}" and that its reply is emitted through the \`emit\` it was handed — a reply emitted from an unrelated context carries no causal link, and needs an explicit correlationId instead.`),this.name="CallTimeoutError",this.channel=e,this.type=t,this.idleMs=s}}class I extends Error{constructor(e){super(`[yoltra] call aborted: ${e}`),this.name="CallAbortedError"}}function q(o){const[e,t]=o;if(t===void 0)return{channel:e,isTerminal:()=>!0};if(typeof t=="string")return{channel:e,isTerminal:n=>n===t};const s=new Set(t);return{channel:e,isTerminal:n=>s.has(n)}}function Y(o,e,t){return o.parentId===e?!0:t===void 0?!1:o.meta?.correlationId===t}class X{constructor(e){this.highWaterMark=e}highWaterMark;buffer=[];takers=[];putters=[];consuming=!1;ended=!1;closed=!1;dropped=0;get droppedCount(){return this.dropped}beginConsuming(){this.consuming=!0}put(e){if(this.closed||this.ended)return Promise.resolve();const t=this.takers.shift();return t!==void 0?(t({value:e,done:!1}),Promise.resolve()):this.buffer.length<this.highWaterMark?(this.buffer.push(e),Promise.resolve()):this.consuming?new Promise(s=>{this.putters.push({item:e,release:s})}):(this.dropped++,Promise.resolve())}take(){this.consuming=!0;const e=this.buffer.shift();if(e!==void 0){const s=this.putters.shift();return s!==void 0&&(this.buffer.push(s.item),s.release()),Promise.resolve({value:e,done:!1})}const t=this.putters.shift();return t!==void 0?(t.release(),Promise.resolve({value:t.item,done:!1})):this.closed||this.ended?Promise.resolve({value:void 0,done:!0}):new Promise(s=>{this.takers.push(s)})}end(){if(this.ended||this.closed)return;this.ended=!0;let e=this.putters.shift();for(;e!==void 0;)this.buffer.push(e.item),e.release(),e=this.putters.shift();let t=this.takers.shift();for(;t!==void 0;){const s=this.buffer.shift();t(s!==void 0?{value:s,done:!1}:{value:void 0,done:!0}),t=this.takers.shift()}}close(){if(this.closed)return;this.closed=!0,this.buffer.length=0;let e=this.takers.shift();for(;e!==void 0;)e({value:void 0,done:!0}),e=this.takers.shift();let t=this.putters.shift();for(;t!==void 0;)t.release(),t=this.putters.shift()}}const Z=3e4,ee=16;function te(o,e,t,s,n){const{channel:r,isTerminal:c}=q(n.reply),d=n.timeoutMs??Z,i=new X(n.highWaterMark??ee),a=o.idFactory();let l,u,h=!1;const p=new Promise((b,v)=>{l=b,u=v});p.catch(()=>{});let f=null,m=null;const y=(b,v=!1)=>{h||(h=!0,f!==null&&clearTimeout(f),f=null,m?.(),m=null,v?i.end():i.close(),n.signal?.removeEventListener("abort",g),b())};function g(){y(()=>u(new I(String(n.signal?.reason??"signal aborted"))))}const P=()=>{f!==null&&clearTimeout(f),f=setTimeout(()=>{y(()=>u(new L(e,t,d)))},d),f.unref?.()};return m=o.registerEffect({when:{channel:r},effect:async b=>{if(!h&&Y(b,a,n.correlationId)){if(P(),c(String(b.type))){y(()=>l(b),!0);return}await i.put(b)}}}),n.signal!==void 0&&(n.signal.aborted?g():n.signal.addEventListener("abort",g,{once:!0})),P(),o.emit(e,t,s,{id:a,...n.correlationId!==void 0?{meta:{correlationId:n.correlationId}}:{}}),{then:(b,v)=>p.then(b,v),catch:b=>p.catch(b),finally:b=>p.finally(b),get dropped(){return i.droppedCount},cancel:(b="cancelled")=>{y(()=>u(new I(b)))},[Symbol.asyncIterator]:()=>(i.beginConsuming(),{next:()=>i.take(),return:async()=>(i.close(),{value:void 0,done:!0})})}}function ne(o,e){if(!e)return o;const s=(e[0]==="."?e.slice(1):e).split(".");let n=o;for(const r of s){if(n==null)return;n=n[r]}return n}function se(o){if(!o)return[];const t=(o[0]==="."?o.slice(1):o).split("."),s=[];for(let n=0;n<t.length;n++)s.push(t.slice(0,n+1).join("."));return s}function M(o,e){return!o||"any"in o&&o.any===!0?!0:"keys"in o?o.keys.some(([t,s])=>e.channel===t&&e.type===s):"channel"in o?e.channel===o.channel:"channels"in o?o.channels.includes(e.channel):!1}function re(o){return typeof o=="function"?o:o.middleware}function ie(o){if(typeof o!="function")return o.when}function A(o){if(o.when){const e=o.when;if("keys"in e)return e.keys}return[]}function oe(o,e){try{return structuredClone(e)}catch(t){throw new Error(`[yoltra] Initial state for slice "${String(o)}" could not be copied: ${t instanceof Error?t.message:String(t)}. State must be structured-cloneable — functions, class instances and DOM nodes are not. Keep behaviour out of state and store plain data.`)}}function O(o,e){return process.env.NODE_ENV==="production"?o:$(o,new WeakSet,e)}const j=100,ce=64,z=16,S=Object.freeze({committed:!1,written:!1}),ae=Object.freeze({committed:!0,written:!1}),de=Object.freeze({committed:!0,written:!0}),_=()=>typeof performance<"u"&&typeof performance.now=="function"?performance.now():Date.now();class k{name;middleware;reducers;state;reducerBus;connectorBus;listeners=new Set;effects=new Map;patternEffects=new Set;committedEventSubscribers=new Map;uncommittedEventSubscribers=new Map;writtenEventSubscribers=new Map;allEventSubscribers=new Map;sliceUnsubs=new Map;patternReducers=new Map;replayEnabled;idFactory;onEffectError;onReducerError;warnedPayloadAliases=new Set;reduceQueue=[];isReducing=!1;currentEvent=null;transitionsThisDrain=0;maxReduceDepth;maxTransitionsPerDrain;onCascade;onRejected;instrumentObservers=new Set;changedPathSink=null;stagingSink=null;stagedRejection=null;stagedRejectedBy="";inFlightEffects=0;processedEvents=new Map;dedupCount=0;effectMeta=new WeakMap;dedupConfig;eventCleanupTimer=null;constructor(e){if(this.name=e.name??"yoltra Store",this.reducerBus=new H,this.connectorBus=new K,this.middleware=[...e.middleware??[]],this.reducers={},this.state={},this.replayEnabled=e.devtools?.allowReplay??!1,this.idFactory=e.idFactory??(()=>crypto.randomUUID()),this.onEffectError=e.onEffectError,this.onReducerError=e.onReducerError,this.maxReduceDepth=e.maxReduceDepth??ce,this.maxTransitionsPerDrain=e.maxTransitionsPerDrain??1/0,this.onCascade=e.onCascade,this.onRejected=e.onRejected,this.dedupConfig={windowMs:e.dedupWindowMs??0,maxCacheSize:1e3},Object.entries(e.reducer).forEach(([t,s])=>{this.mountSlice(t,s,{preserveState:!1})}),e.effects?.length)for(const t of e.effects)this.registerEffect(t);this.dispose=this.dispose.bind(this),this.notifyEffects=this.notifyEffects.bind(this),this.__applyExternalState=this.__applyExternalState.bind(this),this.__replayEvents=this.__replayEvents.bind(this),this.__devtoolsIntrospect=this.__devtoolsIntrospect.bind(this),this.mountSlice=this.mountSlice.bind(this),this.unmountSlice=this.unmountSlice.bind(this),this.getAtPath=this.getAtPath.bind(this),this.emit=this.emit.bind(this),this.subscribe=this.subscribe.bind(this),this.connect=this.connect.bind(this),this.onEffect=this.onEffect.bind(this),this.onEvent=this.onEvent.bind(this),this.getState=this.getState.bind(this),this.registerEffect=this.registerEffect.bind(this),this.registerMiddleware=this.registerMiddleware.bind(this),this.registerReducer=this.registerReducer.bind(this),this.replaceMiddleware=this.replaceMiddleware.bind(this),this.replaceEffects=this.replaceEffects.bind(this),this.replaceReducers=this.replaceReducers.bind(this),this.hotReplace=this.hotReplace.bind(this)}dispose(){this.eventCleanupTimer&&(clearInterval(this.eventCleanupTimer),this.eventCleanupTimer=null),this.processedEvents.clear(),this.effects.clear(),this.patternEffects.clear(),this.effectMeta=new WeakMap,this.warnedPayloadAliases.clear(),this.listeners.clear(),this.committedEventSubscribers.clear(),this.uncommittedEventSubscribers.clear(),this.writtenEventSubscribers.clear(),this.allEventSubscribers.clear(),this.instrumentObservers.clear(),this.connectorBus.clear(),this.reducerBus.clear(),this.patternReducers.clear(),this.sliceUnsubs.clear(),this.changedPathSink=null}fingerprint(e,t,s){const n=`${e}::${t}`;try{if(s==null)return`${n}::null`;if(typeof s!="object")return`${n}::${String(s)}`;const r=JSON.stringify(s);return`${n}::${r}`}catch{return`${n}::${Date.now()}::${Math.random()}`}}shouldDedupe(e,t){const s=Date.now(),n=this.processedEvents.get(e);return n!==void 0&&s-n<t?(this.dedupCount++,!0):(this.processedEvents.set(e,s),this.ensureCleanupTimer(),this.processedEvents.size>this.dedupConfig.maxCacheSize&&this.pruneProcessedEvents(s),!1)}ensureCleanupTimer(){this.eventCleanupTimer===null&&(this.eventCleanupTimer=setInterval(()=>{this.pruneProcessedEvents(Date.now())},5e3),this.eventCleanupTimer.unref?.())}pruneProcessedEvents(e){const t=Math.max(this.dedupConfig.windowMs,j),s=e-t*2;for(const[n,r]of this.processedEvents)r<s&&this.processedEvents.delete(n);this.processedEvents.size===0&&this.eventCleanupTimer!==null&&(clearInterval(this.eventCleanupTimer),this.eventCleanupTimer=null)}reportCascade(e,t,s,n,r){console.error(`[yoltra] Cascade stopped: "${s.channel}/${s.type}" would exceed ${e} (${t}). This event was refused and the chain ends here. A chain this long is almost always two consumers emitting into each other — check what reacts to "${s.channel}/${s.type}" and what that emits in turn.`+(r.length>0?` Recent causal chain: ${r.join(" → ")} → (refused).`:""));try{this.onCascade?.({limit:e,limitValue:t,event:s,depth:n,chain:r})}catch(c){console.error("onCascade handler error:",c)}}async notifyEffects(e){const t=this.scopedEmit(e),s=`${String(e.channel)}::${String(e.type)}`,n=this.effects.get(s);if(n&&n.size>0)for(const r of[...n])try{await r(e,this.getState,t)}catch(c){console.error("Effect error:",c),this.onEffectError?.(c,e)}for(const{effect:r,when:c}of this.patternEffects)if(M(c,e))try{await r(e,this.getState,t)}catch(d){console.error("Effect error:",d),this.onEffectError?.(d,e)}}scopedEmit(e){const t={id:e.id,depth:e.depth??0,chain:[...this.currentEvent?.chain??[],e.id].slice(-z)};return((s,n,r,c)=>this.emitCaused(t,s,n,r,c))}notifyEventSubscribers(e,t){const s=`${String(e.channel)}::${String(e.type)}`,r=(t==="committed"?this.committedEventSubscribers:t==="written"?this.writtenEventSubscribers:this.uncommittedEventSubscribers).get(s);if(r?.size)for(const d of[...r])this.invokeEventSubscriber(d,e,t);if(t==="written")return;const c=this.allEventSubscribers.get(s);if(c?.size)for(const d of[...c])this.invokeEventSubscriber(d,e,t)}invokeEventSubscriber(e,t,s){try{const n=e(t,this.getState,this.emit,s);n&&typeof n.then=="function"&&n.catch(r=>console.error("Event subscription error:",r))}catch(n){console.error("Event subscription error:",n)}}stageSliceGuarded(e,t,s){try{return this.stageSlice(e,t,s)}catch(n){return console.error(`Reducer error in slice "${e}":`,n),this.onReducerError?.(n,t,e),null}}stageSlice(e,t,s){const n=this.state[e],r=this.reducers[e].reduce(n,t);if(U(r))return r;if(n===r)return null;const c=T(n,r);if(c.length===0)return null;const d=t.payload,i=process.env.NODE_ENV!=="production"&&d!==null&&typeof d=="object"?{watch:d,onFound:()=>{const a=`${e}:${t.channel}:${t.type}`;this.warnedPayloadAliases.has(a)||(this.warnedPayloadAliases.add(a),console.warn(`[yoltra] Slice "${e}" stored the payload of "${t.channel}/${t.type}" by reference. It is now frozen along with the rest of the state, so the emitter mutating it later will throw in development and silently corrupt state in production. Copy the payload in the reducer instead.`))}}:void 0;return s.push({name:e,prev:n,frozen:O(r,i),leafPaths:c}),null}commitStaged(e,t){if(e.length===0)return!1;const s={...this.state};for(const n of e)s[n.name]=n.frozen;if(this.state=s,this.changedPathSink)for(const n of e)for(const r of n.leafPaths)this.changedPathSink.push(r?`${n.name}.${r}`:n.name);for(const n of e){const r=new Set;for(const c of n.leafPaths){if(c===""){r.add("");continue}for(const d of k.buildAncestorPaths(c))r.add(d)}for(const c of r)this.connectorBus.emitWith(n.name,c,()=>({oldValue:this.getAtPath(n.prev,c),newValue:this.getAtPath(n.frozen,c),path:c,eventId:t.id,channel:t.channel,type:t.type}))}return!0}__devtoolsIntrospect(){const e=Object.keys(this.reducers).map(d=>{const i=this.patternReducers.get(d);return{name:d,when:i}}),t=[];for(const[d,i]of this.effects){if(i.size===0)continue;const[a,l]=d.split("::");for(const u of i){const h=this.effectMeta.get(u);t.push({channel:a,type:l,name:h?.name,description:h?.description})}}for(const d of this.patternEffects){const i=this.effectMeta.get(d.effect);t.push({channel:"*",type:"*",name:i?.name,description:i?.description})}const s=[];for(const d of this.middleware)typeof d=="function"?s.push({name:d.name||void 0}):s.push({name:d.meta?.name,description:d.meta?.description,when:d.when});const n=[];for(const d of this.connectorBus.__introspect())for(let i=0;i<d.count;i++)n.push({reducer:d.channel,property:d.type});const r=[];for(const[d,i]of this.committedEventSubscribers){if(i.size===0)continue;const[a,l]=d.split("::");for(let u=0;u<i.size;u++)r.push({channel:a,type:l,phase:"committed"})}for(const[d,i]of this.uncommittedEventSubscribers){if(i.size===0)continue;const[a,l]=d.split("::");for(let u=0;u<i.size;u++)r.push({channel:a,type:l,phase:"uncommitted"})}for(const[d,i]of this.allEventSubscribers){if(i.size===0)continue;const[a,l]=d.split("::");for(let u=0;u<i.size;u++)r.push({channel:a,type:l,phase:"all"})}const c=this.listeners.size;return{reducers:e,effects:t,middleware:s,atomic:n,event:r,coarse:c,dedupHits:this.dedupCount,queueDepth:this.reduceQueue.length+this.inFlightEffects}}__applyExternalState(e){if(!this.replayEnabled)throw new Error("[yoltra] External state apply (time-travel) is disabled. Enable it with createStore({ devtools: { allowReplay: true } })");const t=this.state,s=e,n={...this.state};let r=!1;Object.keys(this.reducers).forEach(c=>{const d=t?.[c],i=s?.[c];if(i===void 0){process.env.NODE_ENV!=="production"&&console.warn(`[yoltra] External state is missing slice "${String(c)}"; retaining its current value. Time-travel snapshots should contain all slices.`);return}if(d===i)return;const a=O(i);n[c]=a,r=!0;const l=T(d,i);if(l.length===0)return;const u=new Set;for(const h of l){if(h===""){u.add("");continue}for(const p of k.buildAncestorPaths(h))u.add(p)}for(const h of u){const p=this.getAtPath(d,h),f=this.getAtPath(a,h);this.connectorBus.emit(c,h,{oldValue:p,newValue:f,path:h})}}),r&&(this.state=n),r&&this.listeners.forEach(c=>c())}__replayEvents(e,t){if(!this.replayEnabled)throw new Error("[yoltra] Event replay is disabled. Enable it with createStore({ devtools: { allowReplay: true } })");this.__applyExternalState(e);for(const s of t){const n=s,r=[];this.stagingSink=r;let c=null;try{this.reducerBus.emit(n.channel,n.type,n.payload,n),c=this.stagedRejection;for(const[i,a]of this.patternReducers){if(c!==null)break;if(M(a,n)){const l=this.stageSliceGuarded(i,n,r);l!==null&&(c=l)}}}finally{this.stagingSink=null,this.stagedRejection=null,this.stagedRejectedBy=""}const d=c===null&&this.commitStaged(r,n);this.notifyEventSubscribers(n,"committed"),d&&(this.notifyEventSubscribers(n,"written"),this.listeners.forEach(i=>i()))}}async emit(e,t,s,n){return this.emitCaused(null,e,t,s,n)}async emitCaused(e,t,s,n,r){const c=r?.dedupKey,d=this.dedupConfig.windowMs;if(r?.skipDedup!==!0&&(d>0||c!==void 0)){const p=c!==void 0&&d<=0?j:d,f=c!==void 0?`${t}::${s}::#${c}`:this.fingerprint(t,s,n);if(this.shouldDedupe(f,p))return S}const i=r?.id??this.idFactory(),a=this.currentEvent??e,l=a===null?0:a.depth+1;if(a!==null&&l>this.maxReduceDepth)return this.reportCascade("maxReduceDepth",this.maxReduceDepth,{channel:t,type:s,payload:n,id:i,...r?.meta!==void 0?{meta:r.meta}:{},parentId:a.id,depth:l},l,a.chain),S;let u;const h=new Promise(p=>{u=p});return this.reduceQueue.push({channel:t,type:s,payload:n,id:i,meta:r?.meta,resolve:u,...a!==null?{parentId:a.id,depth:l,chain:a.chain}:{}}),this.drainReduce(),h}drainReduce(){if(!this.isReducing){this.isReducing=!0,this.transitionsThisDrain=0;try{for(;this.reduceQueue.length>0;){const e=this.reduceQueue.shift(),{channel:t,type:s,payload:n,id:r,meta:c,resolve:d,parentId:i,depth:a,chain:l}=e,u={channel:t,type:s,payload:n,id:r,...c!==void 0?{meta:c}:{},...i!==void 0?{parentId:i,depth:a}:{}};if(i!==void 0&&++this.transitionsThisDrain>this.maxTransitionsPerDrain){this.reportCascade("maxTransitionsPerDrain",this.maxTransitionsPerDrain,u,a,l),d(S);continue}this.currentEvent={id:r,depth:a??0,chain:[...l??[],r].slice(-z)};const h=this.instrumentObservers.size>0,p=h?this.state:void 0,f=h?[]:void 0;f!==void 0&&(this.changedPathSink=f);const m=h?_():0;let y=S;try{y=this.applyEventSync(u)}catch(g){console.error("Emit reduce error:",g)}finally{h&&(this.changedPathSink=null),this.currentEvent=null}h&&this.emitInstrumentation(u,y,f??[],p,_()-m),this.runEventEffects(u,y,d)}}finally{this.isReducing=!1}}}applyEventSync(e){for(const c of this.middleware){const d=ie(c);if(!M(d,e))continue;const i=re(c);let a;try{a=i(this.state,e,this.emit),process.env.NODE_ENV!=="production"&&typeof a?.then=="function"&&console.error(`[yoltra] Middleware for "${e.channel}/${e.type}" returned a Promise. Middleware is synchronous: a Promise is truthy, so this event was allowed without waiting and a "return false" inside it can never veto. Do the check synchronously, and put anything that must await in an effect.`)}catch(l){console.error("Middleware error:",l),a=!1}if(!a)return this.notifyEventSubscribers(e,"uncommitted"),S}const t=[];this.stagingSink=t;let s=null,n="";try{this.reducerBus.emit(e.channel,e.type,e.payload,e),s=this.stagedRejection,n=this.stagedRejectedBy;for(const[c,d]of this.patternReducers){if(s!==null)break;if(M(d,e)){const i=this.stageSliceGuarded(c,e,t);i!==null&&(s=i,n=c)}}}finally{this.stagingSink=null,this.stagedRejection=null,this.stagedRejectedBy=""}if(s!==null)return this.onRejected?.(s,e,n),this.notifyEventSubscribers(e,"committed"),{committed:!0,written:!1,rejected:s};const r=this.commitStaged(t,e);return this.notifyEventSubscribers(e,"committed"),r&&(this.notifyEventSubscribers(e,"written"),this.listeners.forEach(c=>c())),r?de:ae}async runEventEffects(e,t,s){this.inFlightEffects++;try{t.committed&&await this.notifyEffects(e)}catch(n){console.error("Effect error:",n)}finally{this.inFlightEffects--,s(t)}}instrument(e){return this.instrumentObservers.add(e),()=>{this.instrumentObservers.delete(e)}}emitInstrumentation(e,t,s,n,r){const c={},d={};for(const a of s)c[a]=this.getAtPath(n,a),d[a]=this.getAtPath(this.state,a);const i={event:{id:e.id,channel:e.channel,type:e.type,payload:e.payload,...e.meta!==void 0?{meta:e.meta}:{}},committed:t.committed,changedPaths:s,prevValues:c,nextValues:d,reduceTimeMs:r,...t.rejected!==void 0?{rejected:t.rejected}:{}};for(const a of[...this.instrumentObservers])try{a(i)}catch(l){console.error("Instrumentation observer error:",l)}}connect(e,t,s){const n=this.connectorBus.on(e.reducer,e.property,t);if(s?.immediate===!0){const r=this.state[e.reducer],c=e.property.includes("*")?"":e.property;t({oldValue:void 0,newValue:this.getAtPath(r,c),path:c})}return n}onEvent(e,t,s,n="committed"){const r=`${e}::${String(t)}`,c=n==="committed"?this.committedEventSubscribers:n==="uncommitted"?this.uncommittedEventSubscribers:n==="written"?this.writtenEventSubscribers:this.allEventSubscribers;return c.has(r)||c.set(r,new Set),c.get(r).add(s),()=>{const d=c.get(r);d&&(d.delete(s),d.size===0&&c.delete(r))}}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}getState(){return this.state}registerMiddleware(e){return this.middleware.push(e),()=>{const t=this.middleware.indexOf(e);t!==-1&&this.middleware.splice(t,1)}}registerReducer(e,t){if(Object.prototype.hasOwnProperty.call(this.reducers,e))throw new Error(`Reducer ${e} already exists`);return this.mountSlice(e,t,{preserveState:!1}),this.listeners.forEach(s=>s()),()=>{this.unmountSlice(e,{deleteState:!0}),this.listeners.forEach(s=>s())}}call(e,t,s,n){return te({idFactory:this.idFactory,registerEffect:this.registerEffect,emit:this.emit},e,t,s,n)}registerEffect(e){const{effect:t,meta:s,when:n}=e,r=[];if(s&&this.effectMeta.set(t,s),n&&("any"in n&&n.any===!0||"channel"in n||"channels"in n)){const i={effect:t,when:n};return this.patternEffects.add(i),()=>{this.patternEffects.delete(i)}}const d=A(e);if(d.length===0&&!n){const i={effect:t,when:{any:!0}};return this.patternEffects.add(i),()=>{this.patternEffects.delete(i)}}for(const[i,a]of d){const l=`${String(i)}::${String(a)}`;this.effects.has(l)||this.effects.set(l,new Set),this.effects.get(l).add(t),r.push(()=>{const u=this.effects.get(l);u&&(u.delete(t),u.size===0&&this.effects.delete(l))})}return()=>{for(const i of r)i()}}onEffect(e,t,s){const n=async(r,c,d)=>{if(r.channel!==e||r.type!==t)return;const i=r;return s(i.payload,c,d,i)};return this.registerEffect({when:{keys:[[e,t]]},effect:n})}replaceMiddleware(e){this.middleware.length=0;for(const t of e)this.middleware.push(t)}replaceEffects(e){this.effects.clear(),this.patternEffects.clear();for(const t of e)this.registerEffect(t)}replaceReducers(e,t={}){const s=t.preserveState!==!1,n=new Set(Object.keys(this.reducers)),r=Object.entries(e),c=new Set(r.map(([d])=>d));for(const d of n)c.has(d)||this.unmountSlice(d,{deleteState:!0});for(const[d,i]of r)n.has(d)?(this.unmountSlice(d,{deleteState:!1}),this.mountSlice(d,i,{preserveState:s})):this.mountSlice(d,i,{preserveState:!1})}hotReplace(e){e.middleware&&this.replaceMiddleware(e.middleware),e.effects&&this.replaceEffects(e.effects),e.reducer&&this.replaceReducers(e.reducer,{preserveState:e.preserveState})}mountSlice(e,t,s){const n=e,{reducer:r,state:c,when:d}=t;if(this.reducers[e]=new W(r),(!s.preserveState||this.state[n]===void 0)&&(this.state={...this.state,[n]:O(oe(n,c))}),d&&("any"in d&&d.any===!0||"channel"in d||"channels"in d)){this.patternReducers.set(e,d),this.sliceUnsubs.set(n,[]);return}const a=A(t);if(a.length===0&&!d){this.patternReducers.set(e,{any:!0}),this.sliceUnsubs.set(n,[]);return}const l=[];for(const[u,h]of a){const p=this.reducerBus.on(u,h,(f,m)=>{const y=m??{channel:u,type:h,payload:f,id:this.idFactory()};if(this.stagingSink===null)return;const g=this.stageSliceGuarded(e,y,this.stagingSink);g!==null&&this.stagedRejection===null&&(this.stagedRejection=g,this.stagedRejectedBy=e)});l.push(p)}this.sliceUnsubs.set(n,l)}unmountSlice(e,t){const s=e;this.patternReducers.delete(e);const n=this.sliceUnsubs.get(s);if(n){for(const r of n)try{r()}catch(c){console.error(`[Store error]: ${c}`)}this.sliceUnsubs.delete(s)}if(delete this.reducers[e],t.deleteState){const{[s]:r,...c}=this.state;this.state=c}}getAtPath(e,t){return ne(e,t)}static buildAncestorPaths(e){return se(e)}}function le(o){return new k({...o,reducer:o.reducer??{},middleware:o.middleware??[],effects:o.effects??[]})}const ue=o=>(e,t)=>t.map(s=>[e,s]),fe=()=>o=>o,N=new Set;function he(o){const e=String(o);N.has(e)||(N.add(e),console.warn(`[yoltra] Entity id "${e}" contains a dot. Paths are dotted, so a subscription to "entities.${e}" is indistinguishable from one to a nested object of the same name. Use ids without dots.`))}function pe(o,e){if(o.length!==e.length)return e;for(let t=0;t<o.length;t++)if(o[t]!==e[t])return e;return o}function me(o={}){const e=o.selectId??(i=>i.id),{sortComparer:t}=o,s=(i,a)=>{if(t===void 0)return a;const l=[...a].sort((u,h)=>{const p=i.entities[u],f=i.entities[h];return p===void 0||f===void 0?0:t(p,f)});return pe(a,l)},n=(i,a,l)=>{const u={...i,entities:a,ids:l};return{...u,ids:s(u,l)}},r=(i,a,l)=>{let u=null,h=null;for(const p of a){const f=e(p);process.env.NODE_ENV!=="production"&&String(f).includes(".")&&he(f);const m=(u??i.entities)[f];if(m!==void 0&&l==="add")continue;const y=m!==void 0&&l==="upsert"?{...m,...p}:p;u??={...i.entities},u[f]=y,m===void 0&&(h??=[...i.ids],h.push(f))}return u===null?i:n(i,u,h??i.ids)},c=(i,a)=>{let l=null;for(const{id:u,changes:h}of a){const p=(l??i.entities)[u];p!==void 0&&(l??={...i.entities},l[u]={...p,...h})}return l===null?i:n(i,l,i.ids)},d=(i,a)=>{const l=new Set(a.filter(h=>i.entities[h]!==void 0));if(l.size===0)return i;const u={...i.entities};for(const h of l)delete u[h];return n(i,u,i.ids.filter(h=>!l.has(h)))};return{getInitialState(i){const a={ids:[],entities:{}};return i===void 0?a:{...a,...i}},addOne:(i,a)=>r(i,[a],"add"),addMany:(i,a)=>r(i,a,"add"),setOne:(i,a)=>r(i,[a],"set"),setMany:(i,a)=>r(i,a,"set"),setAll:(i,a)=>{const l={},u=[];for(const h of a){const p=e(h);l[p]===void 0&&u.push(p),l[p]=h}return n(i,l,u)},updateOne:(i,a)=>c(i,[a]),updateMany:(i,a)=>c(i,a),upsertOne:(i,a)=>r(i,[a],"upsert"),upsertMany:(i,a)=>r(i,a,"upsert"),removeOne:(i,a)=>d(i,[a]),removeMany:(i,a)=>d(i,a),removeAll:i=>i.ids.length===0?i:n(i,{},[]),selectIds:i=>i.ids,selectEntities:i=>i.entities,selectAll:i=>i.ids.map(a=>i.entities[a]),selectById:(i,a)=>i.entities[a],selectTotal:i=>i.ids.length,idsPath:"ids",pathTo:(i,a)=>a===void 0?`entities.${i}`:`entities.${i}.${a}`,anyField:i=>`entities.*.${i}`}}const E="$yoltra";function C(o,e={}){const t=e.maxNodes??1e5,s=e.sanitize,n=[],r=new Map;let c=0,d=!1;function i(l,u){if(s!==void 0&&(l=s(u,l)),c+=1,c>t)return d=!0,{[E]:"unsupported",kind:"truncated"};switch(typeof l){case"undefined":return{[E]:"undefined"};case"bigint":return{[E]:"bigint",value:l.toString()};case"number":return Number.isNaN(l)?{[E]:"nan"}:l===1/0?{[E]:"infinity",sign:1}:l===-1/0?{[E]:"infinity",sign:-1}:l;case"function":case"symbol":return n.push(u),{[E]:"unsupported",kind:typeof l};case"string":case"boolean":return l}if(l===null)return null;const h=l,p=r.get(h);if(p!==void 0)return{[E]:"ref",path:p};if(r.set(h,u),l instanceof Date)return{[E]:"date",iso:l.toISOString()};if(l instanceof RegExp)return{[E]:"regexp",source:l.source,flags:l.flags};if(l instanceof Error)return{[E]:"error",name:l.name,message:l.message};if(l instanceof Map){const m=[];let y=0;for(const[g,P]of l)m.push([i(g,`${u}/@k${y}`),i(P,`${u}/${y}`)]),y+=1;return{[E]:"map",entries:m}}if(l instanceof Set){const m=[];let y=0;for(const g of l)m.push(i(g,`${u}/${y}`)),y+=1;return{[E]:"set",values:m}}if(Array.isArray(l))return l.map((m,y)=>i(m,`${u}/${y}`));const f={};for(const[m,y]of Object.entries(l))f[m]=i(y,`${u}/${Q(m)}`);return E in f?{[E]:"escaped",value:f}:f}return{value:i(o,""),report:{truncated:d,unsupported:n}}}function V(o){const e=new Map,t=[];function s(c,d){if(c===null||typeof c!="object")return c;if(Array.isArray(c)){const a=[];return e.set(d,a),c.forEach((l,u)=>{if(B(l)){t.push({target:a,key:u,path:l.path}),a[u]=void 0;return}a[u]=s(l,`${d}/${u}`)}),a}if(typeof c[E]=="string"){const a=c;switch(a[E]){case"undefined":return;case"nan":return Number.NaN;case"infinity":return a.sign===1?1/0:-1/0;case"bigint":return BigInt(a.value);case"date":return new Date(a.iso);case"regexp":return new RegExp(a.source,a.flags);case"error":{const l=new Error(a.message);return l.name=a.name,l}case"unsupported":return;case"ref":return;case"map":{const l=new Map;return e.set(d,l),a.entries.forEach(([u,h],p)=>{l.set(s(u,`${d}/@k${p}`),s(h,`${d}/${p}`))}),l}case"set":{const l=new Set;return e.set(d,l),a.values.forEach((u,h)=>l.add(s(u,`${d}/${h}`))),l}case"escaped":return n(a.value,d);default:return}}return n(c,d)}function n(c,d){const i={};e.set(d,i);for(const[a,l]of Object.entries(c)){const u=`${d}/${Q(a)}`;if(B(l)){t.push({target:i,key:a,path:l.path}),i[a]=void 0;continue}i[a]=s(l,u)}return i}const r=s(o,"");e.set("",r);for(const{target:c,key:d,path:i}of t)c[d]=e.get(i);return r}function B(o){return o!==null&&typeof o=="object"&&o[E]==="ref"&&typeof o.path=="string"}function Q(o){return o.replace(/~/g,"~0").replace(/\//g,"~1")}function ye(o,e,t={}){let s=t.maxNodes??1e5;for(let n=0;n<8;n+=1){const{value:r,report:c}=C(o,{...t,maxNodes:s});let d;try{d=JSON.stringify(r)?.length??0}catch{d=Number.POSITIVE_INFINITY}if(d<=e)return c.truncated?{value:r,truncated:!0,note:`State was too large to send in full; parts beyond ${s} nodes are omitted.`}:{value:r,truncated:!1};const i=Math.floor(s*e*.8/d);if(s=Math.max(1,Math.min(i,s-1)),s<=1&&n>0)break}return{value:{[E]:"unsupported",kind:"truncated"},truncated:!0,note:`State exceeds the ${e}-byte transport limit and could not be reduced to fit.`}}function w(o,e,t){o.onError?.(e,t)}async function ge(o){const e={slices:{},restored:!1};let t;try{t=o.source??await o.adapter.read(o.key)}catch(n){return w(o,n,"read"),e}if(t==null||t==="")return e;let s;try{s=V(JSON.parse(t))}catch(n){return w(o,n,"decode"),e}if(s===null||typeof s!="object"||typeof s.version!="number")return w(o,new Error("persisted payload is not a recognisable envelope"),"decode"),e;if(s.version!==o.version){if(o.migrate===void 0)return w(o,new Error(`persisted state is version ${s.version}, this build expects ${o.version}, and no migrate was supplied`),"migrate"),e;try{const n=o.migrate(s.slices,s.version);return n===null?e:{slices:n,restored:!0}}catch(n){return w(o,n,"migrate"),e}}return{slices:s.slices??{},restored:!0}}function Ee(o,e){if(!e.restored)return o;const t={};for(const[s,n]of Object.entries(o)){const r=e.slices[s];t[s]=r===void 0?n:{...n,state:r}}return t}function G(o,e){const t=o??{},s=e.slices===void 0?t:Object.fromEntries(e.slices.filter(n=>n in t).map(n=>[n,t[n]]));return JSON.stringify(C({version:e.version,slices:s}).value)}function be(o,e){const t=e.throttleMs??250,s=e.slices;let n=null,r=!1;const c=()=>{if(r){r=!1;try{const a=e.adapter.write(e.key,G(o.getState(),e));a instanceof Promise&&a.catch(l=>w(e,l,"write"))}catch(a){w(e,a,"write")}}},d=()=>{if(r=!0,t<=0){c();return}n===null&&(n=setTimeout(()=>{n=null,c()},t),n.unref?.())},i=o.instrument(a=>{if(s===void 0){d();return}(a.changedPaths??[]).some(u=>s.some(h=>u===h||u.startsWith(`${h}.`)))&&d()});return()=>{i(),n!==null&&(clearTimeout(n),n=null),c()}}function we(o,e){return G(o.getState(),e)}function ve(o){return{read:e=>o.getItem(e),write:(e,t)=>o.setItem(e,t),remove:e=>o.removeItem(e)}}function Se(o){const e=new Map(Object.entries(o??{}));return{read:t=>e.get(t)??null,write:(t,s)=>{e.set(t,s)},remove:t=>{e.delete(t)}}}exports.CallAbortedError=I;exports.CallTimeoutError=L;exports.EventBus=H;exports.LooseEventBus=K;exports.Reducer=W;exports.Rejected=J;exports.Store=k;exports.createEntityAdapter=me;exports.createMemoryAdapter=Se;exports.createStore=le;exports.createWebStorageAdapter=ve;exports.decodeState=V;exports.dehydrate=we;exports.detectChangedProps=T;exports.encodeState=C;exports.encodeStateBounded=ye;exports.eventKeys=fe;exports.freezeState=$;exports.hydrate=ge;exports.isRejected=U;exports.persist=be;exports.typedEvents=ue;exports.withHydration=Ee;
|
|
11
6
|
//# sourceMappingURL=yoltra.cjs.map
|