mvc-kit 2.5.0 → 2.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -26,7 +26,7 @@ npx mvc-kit-setup cursor # Cursor only
26
26
  npx mvc-kit-setup copilot # GitHub Copilot only
27
27
  ```
28
28
 
29
- **Claude Code** — installs `.claude/rules/` and `.claude/commands/`. Auto-updates on subsequent `npm install`/`npm update`.
29
+ **Claude Code** — installs `.claude/rules/`, `.claude/commands/`, and `.claude/agents/`. Auto-updates on subsequent `npm install`/`npm update`.
30
30
 
31
31
  **Cursor** — writes `.cursorrules`. **Copilot** — writes `.github/copilot-instructions.md`. Both use idempotent markers, safe to re-run.
32
32
 
@@ -88,6 +88,7 @@ function setupClaude() {
88
88
  }
89
89
  console.log('');
90
90
  console.log(' Commands: /project:mvc-kit-scaffold, /project:mvc-kit-review');
91
+ console.log(' Agent: mvc-kit-architect (architecture planning)');
91
92
  console.log(' Reference: Auto-loaded via .claude/rules/mvc-kit.md\n');
92
93
  }
93
94
 
@@ -5,6 +5,7 @@ import { fileURLToPath } from 'node:url';
5
5
  const __filename = fileURLToPath(import.meta.url);
6
6
  const __dirname = dirname(__filename);
7
7
  const SKILLS_DIR = join(__dirname, '..', 'claude-code', 'skills');
8
+ const AGENTS_DIR = join(__dirname, '..', 'claude-code', 'agents');
8
9
 
9
10
  const AUTO_HEADER = '<!-- Auto-generated by mvc-kit. Updated on npm install/update. Do not edit. -->\n\n';
10
11
 
@@ -26,6 +27,7 @@ function ensureDir(dir) {
26
27
  * .claude/rules/mvc-kit.md — Framework reference (always loaded in context)
27
28
  * .claude/commands/mvc-kit-scaffold.md — Scaffold command (/project:mvc-kit-scaffold)
28
29
  * .claude/commands/mvc-kit-review.md — Review command (/project:mvc-kit-review)
30
+ * .claude/agents/mvc-kit-architect.md — Architecture planning agent
29
31
  *
30
32
  * @param {string} projectRoot — Absolute path to the consuming project's root
31
33
  * @returns {{ files: string[] }} — List of created/updated file paths (relative to projectRoot)
@@ -34,9 +36,11 @@ export function installClaude(projectRoot) {
34
36
  const claudeDir = join(projectRoot, '.claude');
35
37
  const rulesDir = join(claudeDir, 'rules');
36
38
  const commandsDir = join(claudeDir, 'commands');
39
+ const agentsDir = join(claudeDir, 'agents');
37
40
 
38
41
  ensureDir(rulesDir);
39
42
  ensureDir(commandsDir);
43
+ ensureDir(agentsDir);
40
44
 
41
45
  const files = [];
42
46
 
@@ -83,5 +87,10 @@ For complete API details, patterns, and anti-patterns, read the files in:
83
87
  writeFileSync(join(commandsDir, 'mvc-kit-review.md'), AUTO_HEADER + reviewBody, 'utf-8');
84
88
  files.push('.claude/commands/mvc-kit-review.md');
85
89
 
90
+ // 4. Architect agent
91
+ const architectAgent = readFileSync(join(AGENTS_DIR, 'mvc-kit-architect.md'), 'utf-8');
92
+ writeFileSync(join(agentsDir, 'mvc-kit-architect.md'), AUTO_HEADER + architectAgent, 'utf-8');
93
+ files.push('.claude/agents/mvc-kit-architect.md');
94
+
86
95
  return { files };
87
96
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ViewModel.d.ts","sourceRoot":"","sources":["../src/ViewModel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ViewModel.d.ts","sourceRoot":"","sources":["../src/ViewModel.ts"],"names":[],"mappings":"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"}
package/dist/mvc-kit.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const b=require("./singleton-L-u2W_lX.cjs"),w=require("./PersistentCollection-B8kNECDj.cjs");class z extends Error{constructor(t,s){super(s??`HTTP ${t}`),this.status=t,this.name="HttpError"}}function m(r){return r instanceof Error&&r.name==="AbortError"}function T(r){return r===401?"unauthorized":r===403?"forbidden":r===404?"not_found":r===422?"validation":r===429?"rate_limited":r>=500?"server_error":"unknown"}function x(r){return typeof r=="object"&&r!==null&&typeof r.status=="number"&&typeof r.statusText=="string"&&!(r instanceof Error)}function O(r){return r instanceof Error&&r.name==="AbortError"?{code:"abort",message:"Request was aborted",original:r}:r instanceof z?{code:T(r.status),message:r.message,status:r.status,original:r}:x(r)?{code:T(r.status),message:r.statusText||`HTTP ${r.status}`,status:r.status,original:r}:r instanceof TypeError&&r.message.toLowerCase().includes("fetch")?{code:"network",message:r.message,original:r}:r instanceof Error&&r.name==="TimeoutError"?{code:"timeout",message:r.message,original:r}:r instanceof Error?{code:"unknown",message:r.message,original:r}:{code:"unknown",message:String(r),original:r}}const d=typeof __MVC_KIT_DEV__<"u"&&__MVC_KIT_DEV__;function M(r){return r!==null&&typeof r=="object"&&typeof r.subscribe=="function"}function S(r,t,s){let e=Object.getPrototypeOf(r);for(;e&&e!==t;){const n=Object.getOwnPropertyDescriptors(e);for(const[o,c]of Object.entries(n))o!=="constructor"&&s(o,c,e);e=Object.getPrototypeOf(e)}}const j=Object.freeze({loading:!1,error:null,errorCode:null}),E=["async","subscribeAsync"],P=new Set(["onInit","onSet","onDispose"]);class y{_state;_initialState;_disposed=!1;_initialized=!1;_listeners=new Set;_abortController=null;_cleanups=null;_subscriptionCleanups=null;_eventBus=null;_revision=0;_stateTracking=null;_sourceTracking=null;_trackedSources=new Map;_asyncStates=new Map;_asyncSnapshots=new Map;_asyncListeners=new Set;_asyncProxy=null;_activeOps=null;static GHOST_TIMEOUT=3e3;constructor(t){this._state=Object.freeze({...t}),this._initialState=this._state,this._guardReservedKeys()}get state(){return this._state}get disposed(){return this._disposed}get initialized(){return this._initialized}get disposeSignal(){return this._abortController||(this._abortController=new AbortController),this._abortController.signal}get events(){return this._eventBus||(this._eventBus=new b.EventBus),this._eventBus}init(){if(!(this._initialized||this._disposed))return this._initialized=!0,this._trackSubscribables(),this._installStateProxy(),this._memoizeGetters(),this._wrapMethods(),this.onInit?.()}set(t){if(this._disposed)return;if(d&&this._stateTracking){console.error("[mvc-kit] set() called inside a getter. Getters must be pure — they read state and return a value. They must never call set(), which would cause an infinite render loop. Move this logic to an action method.");return}const s=typeof t=="function"?t(this._state):t;if(!Object.keys(s).some(l=>s[l]!==this._state[l]))return;const o=this._state,c=Object.freeze({...o,...s});this._state=c,this._revision++,this.onSet?.(o,c);for(const l of this._listeners)l(c,o)}emit(t,s){(this._eventBus?.disposed??this._disposed)||this.events.emit(t,s)}subscribe(t){return this._disposed?()=>{}:(this._listeners.add(t),()=>{this._listeners.delete(t)})}dispose(){if(!this._disposed){if(this._disposed=!0,this._teardownSubscriptions(),this._abortController?.abort(),this._cleanups){for(const t of this._cleanups)t();this._cleanups=null}this._eventBus?.dispose(),this.onDispose?.(),this._listeners.clear()}}reset(t){if(!this._disposed){this._abortController?.abort(),this._abortController=null,this._teardownSubscriptions(),this._state=t?Object.freeze({...t}):this._initialState,this._revision++,this._asyncStates.clear(),this._asyncSnapshots.clear(),this._notifyAsync(),this._trackSubscribables();for(const s of this._listeners)s(this._state,this._state);return this.onInit?.()}}addCleanup(t){this._cleanups||(this._cleanups=[]),this._cleanups.push(t)}subscribeTo(t,s){const e=t.subscribe(s);return this._subscriptionCleanups||(this._subscriptionCleanups=[]),this._subscriptionCleanups.push(e),e}get async(){if(!this._asyncProxy){const t=this;this._asyncProxy=new Proxy({},{get(s,e){return t._asyncSnapshots.get(e)??j},has(s,e){return t._asyncSnapshots.has(e)},ownKeys(){return Array.from(t._asyncSnapshots.keys())},getOwnPropertyDescriptor(s,e){if(t._asyncSnapshots.has(e))return{configurable:!0,enumerable:!0,value:t._asyncSnapshots.get(e)}}})}return this._asyncProxy}subscribeAsync(t){return this._disposed?()=>{}:(this._asyncListeners.add(t),()=>{this._asyncListeners.delete(t)})}_notifyAsync(){for(const t of this._asyncListeners)t()}_teardownSubscriptions(){for(const t of this._trackedSources.values())t.unsubscribe();if(this._trackedSources.clear(),this._subscriptionCleanups){for(const t of this._subscriptionCleanups)t();this._subscriptionCleanups=null}}_guardReservedKeys(){S(this,y.prototype,t=>{if(E.includes(t))throw new Error(`[mvc-kit] "${t}" is a reserved property on ViewModel and cannot be overridden.`)})}_wrapMethods(){for(const n of E)if(Object.getOwnPropertyDescriptor(this,n)?.value!==void 0)throw new Error(`[mvc-kit] "${n}" is a reserved property on ViewModel and cannot be overridden.`);const t=this,s=new Set,e=[];d&&(this._activeOps=new Map),S(this,y.prototype,(n,o)=>{if(o.get||o.set||typeof o.value!="function"||n.startsWith("_")||P.has(n)||s.has(n))return;s.add(n);const c=o.value;let l=!1;const p=function(...g){if(t._disposed){d&&console.warn(`[mvc-kit] "${n}" called after dispose — ignored.`);return}d&&!t._initialized&&console.warn(`[mvc-kit] "${n}" called before init(). Async tracking is active only after init().`);let u;try{u=c.apply(t,g)}catch(a){throw a}if(!u||typeof u.then!="function")return l||(l=!0,t._asyncStates.delete(n),t._asyncSnapshots.delete(n),t[n]=c.bind(t)),u;let i=t._asyncStates.get(n);return i||(i={loading:!1,error:null,errorCode:null,count:0},t._asyncStates.set(n,i)),i.count++,i.loading=!0,i.error=null,i.errorCode=null,t._asyncSnapshots.set(n,Object.freeze({loading:!0,error:null,errorCode:null})),t._notifyAsync(),d&&t._activeOps&&t._activeOps.set(n,(t._activeOps.get(n)??0)+1),u.then(a=>{if(t._disposed)return a;if(i.count--,i.loading=i.count>0,t._asyncSnapshots.set(n,Object.freeze({loading:i.loading,error:i.error,errorCode:i.errorCode})),t._notifyAsync(),d&&t._activeOps){const _=(t._activeOps.get(n)??1)-1;_<=0?t._activeOps.delete(n):t._activeOps.set(n,_)}return a},a=>{if(m(a)){if(t._disposed||(i.count--,i.loading=i.count>0,t._asyncSnapshots.set(n,Object.freeze({loading:i.loading,error:i.error,errorCode:i.errorCode})),t._notifyAsync()),d&&t._activeOps){const h=(t._activeOps.get(n)??1)-1;h<=0?t._activeOps.delete(n):t._activeOps.set(n,h)}return}if(t._disposed)return;i.count--,i.loading=i.count>0;const _=O(a);if(i.error=_.message,i.errorCode=_.code,t._asyncSnapshots.set(n,Object.freeze({loading:i.loading,error:_.message,errorCode:_.code})),t._notifyAsync(),d&&t._activeOps){const h=(t._activeOps.get(n)??1)-1;h<=0?t._activeOps.delete(n):t._activeOps.set(n,h)}throw a})};e.push(n),t[n]=p}),e.length>0&&this.addCleanup(()=>{const n=d&&t._activeOps?new Map(t._activeOps):null;for(const o of e)d?t[o]=()=>{console.warn(`[mvc-kit] "${o}" called after dispose — ignored.`)}:t[o]=()=>{};t._asyncListeners.clear(),t._asyncStates.clear(),t._asyncSnapshots.clear(),d&&n&&n.size>0&&t._scheduleGhostCheck(n)})}_scheduleGhostCheck(t){d&&setTimeout(()=>{for(const[s,e]of t)console.warn(`[mvc-kit] Ghost async operation detected: "${s}" had ${e} pending call(s) when the ViewModel was disposed. Consider using disposeSignal to cancel in-flight work.`)},this.constructor.GHOST_TIMEOUT)}_installStateProxy(){const t=new Proxy({},{get:(s,e)=>(this._stateTracking?.add(e),this._state[e]),ownKeys:()=>Reflect.ownKeys(this._state),getOwnPropertyDescriptor:(s,e)=>Reflect.getOwnPropertyDescriptor(this._state,e),set:()=>{throw new Error("Cannot mutate state directly. Use set() instead.")},has:(s,e)=>e in this._state});Object.defineProperty(this,"state",{get:()=>this._stateTracking?t:this._state,configurable:!0,enumerable:!0})}_trackSubscribables(){for(const t of Object.getOwnPropertyNames(this)){const s=this[t];if(!M(s))continue;const e={source:s,revision:0,unsubscribe:s.subscribe(()=>{if(!this._disposed){e.revision++,this._revision++,this._state=Object.freeze({...this._state});for(const n of this._listeners)n(this._state,this._state)}})};this._trackedSources.set(t,e),Object.defineProperty(this,t,{get:()=>(this._sourceTracking?.set(t,e),s),configurable:!0,enumerable:!1})}}_memoizeGetters(){const t=new Set;S(this,y.prototype,(s,e)=>{!e.get||t.has(s)||(t.add(s),this._wrapGetter(s,e.get))})}_wrapGetter(t,s){let e,n=-1,o,c,l;Object.defineProperty(this,t,{get:()=>{if(this._disposed||n===this._revision)return e;if(o&&c){let i=!0;for(const[a,_]of c)if(this._state[a]!==_){i=!1;break}if(i&&l)for(const[a,_]of l){const h=this._trackedSources.get(a);if(h&&h.revision!==_){i=!1;break}}if(i)return n=this._revision,e}const p=this._stateTracking,g=this._sourceTracking;this._stateTracking=new Set,this._sourceTracking=new Map;try{e=s.call(this)}catch(i){throw this._stateTracking=p,this._sourceTracking=g,i}o=this._stateTracking;const u=this._sourceTracking;if(this._stateTracking=p,this._sourceTracking=g,p)for(const i of o)p.add(i);if(g)for(const[i,a]of u)g.set(i,a);c=new Map;for(const i of o)c.set(i,this._state[i]);l=new Map;for(const[i,a]of u)l.set(i,a.revision);return n=this._revision,e},configurable:!0,enumerable:!0})}}class D{_state;_committed;_disposed=!1;_initialized=!1;_listeners=new Set;_abortController=null;_cleanups=null;constructor(t){const s=Object.freeze({...t});this._state=s,this._committed=s}get state(){return this._state}get committed(){return this._committed}get dirty(){return!this.shallowEqual(this._state,this._committed)}get errors(){return this.validate(this._state)}get valid(){return Object.keys(this.errors).length===0}get disposed(){return this._disposed}get initialized(){return this._initialized}get disposeSignal(){return this._abortController||(this._abortController=new AbortController),this._abortController.signal}init(){if(!(this._initialized||this._disposed))return this._initialized=!0,this.onInit?.()}set(t){if(this._disposed)throw new Error("Cannot set state on disposed Model");const s=typeof t=="function"?t(this._state):t;if(!Object.keys(s).some(l=>s[l]!==this._state[l]))return;const o=this._state,c=Object.freeze({...o,...s});this._state=c,this.onSet?.(o,c);for(const l of this._listeners)l(c,o)}commit(){if(this._disposed)throw new Error("Cannot commit on disposed Model");this._committed=this._state}rollback(){if(this._disposed)throw new Error("Cannot rollback on disposed Model");if(this.shallowEqual(this._state,this._committed))return;const t=this._state;this._state=this._committed,this.onSet?.(t,this._state);for(const s of this._listeners)s(this._state,t)}subscribe(t){return this._disposed?()=>{}:(this._listeners.add(t),()=>{this._listeners.delete(t)})}dispose(){if(!this._disposed){if(this._disposed=!0,this._abortController?.abort(),this._cleanups){for(const t of this._cleanups)t();this._cleanups=null}this.onDispose?.(),this._listeners.clear()}}validate(t){return{}}addCleanup(t){this._cleanups||(this._cleanups=[]),this._cleanups.push(t)}subscribeTo(t,s){const e=t.subscribe(s);return this.addCleanup(e),e}shallowEqual(t,s){const e=Object.keys(t),n=Object.keys(s);if(e.length!==n.length)return!1;for(const o of e)if(t[o]!==s[o])return!1;return!0}}const f=typeof __MVC_KIT_DEV__<"u"&&__MVC_KIT_DEV__,k=Object.freeze({loading:!1,error:null,errorCode:null}),A=["async","subscribeAsync"],R=new Set(["onInit","onDispose"]);class v extends w.Collection{_external=null;_initialized=!1;_asyncStates=new Map;_asyncSnapshots=new Map;_asyncListeners=new Set;_asyncProxy=null;_activeOps=null;static GHOST_TIMEOUT=3e3;constructor(t){const s=t!=null&&!Array.isArray(t);if(super(s?[]:t??[]),s&&(this._external=t,f)){const e=this.constructor;(e.MAX_SIZE>0||e.TTL>0)&&console.warn(`[mvc-kit] Resource "${e.name}" has MAX_SIZE or TTL set but uses an injected Collection. Configure these on the Collection instead.`)}this._guardReservedKeys()}get initialized(){return this._initialized}init(){if(!(this._initialized||this.disposed))return this._initialized=!0,this._wrapMethods(),this.onInit?.()}get state(){return this._external?this._external.state:super.state}get items(){return this._external?this._external.items:super.items}get length(){return this._external?this._external.length:super.length}add(...t){this._external?this._external.add(...t):super.add(...t)}upsert(...t){this._external?this._external.upsert(...t):super.upsert(...t)}update(t,s){this._external?this._external.update(t,s):super.update(t,s)}remove(...t){this._external?this._external.remove(...t):super.remove(...t)}reset(t){this._external?this._external.reset(t):super.reset(t)}clear(){this._external?this._external.clear():super.clear()}optimistic(t){return this._external?this._external.optimistic(t):super.optimistic(t)}get(t){return this._external?this._external.get(t):super.get(t)}has(t){return this._external?this._external.has(t):super.has(t)}find(t){return this._external?this._external.find(t):super.find(t)}filter(t){return this._external?this._external.filter(t):super.filter(t)}sorted(t){return this._external?this._external.sorted(t):super.sorted(t)}map(t){return this._external?this._external.map(t):super.map(t)}subscribe(t){return this.disposed?()=>{}:this._external?this._external.subscribe(t):super.subscribe(t)}get async(){if(!this._asyncProxy){const t=this;this._asyncProxy=new Proxy({},{get(s,e){return t._asyncSnapshots.get(e)??k},has(s,e){return t._asyncSnapshots.has(e)},ownKeys(){return Array.from(t._asyncSnapshots.keys())},getOwnPropertyDescriptor(s,e){if(t._asyncSnapshots.has(e))return{configurable:!0,enumerable:!0,value:t._asyncSnapshots.get(e)}}})}return this._asyncProxy}subscribeAsync(t){return this.disposed?()=>{}:(this._asyncListeners.add(t),()=>{this._asyncListeners.delete(t)})}_notifyAsync(){for(const t of this._asyncListeners)t()}_guardReservedKeys(){S(this,v.prototype,t=>{if(A.includes(t))throw new Error(`[mvc-kit] "${t}" is a reserved property on Resource and cannot be overridden.`)})}_wrapMethods(){for(const n of A)if(Object.getOwnPropertyDescriptor(this,n)?.value!==void 0)throw new Error(`[mvc-kit] "${n}" is a reserved property on Resource and cannot be overridden.`);const t=this,s=new Set,e=[];f&&(this._activeOps=new Map),S(this,v.prototype,(n,o)=>{if(o.get||o.set||typeof o.value!="function"||n.startsWith("_")||R.has(n)||s.has(n))return;s.add(n);const c=o.value;let l=!1;const p=function(...g){if(t.disposed){f&&console.warn(`[mvc-kit] "${n}" called after dispose — ignored.`);return}f&&!t._initialized&&console.warn(`[mvc-kit] "${n}" called before init(). Async tracking is active only after init().`);let u;try{u=c.apply(t,g)}catch(a){throw a}if(!u||typeof u.then!="function")return l||(l=!0,t._asyncStates.delete(n),t._asyncSnapshots.delete(n),t[n]=c.bind(t)),u;let i=t._asyncStates.get(n);return i||(i={loading:!1,error:null,errorCode:null,count:0},t._asyncStates.set(n,i)),i.count++,i.loading=!0,i.error=null,i.errorCode=null,t._asyncSnapshots.set(n,Object.freeze({loading:!0,error:null,errorCode:null})),t._notifyAsync(),f&&t._activeOps&&t._activeOps.set(n,(t._activeOps.get(n)??0)+1),u.then(a=>{if(t.disposed)return a;if(i.count--,i.loading=i.count>0,t._asyncSnapshots.set(n,Object.freeze({loading:i.loading,error:i.error,errorCode:i.errorCode})),t._notifyAsync(),f&&t._activeOps){const _=(t._activeOps.get(n)??1)-1;_<=0?t._activeOps.delete(n):t._activeOps.set(n,_)}return a},a=>{if(m(a)){if(t.disposed||(i.count--,i.loading=i.count>0,t._asyncSnapshots.set(n,Object.freeze({loading:i.loading,error:i.error,errorCode:i.errorCode})),t._notifyAsync()),f&&t._activeOps){const h=(t._activeOps.get(n)??1)-1;h<=0?t._activeOps.delete(n):t._activeOps.set(n,h)}return}if(t.disposed)return;i.count--,i.loading=i.count>0;const _=O(a);if(i.error=_.message,i.errorCode=_.code,t._asyncSnapshots.set(n,Object.freeze({loading:i.loading,error:_.message,errorCode:_.code})),t._notifyAsync(),f&&t._activeOps){const h=(t._activeOps.get(n)??1)-1;h<=0?t._activeOps.delete(n):t._activeOps.set(n,h)}throw a})};e.push(n),t[n]=p}),e.length>0&&this.addCleanup(()=>{const n=f&&t._activeOps?new Map(t._activeOps):null;for(const o of e)f?t[o]=()=>{console.warn(`[mvc-kit] "${o}" called after dispose — ignored.`)}:t[o]=()=>{};t._asyncListeners.clear(),t._asyncStates.clear(),t._asyncSnapshots.clear(),f&&n&&n.size>0&&t._scheduleGhostCheck(n)})}_scheduleGhostCheck(t){f&&setTimeout(()=>{for(const[s,e]of t)console.warn(`[mvc-kit] Ghost async operation detected: "${s}" had ${e} pending call(s) when the Resource was disposed. Consider using disposeSignal to cancel in-flight work.`)},this.constructor.GHOST_TIMEOUT)}}class I{_disposed=!1;_initialized=!1;_abortController=null;_cleanups=null;get disposed(){return this._disposed}get initialized(){return this._initialized}get disposeSignal(){return this._abortController||(this._abortController=new AbortController),this._abortController.signal}init(){if(!(this._initialized||this._disposed))return this._initialized=!0,this.onInit?.()}dispose(){if(!this._disposed){if(this._disposed=!0,this._abortController?.abort(),this._cleanups){for(const t of this._cleanups)t();this._cleanups=null}this.onDispose?.()}}addCleanup(t){this._cleanups||(this._cleanups=[]),this._cleanups.push(t)}subscribeTo(t,s){const e=t.subscribe(s);return this.addCleanup(e),e}}class K{_disposed=!1;_initialized=!1;_abortController=null;_cleanups=null;get disposed(){return this._disposed}get initialized(){return this._initialized}get disposeSignal(){return this._abortController||(this._abortController=new AbortController),this._abortController.signal}init(){if(!(this._initialized||this._disposed))return this._initialized=!0,this.onInit?.()}dispose(){if(!this._disposed){if(this._disposed=!0,this._abortController?.abort(),this._cleanups){for(const t of this._cleanups)t();this._cleanups=null}this.onDispose?.()}}addCleanup(t){this._cleanups||(this._cleanups=[]),this._cleanups.push(t)}}const C=typeof __MVC_KIT_DEV__<"u"&&__MVC_KIT_DEV__,$=Object.freeze({connected:!1,reconnecting:!1,attempt:0,error:null});class L{static RECONNECT_BASE=1e3;static RECONNECT_MAX=3e4;static RECONNECT_FACTOR=2;static MAX_ATTEMPTS=1/0;_status=$;_connState=0;_disposed=!1;_initialized=!1;_listeners=new Set;_handlers=new Map;_abortController=null;_connectAbort=null;_reconnectTimer=null;_cleanups=null;get state(){return this._status}subscribe(t){return this._disposed?()=>{}:(this._listeners.add(t),()=>{this._listeners.delete(t)})}get disposed(){return this._disposed}get initialized(){return this._initialized}get disposeSignal(){return this._abortController||(this._abortController=new AbortController),this._abortController.signal}init(){if(!(this._initialized||this._disposed))return this._initialized=!0,this.onInit?.()}dispose(){if(!this._disposed){this._disposed=!0,this._connState=4,this._reconnectTimer!==null&&(clearTimeout(this._reconnectTimer),this._reconnectTimer=null),this._connectAbort?.abort(),this._connectAbort=null,this._abortController?.abort();try{this.close()}catch{}if(this._cleanups){for(const t of this._cleanups)t();this._cleanups=null}this.onDispose?.(),this._listeners.clear(),this._handlers.clear()}}connect(){if(this._disposed){C&&console.warn("[mvc-kit] connect() called after dispose — ignored.");return}C&&!this._initialized&&console.warn("[mvc-kit] connect() called before init()."),!(this._connState===1||this._connState===2)&&(this._reconnectTimer!==null&&(clearTimeout(this._reconnectTimer),this._reconnectTimer=null),this._attemptConnect(0))}disconnect(){if(!this._disposed){if(this._reconnectTimer!==null&&(clearTimeout(this._reconnectTimer),this._reconnectTimer=null),this._connectAbort?.abort(),this._connectAbort=null,this._connState===2||this._connState===1){this._connState=0;try{this.close()}catch{}}else this._connState=0;this._setStatus({connected:!1,reconnecting:!1,attempt:0,error:null})}}receive(t,s){if(this._disposed){C&&console.warn(`[mvc-kit] receive("${String(t)}") called after dispose — ignored.`);return}const e=this._handlers.get(t);if(e)for(const n of e)n(s)}disconnected(){this._disposed||this._connState!==2&&this._connState!==1||(this._connectAbort?.abort(),this._connectAbort=null,this._connState=3,this._scheduleReconnect(1))}on(t,s){if(this._disposed)return()=>{};let e=this._handlers.get(t);return e||(e=new Set,this._handlers.set(t,e)),e.add(s),()=>{e.delete(s)}}once(t,s){const e=this.on(t,n=>{e(),s(n)});return e}addCleanup(t){this._cleanups||(this._cleanups=[]),this._cleanups.push(t)}subscribeTo(t,s){const e=t.subscribe(s);return this.addCleanup(e),e}_calculateDelay(t){const s=this.constructor,e=Math.min(s.RECONNECT_BASE*Math.pow(s.RECONNECT_FACTOR,t),s.RECONNECT_MAX);return Math.random()*e}_setStatus(t){const s=this._status;if(!(s.connected===t.connected&&s.reconnecting===t.reconnecting&&s.attempt===t.attempt&&s.error===t.error)){this._status=Object.freeze(t);for(const e of this._listeners)e(this._status,s)}}_attemptConnect(t){if(this._disposed)return;this._connState=1,this._connectAbort?.abort(),this._connectAbort=new AbortController;const s=this._abortController?AbortSignal.any([this._abortController.signal,this._connectAbort.signal]):this._connectAbort.signal;this._setStatus({connected:!1,reconnecting:t>0,attempt:t,error:null});let e;try{e=this.open(s)}catch(n){this._onOpenFailed(t,n);return}e&&typeof e.then=="function"?e.then(()=>this._onOpenSucceeded(),n=>this._onOpenFailed(t,n)):this._onOpenSucceeded()}_onOpenSucceeded(){this._disposed||this._connState===1&&(this._connState=2,this._setStatus({connected:!0,reconnecting:!1,attempt:0,error:null}))}_onOpenFailed(t,s){this._disposed||this._connState!==0&&(this._connectAbort?.abort(),this._connectAbort=null,this._connState=3,this._scheduleReconnect(t+1,s))}_scheduleReconnect(t,s){const e=this.constructor;if(t>e.MAX_ATTEMPTS){this._connState=0,this._setStatus({connected:!1,reconnecting:!1,attempt:t,error:s instanceof Error?s.message:"Max reconnection attempts reached"});return}const n=s instanceof Error?s.message:s?String(s):null;this._setStatus({connected:!1,reconnecting:!0,attempt:t,error:n});const o=this._calculateDelay(t-1);this._reconnectTimer=setTimeout(()=>{this._reconnectTimer=null,this._attemptConnect(t)},o)}}exports.EventBus=b.EventBus;exports.hasSingleton=b.hasSingleton;exports.singleton=b.singleton;exports.teardown=b.teardown;exports.teardownAll=b.teardownAll;exports.Collection=w.Collection;exports.PersistentCollection=w.PersistentCollection;exports.Channel=L;exports.Controller=I;exports.HttpError=z;exports.Model=D;exports.Resource=v;exports.Service=K;exports.ViewModel=y;exports.classifyError=O;exports.isAbortError=m;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const b=require("./singleton-L-u2W_lX.cjs"),w=require("./PersistentCollection-B8kNECDj.cjs");class z extends Error{constructor(t,e){super(e??`HTTP ${t}`),this.status=t,this.name="HttpError"}}function m(r){return r instanceof Error&&r.name==="AbortError"}function T(r){return r===401?"unauthorized":r===403?"forbidden":r===404?"not_found":r===422?"validation":r===429?"rate_limited":r>=500?"server_error":"unknown"}function x(r){return typeof r=="object"&&r!==null&&typeof r.status=="number"&&typeof r.statusText=="string"&&!(r instanceof Error)}function O(r){return r instanceof Error&&r.name==="AbortError"?{code:"abort",message:"Request was aborted",original:r}:r instanceof z?{code:T(r.status),message:r.message,status:r.status,original:r}:x(r)?{code:T(r.status),message:r.statusText||`HTTP ${r.status}`,status:r.status,original:r}:r instanceof TypeError&&r.message.toLowerCase().includes("fetch")?{code:"network",message:r.message,original:r}:r instanceof Error&&r.name==="TimeoutError"?{code:"timeout",message:r.message,original:r}:r instanceof Error?{code:"unknown",message:r.message,original:r}:{code:"unknown",message:String(r),original:r}}const d=typeof __MVC_KIT_DEV__<"u"&&__MVC_KIT_DEV__;function M(r){return r!==null&&typeof r=="object"&&typeof r.subscribe=="function"}function y(r,t,e){let s=Object.getPrototypeOf(r);for(;s&&s!==t;){const n=Object.getOwnPropertyDescriptors(s);for(const[o,c]of Object.entries(n))o!=="constructor"&&e(o,c,s);s=Object.getPrototypeOf(s)}}const j=Object.freeze({loading:!1,error:null,errorCode:null}),E=["async","subscribeAsync"],P=new Set(["onInit","onSet","onDispose"]);class S{_state;_initialState;_disposed=!1;_initialized=!1;_listeners=new Set;_abortController=null;_cleanups=null;_subscriptionCleanups=null;_eventBus=null;_revision=0;_stateTracking=null;_sourceTracking=null;_trackedSources=new Map;_asyncStates=new Map;_asyncSnapshots=new Map;_asyncListeners=new Set;_asyncProxy=null;_activeOps=null;static GHOST_TIMEOUT=3e3;constructor(t){this._state=Object.freeze({...t}),this._initialState=this._state,this._guardReservedKeys()}get state(){return this._state}get disposed(){return this._disposed}get initialized(){return this._initialized}get disposeSignal(){return this._abortController||(this._abortController=new AbortController),this._abortController.signal}get events(){return this._eventBus||(this._eventBus=new b.EventBus),this._eventBus}init(){if(!(this._initialized||this._disposed))return this._initialized=!0,this._trackSubscribables(),this._installStateProxy(),this._memoizeGetters(),this._wrapMethods(),this.onInit?.()}set(t){if(this._disposed)return;if(d&&this._stateTracking){console.error("[mvc-kit] set() called inside a getter. Getters must be pure — they read state and return a value. They must never call set(), which would cause an infinite render loop. Move this logic to an action method.");return}const e=typeof t=="function"?t(this._state):t;if(!Object.keys(e).some(l=>e[l]!==this._state[l]))return;const o=this._state,c=Object.freeze({...o,...e});this._state=c,this._revision++,this.onSet?.(o,c);for(const l of this._listeners)l(c,o)}emit(t,e){(this._eventBus?.disposed??this._disposed)||this.events.emit(t,e)}subscribe(t){return this._disposed?()=>{}:(this._listeners.add(t),()=>{this._listeners.delete(t)})}dispose(){if(!this._disposed){if(this._disposed=!0,this._teardownSubscriptions(),this._abortController?.abort(),this._cleanups){for(const t of this._cleanups)t();this._cleanups=null}this._eventBus?.dispose(),this.onDispose?.(),this._listeners.clear()}}reset(t){if(!this._disposed){this._abortController?.abort(),this._abortController=null,this._teardownSubscriptions(),this._state=t?Object.freeze({...t}):this._initialState,this._revision++,this._asyncStates.clear(),this._asyncSnapshots.clear(),this._notifyAsync(),this._trackSubscribables();for(const e of this._listeners)e(this._state,this._state);return this.onInit?.()}}addCleanup(t){this._cleanups||(this._cleanups=[]),this._cleanups.push(t)}subscribeTo(t,e){const s=t.subscribe(e);return this._subscriptionCleanups||(this._subscriptionCleanups=[]),this._subscriptionCleanups.push(s),s}get async(){if(!this._asyncProxy){const t=this;this._asyncProxy=new Proxy({},{get(e,s){return t._asyncSnapshots.get(s)??j},has(e,s){return t._asyncSnapshots.has(s)},ownKeys(){return Array.from(t._asyncSnapshots.keys())},getOwnPropertyDescriptor(e,s){if(t._asyncSnapshots.has(s))return{configurable:!0,enumerable:!0,value:t._asyncSnapshots.get(s)}}})}return this._asyncProxy}subscribeAsync(t){return this._disposed?()=>{}:(this._asyncListeners.add(t),()=>{this._asyncListeners.delete(t)})}_notifyAsync(){for(const t of this._asyncListeners)t()}_teardownSubscriptions(){for(const t of this._trackedSources.values())t.unsubscribe();if(this._trackedSources.clear(),this._subscriptionCleanups){for(const t of this._subscriptionCleanups)t();this._subscriptionCleanups=null}}_guardReservedKeys(){y(this,S.prototype,t=>{if(E.includes(t))throw new Error(`[mvc-kit] "${t}" is a reserved property on ViewModel and cannot be overridden.`)})}_wrapMethods(){for(const n of E)if(Object.getOwnPropertyDescriptor(this,n)?.value!==void 0)throw new Error(`[mvc-kit] "${n}" is a reserved property on ViewModel and cannot be overridden.`);const t=this,e=new Set,s=[];d&&(this._activeOps=new Map),y(this,S.prototype,(n,o)=>{if(o.get||o.set||typeof o.value!="function"||n.startsWith("_")||P.has(n)||e.has(n))return;e.add(n);const c=o.value;let l=!1;const p=function(...g){if(t._disposed){d&&console.warn(`[mvc-kit] "${n}" called after dispose — ignored.`);return}d&&!t._initialized&&console.warn(`[mvc-kit] "${n}" called before init(). Async tracking is active only after init().`);let _;try{_=c.apply(t,g)}catch(a){throw a}if(!_||typeof _.then!="function")return l||(l=!0,t._asyncStates.delete(n),t._asyncSnapshots.delete(n),t[n]=c.bind(t)),_;let i=t._asyncStates.get(n);return i||(i={loading:!1,error:null,errorCode:null,count:0},t._asyncStates.set(n,i)),i.count++,i.loading=!0,i.error=null,i.errorCode=null,t._asyncSnapshots.set(n,Object.freeze({loading:!0,error:null,errorCode:null})),t._notifyAsync(),d&&t._activeOps&&t._activeOps.set(n,(t._activeOps.get(n)??0)+1),_.then(a=>{if(t._disposed)return a;if(i.count--,i.loading=i.count>0,t._asyncSnapshots.set(n,Object.freeze({loading:i.loading,error:i.error,errorCode:i.errorCode})),t._notifyAsync(),d&&t._activeOps){const u=(t._activeOps.get(n)??1)-1;u<=0?t._activeOps.delete(n):t._activeOps.set(n,u)}return a},a=>{if(m(a)){if(t._disposed||(i.count--,i.loading=i.count>0,t._asyncSnapshots.set(n,Object.freeze({loading:i.loading,error:i.error,errorCode:i.errorCode})),t._notifyAsync()),d&&t._activeOps){const h=(t._activeOps.get(n)??1)-1;h<=0?t._activeOps.delete(n):t._activeOps.set(n,h)}return}if(t._disposed)return;i.count--,i.loading=i.count>0;const u=O(a);if(i.error=u.message,i.errorCode=u.code,t._asyncSnapshots.set(n,Object.freeze({loading:i.loading,error:u.message,errorCode:u.code})),t._notifyAsync(),d&&t._activeOps){const h=(t._activeOps.get(n)??1)-1;h<=0?t._activeOps.delete(n):t._activeOps.set(n,h)}throw a})};s.push(n),t[n]=p}),s.length>0&&this.addCleanup(()=>{const n=d&&t._activeOps?new Map(t._activeOps):null;for(const o of s)d?t[o]=()=>{console.warn(`[mvc-kit] "${o}" called after dispose — ignored.`)}:t[o]=()=>{};t._asyncListeners.clear(),t._asyncStates.clear(),t._asyncSnapshots.clear(),d&&n&&n.size>0&&t._scheduleGhostCheck(n)})}_scheduleGhostCheck(t){d&&setTimeout(()=>{for(const[e,s]of t)console.warn(`[mvc-kit] Ghost async operation detected: "${e}" had ${s} pending call(s) when the ViewModel was disposed. Consider using disposeSignal to cancel in-flight work.`)},this.constructor.GHOST_TIMEOUT)}_installStateProxy(){const t=new Proxy({},{get:(e,s)=>(this._stateTracking?.add(s),this._state[s]),ownKeys:()=>Reflect.ownKeys(this._state),getOwnPropertyDescriptor:(e,s)=>Reflect.getOwnPropertyDescriptor(this._state,s),set:()=>{throw new Error("Cannot mutate state directly. Use set() instead.")},has:(e,s)=>s in this._state});Object.defineProperty(this,"state",{get:()=>this._stateTracking?t:this._state,configurable:!0,enumerable:!0})}_trackSubscribables(){for(const t of Object.getOwnPropertyNames(this)){const e=this[t];if(!M(e))continue;let s;const n=()=>{if(!this._disposed){s.revision++,this._revision++,this._state=Object.freeze({...this._state});for(const l of this._listeners)l(this._state,this._state)}},o=e.subscribe(n),c=typeof e.subscribeAsync=="function"?e.subscribeAsync(n):void 0;s={source:e,revision:0,unsubscribe:c?()=>{o(),c()}:o},this._trackedSources.set(t,s),Object.defineProperty(this,t,{get:()=>(this._sourceTracking?.set(t,s),e),configurable:!0,enumerable:!1})}}_memoizeGetters(){const t=new Set;y(this,S.prototype,(e,s)=>{!s.get||t.has(e)||(t.add(e),this._wrapGetter(e,s.get))})}_wrapGetter(t,e){let s,n=-1,o,c,l;Object.defineProperty(this,t,{get:()=>{if(this._disposed||n===this._revision)return s;if(o&&c){let i=!0;for(const[a,u]of c)if(this._state[a]!==u){i=!1;break}if(i&&l)for(const[a,u]of l){const h=this._trackedSources.get(a);if(h&&h.revision!==u){i=!1;break}}if(i)return n=this._revision,s}const p=this._stateTracking,g=this._sourceTracking;this._stateTracking=new Set,this._sourceTracking=new Map;try{s=e.call(this)}catch(i){throw this._stateTracking=p,this._sourceTracking=g,i}o=this._stateTracking;const _=this._sourceTracking;if(this._stateTracking=p,this._sourceTracking=g,p)for(const i of o)p.add(i);if(g)for(const[i,a]of _)g.set(i,a);c=new Map;for(const i of o)c.set(i,this._state[i]);l=new Map;for(const[i,a]of _)l.set(i,a.revision);return n=this._revision,s},configurable:!0,enumerable:!0})}}class D{_state;_committed;_disposed=!1;_initialized=!1;_listeners=new Set;_abortController=null;_cleanups=null;constructor(t){const e=Object.freeze({...t});this._state=e,this._committed=e}get state(){return this._state}get committed(){return this._committed}get dirty(){return!this.shallowEqual(this._state,this._committed)}get errors(){return this.validate(this._state)}get valid(){return Object.keys(this.errors).length===0}get disposed(){return this._disposed}get initialized(){return this._initialized}get disposeSignal(){return this._abortController||(this._abortController=new AbortController),this._abortController.signal}init(){if(!(this._initialized||this._disposed))return this._initialized=!0,this.onInit?.()}set(t){if(this._disposed)throw new Error("Cannot set state on disposed Model");const e=typeof t=="function"?t(this._state):t;if(!Object.keys(e).some(l=>e[l]!==this._state[l]))return;const o=this._state,c=Object.freeze({...o,...e});this._state=c,this.onSet?.(o,c);for(const l of this._listeners)l(c,o)}commit(){if(this._disposed)throw new Error("Cannot commit on disposed Model");this._committed=this._state}rollback(){if(this._disposed)throw new Error("Cannot rollback on disposed Model");if(this.shallowEqual(this._state,this._committed))return;const t=this._state;this._state=this._committed,this.onSet?.(t,this._state);for(const e of this._listeners)e(this._state,t)}subscribe(t){return this._disposed?()=>{}:(this._listeners.add(t),()=>{this._listeners.delete(t)})}dispose(){if(!this._disposed){if(this._disposed=!0,this._abortController?.abort(),this._cleanups){for(const t of this._cleanups)t();this._cleanups=null}this.onDispose?.(),this._listeners.clear()}}validate(t){return{}}addCleanup(t){this._cleanups||(this._cleanups=[]),this._cleanups.push(t)}subscribeTo(t,e){const s=t.subscribe(e);return this.addCleanup(s),s}shallowEqual(t,e){const s=Object.keys(t),n=Object.keys(e);if(s.length!==n.length)return!1;for(const o of s)if(t[o]!==e[o])return!1;return!0}}const f=typeof __MVC_KIT_DEV__<"u"&&__MVC_KIT_DEV__,k=Object.freeze({loading:!1,error:null,errorCode:null}),A=["async","subscribeAsync"],R=new Set(["onInit","onDispose"]);class v extends w.Collection{_external=null;_initialized=!1;_asyncStates=new Map;_asyncSnapshots=new Map;_asyncListeners=new Set;_asyncProxy=null;_activeOps=null;static GHOST_TIMEOUT=3e3;constructor(t){const e=t!=null&&!Array.isArray(t);if(super(e?[]:t??[]),e&&(this._external=t,f)){const s=this.constructor;(s.MAX_SIZE>0||s.TTL>0)&&console.warn(`[mvc-kit] Resource "${s.name}" has MAX_SIZE or TTL set but uses an injected Collection. Configure these on the Collection instead.`)}this._guardReservedKeys()}get initialized(){return this._initialized}init(){if(!(this._initialized||this.disposed))return this._initialized=!0,this._wrapMethods(),this.onInit?.()}get state(){return this._external?this._external.state:super.state}get items(){return this._external?this._external.items:super.items}get length(){return this._external?this._external.length:super.length}add(...t){this._external?this._external.add(...t):super.add(...t)}upsert(...t){this._external?this._external.upsert(...t):super.upsert(...t)}update(t,e){this._external?this._external.update(t,e):super.update(t,e)}remove(...t){this._external?this._external.remove(...t):super.remove(...t)}reset(t){this._external?this._external.reset(t):super.reset(t)}clear(){this._external?this._external.clear():super.clear()}optimistic(t){return this._external?this._external.optimistic(t):super.optimistic(t)}get(t){return this._external?this._external.get(t):super.get(t)}has(t){return this._external?this._external.has(t):super.has(t)}find(t){return this._external?this._external.find(t):super.find(t)}filter(t){return this._external?this._external.filter(t):super.filter(t)}sorted(t){return this._external?this._external.sorted(t):super.sorted(t)}map(t){return this._external?this._external.map(t):super.map(t)}subscribe(t){return this.disposed?()=>{}:this._external?this._external.subscribe(t):super.subscribe(t)}get async(){if(!this._asyncProxy){const t=this;this._asyncProxy=new Proxy({},{get(e,s){return t._asyncSnapshots.get(s)??k},has(e,s){return t._asyncSnapshots.has(s)},ownKeys(){return Array.from(t._asyncSnapshots.keys())},getOwnPropertyDescriptor(e,s){if(t._asyncSnapshots.has(s))return{configurable:!0,enumerable:!0,value:t._asyncSnapshots.get(s)}}})}return this._asyncProxy}subscribeAsync(t){return this.disposed?()=>{}:(this._asyncListeners.add(t),()=>{this._asyncListeners.delete(t)})}_notifyAsync(){for(const t of this._asyncListeners)t()}_guardReservedKeys(){y(this,v.prototype,t=>{if(A.includes(t))throw new Error(`[mvc-kit] "${t}" is a reserved property on Resource and cannot be overridden.`)})}_wrapMethods(){for(const n of A)if(Object.getOwnPropertyDescriptor(this,n)?.value!==void 0)throw new Error(`[mvc-kit] "${n}" is a reserved property on Resource and cannot be overridden.`);const t=this,e=new Set,s=[];f&&(this._activeOps=new Map),y(this,v.prototype,(n,o)=>{if(o.get||o.set||typeof o.value!="function"||n.startsWith("_")||R.has(n)||e.has(n))return;e.add(n);const c=o.value;let l=!1;const p=function(...g){if(t.disposed){f&&console.warn(`[mvc-kit] "${n}" called after dispose — ignored.`);return}f&&!t._initialized&&console.warn(`[mvc-kit] "${n}" called before init(). Async tracking is active only after init().`);let _;try{_=c.apply(t,g)}catch(a){throw a}if(!_||typeof _.then!="function")return l||(l=!0,t._asyncStates.delete(n),t._asyncSnapshots.delete(n),t[n]=c.bind(t)),_;let i=t._asyncStates.get(n);return i||(i={loading:!1,error:null,errorCode:null,count:0},t._asyncStates.set(n,i)),i.count++,i.loading=!0,i.error=null,i.errorCode=null,t._asyncSnapshots.set(n,Object.freeze({loading:!0,error:null,errorCode:null})),t._notifyAsync(),f&&t._activeOps&&t._activeOps.set(n,(t._activeOps.get(n)??0)+1),_.then(a=>{if(t.disposed)return a;if(i.count--,i.loading=i.count>0,t._asyncSnapshots.set(n,Object.freeze({loading:i.loading,error:i.error,errorCode:i.errorCode})),t._notifyAsync(),f&&t._activeOps){const u=(t._activeOps.get(n)??1)-1;u<=0?t._activeOps.delete(n):t._activeOps.set(n,u)}return a},a=>{if(m(a)){if(t.disposed||(i.count--,i.loading=i.count>0,t._asyncSnapshots.set(n,Object.freeze({loading:i.loading,error:i.error,errorCode:i.errorCode})),t._notifyAsync()),f&&t._activeOps){const h=(t._activeOps.get(n)??1)-1;h<=0?t._activeOps.delete(n):t._activeOps.set(n,h)}return}if(t.disposed)return;i.count--,i.loading=i.count>0;const u=O(a);if(i.error=u.message,i.errorCode=u.code,t._asyncSnapshots.set(n,Object.freeze({loading:i.loading,error:u.message,errorCode:u.code})),t._notifyAsync(),f&&t._activeOps){const h=(t._activeOps.get(n)??1)-1;h<=0?t._activeOps.delete(n):t._activeOps.set(n,h)}throw a})};s.push(n),t[n]=p}),s.length>0&&this.addCleanup(()=>{const n=f&&t._activeOps?new Map(t._activeOps):null;for(const o of s)f?t[o]=()=>{console.warn(`[mvc-kit] "${o}" called after dispose — ignored.`)}:t[o]=()=>{};t._asyncListeners.clear(),t._asyncStates.clear(),t._asyncSnapshots.clear(),f&&n&&n.size>0&&t._scheduleGhostCheck(n)})}_scheduleGhostCheck(t){f&&setTimeout(()=>{for(const[e,s]of t)console.warn(`[mvc-kit] Ghost async operation detected: "${e}" had ${s} pending call(s) when the Resource was disposed. Consider using disposeSignal to cancel in-flight work.`)},this.constructor.GHOST_TIMEOUT)}}class I{_disposed=!1;_initialized=!1;_abortController=null;_cleanups=null;get disposed(){return this._disposed}get initialized(){return this._initialized}get disposeSignal(){return this._abortController||(this._abortController=new AbortController),this._abortController.signal}init(){if(!(this._initialized||this._disposed))return this._initialized=!0,this.onInit?.()}dispose(){if(!this._disposed){if(this._disposed=!0,this._abortController?.abort(),this._cleanups){for(const t of this._cleanups)t();this._cleanups=null}this.onDispose?.()}}addCleanup(t){this._cleanups||(this._cleanups=[]),this._cleanups.push(t)}subscribeTo(t,e){const s=t.subscribe(e);return this.addCleanup(s),s}}class K{_disposed=!1;_initialized=!1;_abortController=null;_cleanups=null;get disposed(){return this._disposed}get initialized(){return this._initialized}get disposeSignal(){return this._abortController||(this._abortController=new AbortController),this._abortController.signal}init(){if(!(this._initialized||this._disposed))return this._initialized=!0,this.onInit?.()}dispose(){if(!this._disposed){if(this._disposed=!0,this._abortController?.abort(),this._cleanups){for(const t of this._cleanups)t();this._cleanups=null}this.onDispose?.()}}addCleanup(t){this._cleanups||(this._cleanups=[]),this._cleanups.push(t)}}const C=typeof __MVC_KIT_DEV__<"u"&&__MVC_KIT_DEV__,$=Object.freeze({connected:!1,reconnecting:!1,attempt:0,error:null});class L{static RECONNECT_BASE=1e3;static RECONNECT_MAX=3e4;static RECONNECT_FACTOR=2;static MAX_ATTEMPTS=1/0;_status=$;_connState=0;_disposed=!1;_initialized=!1;_listeners=new Set;_handlers=new Map;_abortController=null;_connectAbort=null;_reconnectTimer=null;_cleanups=null;get state(){return this._status}subscribe(t){return this._disposed?()=>{}:(this._listeners.add(t),()=>{this._listeners.delete(t)})}get disposed(){return this._disposed}get initialized(){return this._initialized}get disposeSignal(){return this._abortController||(this._abortController=new AbortController),this._abortController.signal}init(){if(!(this._initialized||this._disposed))return this._initialized=!0,this.onInit?.()}dispose(){if(!this._disposed){this._disposed=!0,this._connState=4,this._reconnectTimer!==null&&(clearTimeout(this._reconnectTimer),this._reconnectTimer=null),this._connectAbort?.abort(),this._connectAbort=null,this._abortController?.abort();try{this.close()}catch{}if(this._cleanups){for(const t of this._cleanups)t();this._cleanups=null}this.onDispose?.(),this._listeners.clear(),this._handlers.clear()}}connect(){if(this._disposed){C&&console.warn("[mvc-kit] connect() called after dispose — ignored.");return}C&&!this._initialized&&console.warn("[mvc-kit] connect() called before init()."),!(this._connState===1||this._connState===2)&&(this._reconnectTimer!==null&&(clearTimeout(this._reconnectTimer),this._reconnectTimer=null),this._attemptConnect(0))}disconnect(){if(!this._disposed){if(this._reconnectTimer!==null&&(clearTimeout(this._reconnectTimer),this._reconnectTimer=null),this._connectAbort?.abort(),this._connectAbort=null,this._connState===2||this._connState===1){this._connState=0;try{this.close()}catch{}}else this._connState=0;this._setStatus({connected:!1,reconnecting:!1,attempt:0,error:null})}}receive(t,e){if(this._disposed){C&&console.warn(`[mvc-kit] receive("${String(t)}") called after dispose — ignored.`);return}const s=this._handlers.get(t);if(s)for(const n of s)n(e)}disconnected(){this._disposed||this._connState!==2&&this._connState!==1||(this._connectAbort?.abort(),this._connectAbort=null,this._connState=3,this._scheduleReconnect(1))}on(t,e){if(this._disposed)return()=>{};let s=this._handlers.get(t);return s||(s=new Set,this._handlers.set(t,s)),s.add(e),()=>{s.delete(e)}}once(t,e){const s=this.on(t,n=>{s(),e(n)});return s}addCleanup(t){this._cleanups||(this._cleanups=[]),this._cleanups.push(t)}subscribeTo(t,e){const s=t.subscribe(e);return this.addCleanup(s),s}_calculateDelay(t){const e=this.constructor,s=Math.min(e.RECONNECT_BASE*Math.pow(e.RECONNECT_FACTOR,t),e.RECONNECT_MAX);return Math.random()*s}_setStatus(t){const e=this._status;if(!(e.connected===t.connected&&e.reconnecting===t.reconnecting&&e.attempt===t.attempt&&e.error===t.error)){this._status=Object.freeze(t);for(const s of this._listeners)s(this._status,e)}}_attemptConnect(t){if(this._disposed)return;this._connState=1,this._connectAbort?.abort(),this._connectAbort=new AbortController;const e=this._abortController?AbortSignal.any([this._abortController.signal,this._connectAbort.signal]):this._connectAbort.signal;this._setStatus({connected:!1,reconnecting:t>0,attempt:t,error:null});let s;try{s=this.open(e)}catch(n){this._onOpenFailed(t,n);return}s&&typeof s.then=="function"?s.then(()=>this._onOpenSucceeded(),n=>this._onOpenFailed(t,n)):this._onOpenSucceeded()}_onOpenSucceeded(){this._disposed||this._connState===1&&(this._connState=2,this._setStatus({connected:!0,reconnecting:!1,attempt:0,error:null}))}_onOpenFailed(t,e){this._disposed||this._connState!==0&&(this._connectAbort?.abort(),this._connectAbort=null,this._connState=3,this._scheduleReconnect(t+1,e))}_scheduleReconnect(t,e){const s=this.constructor;if(t>s.MAX_ATTEMPTS){this._connState=0,this._setStatus({connected:!1,reconnecting:!1,attempt:t,error:e instanceof Error?e.message:"Max reconnection attempts reached"});return}const n=e instanceof Error?e.message:e?String(e):null;this._setStatus({connected:!1,reconnecting:!0,attempt:t,error:n});const o=this._calculateDelay(t-1);this._reconnectTimer=setTimeout(()=>{this._reconnectTimer=null,this._attemptConnect(t)},o)}}exports.EventBus=b.EventBus;exports.hasSingleton=b.hasSingleton;exports.singleton=b.singleton;exports.teardown=b.teardown;exports.teardownAll=b.teardownAll;exports.Collection=w.Collection;exports.PersistentCollection=w.PersistentCollection;exports.Channel=L;exports.Controller=I;exports.HttpError=z;exports.Model=D;exports.Resource=v;exports.Service=K;exports.ViewModel=S;exports.classifyError=O;exports.isAbortError=m;
2
2
  //# sourceMappingURL=mvc-kit.cjs.map