mvc-kit 2.2.2 → 2.2.3
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 +5 -4
- package/agent-config/claude-code/agents/mvc-kit-architect.md +2 -3
- package/agent-config/claude-code/skills/guide/SKILL.md +1 -1
- package/agent-config/claude-code/skills/guide/anti-patterns.md +42 -3
- package/agent-config/claude-code/skills/guide/api-reference.md +4 -3
- package/agent-config/claude-code/skills/guide/patterns.md +18 -13
- package/agent-config/claude-code/skills/review/checklist.md +1 -1
- package/agent-config/claude-code/skills/scaffold/SKILL.md +1 -1
- package/agent-config/claude-code/skills/scaffold/templates/collection.md +7 -14
- package/agent-config/claude-code/skills/scaffold/templates/viewmodel.md +13 -42
- package/agent-config/copilot/copilot-instructions.md +14 -16
- package/agent-config/cursor/cursorrules +14 -16
- package/dist/Channel.d.ts +29 -0
- package/dist/Channel.d.ts.map +1 -1
- package/dist/Collection.d.ts +16 -1
- package/dist/Collection.d.ts.map +1 -1
- package/dist/Controller.d.ts +9 -0
- package/dist/Controller.d.ts.map +1 -1
- package/dist/EventBus.d.ts +5 -0
- package/dist/EventBus.d.ts.map +1 -1
- package/dist/Model.d.ts +16 -0
- package/dist/Model.d.ts.map +1 -1
- package/dist/Service.d.ts +8 -0
- package/dist/Service.d.ts.map +1 -1
- package/dist/ViewModel.d.ts +35 -1
- package/dist/ViewModel.d.ts.map +1 -1
- package/dist/mvc-kit.cjs +1 -1
- package/dist/mvc-kit.cjs.map +1 -1
- package/dist/mvc-kit.js +226 -111
- package/dist/mvc-kit.js.map +1 -1
- package/dist/react/provider.d.ts +1 -0
- package/dist/react/provider.d.ts.map +1 -1
- package/dist/react/use-model.d.ts +2 -0
- package/dist/react/use-model.d.ts.map +1 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +1 -1
- package/dist/react.js.map +1 -1
- package/dist/{singleton-C8_FRbA7.js → singleton-CaEXSbYg.js} +5 -1
- package/dist/singleton-CaEXSbYg.js.map +1 -0
- package/dist/singleton-L-u2W_lX.cjs.map +1 -1
- package/dist/singleton.d.ts +10 -0
- package/dist/singleton.d.ts.map +1 -1
- package/mvc-kit-logo.jpg +0 -0
- package/package.json +2 -1
- package/dist/singleton-C8_FRbA7.js.map +0 -1
package/dist/mvc-kit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mvc-kit.js","sources":["../src/errors.ts","../src/ViewModel.ts","../src/Model.ts","../src/Collection.ts","../src/Controller.ts","../src/Service.ts","../src/Channel.ts"],"sourcesContent":["/**\n * Canonical application error shape for consistent error handling.\n */\nexport interface AppError {\n code:\n | 'unauthorized'\n | 'forbidden'\n | 'not_found'\n | 'validation'\n | 'rate_limited'\n | 'server_error'\n | 'network'\n | 'timeout'\n | 'abort'\n | 'unknown';\n message: string;\n status?: number;\n original?: unknown;\n}\n\n/**\n * Typed HTTP error for services to throw.\n */\nexport class HttpError extends Error {\n constructor(\n public readonly status: number,\n message?: string\n ) {\n super(message ?? `HTTP ${status}`);\n this.name = 'HttpError';\n }\n}\n\n/**\n * Guard for AbortError — the most-repeated check in async ViewModels.\n * Uses duck-typing so the core lib doesn't require DOM types.\n */\nexport function isAbortError(error: unknown): boolean {\n return error instanceof Error && error.name === 'AbortError';\n}\n\nfunction classifyHttpStatus(\n status: number\n): AppError['code'] {\n if (status === 401) return 'unauthorized';\n if (status === 403) return 'forbidden';\n if (status === 404) return 'not_found';\n if (status === 422) return 'validation';\n if (status === 429) return 'rate_limited';\n if (status >= 500) return 'server_error';\n return 'unknown';\n}\n\nfunction isResponseLike(value: unknown): value is { status: number; statusText: string } {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as Record<string, unknown>).status === 'number' &&\n typeof (value as Record<string, unknown>).statusText === 'string' &&\n !(value instanceof Error)\n );\n}\n\n/**\n * Maps raw errors to a canonical AppError shape.\n */\nexport function classifyError(error: unknown): AppError {\n // AbortError (fetch cancelled / DOMException)\n if (error instanceof Error && error.name === 'AbortError') {\n return {\n code: 'abort',\n message: 'Request was aborted',\n original: error,\n };\n }\n\n // HttpError (thrown by services)\n if (error instanceof HttpError) {\n return {\n code: classifyHttpStatus(error.status),\n message: error.message,\n status: error.status,\n original: error,\n };\n }\n\n // Raw Response object (duck-typed: has status + statusText, is not an Error)\n if (isResponseLike(error)) {\n return {\n code: classifyHttpStatus(error.status),\n message: error.statusText || `HTTP ${error.status}`,\n status: error.status,\n original: error,\n };\n }\n\n // Network error (fetch failure)\n if (\n error instanceof TypeError &&\n error.message.toLowerCase().includes('fetch')\n ) {\n return {\n code: 'network',\n message: error.message,\n original: error,\n };\n }\n\n // Timeout error\n if (error instanceof Error && error.name === 'TimeoutError') {\n return {\n code: 'timeout',\n message: error.message,\n original: error,\n };\n }\n\n // Generic Error fallback\n if (error instanceof Error) {\n return {\n code: 'unknown',\n message: error.message,\n original: error,\n };\n }\n\n // Non-Error fallback\n return {\n code: 'unknown',\n message: String(error),\n original: error,\n };\n}\n","import { EventBus } from './EventBus';\nimport { isAbortError, classifyError } from './errors';\nimport type { Listener, Updater, Subscribable, TaskState } from './types';\n\n// Re-export for backwards compatibility\nexport type { Listener, Updater } from './types';\n\nconst __DEV__ = typeof __MVC_KIT_DEV__ !== 'undefined' && __MVC_KIT_DEV__;\n\n// ── Auto-tracking types ──────────────────────────────────────────\n\ninterface TrackedSource {\n source: { subscribe(cb: () => void): () => void };\n revision: number;\n unsubscribe: () => void;\n}\n\n// ── Auto-tracking utilities ──────────────────────────────────────\n\nfunction isAutoTrackable(value: unknown): boolean {\n return (\n value !== null &&\n typeof value === 'object' &&\n typeof (value as any).subscribe === 'function'\n );\n}\n\n/**\n * Walk the prototype chain from `instance`'s class up to (but not including)\n * `stopAt`. Calls `visitor` for each own property descriptor found.\n *\n * Shared utility — also used by RFC 2's _wrapMethods().\n */\nexport function walkPrototypeChain(\n instance: object,\n stopAt: object,\n visitor: (key: string, desc: PropertyDescriptor, proto: object) => void,\n): void {\n let proto = Object.getPrototypeOf(instance);\n while (proto && proto !== stopAt) {\n const descriptors = Object.getOwnPropertyDescriptors(proto);\n for (const [key, desc] of Object.entries(descriptors)) {\n if (key === 'constructor') continue;\n visitor(key, desc, proto);\n }\n proto = Object.getPrototypeOf(proto);\n }\n}\n\n// ── Async tracking types ─────────────────────────────────────────\n\nconst DEFAULT_TASK_STATE: TaskState = Object.freeze({ loading: false, error: null, errorCode: null });\n\nexport type AsyncMethodKeys<T, Base = ViewModel<any, any>> = {\n [K in Exclude<keyof T, keyof Base>]: T[K] extends (...args: any[]) => Promise<any> ? K : never;\n}[Exclude<keyof T, keyof Base>];\n\ntype AsyncMap<T> = {\n readonly [K in AsyncMethodKeys<T>]: TaskState;\n};\n\ninterface InternalTaskState {\n loading: boolean;\n error: string | null;\n errorCode: TaskState['errorCode'];\n count: number;\n}\n\nconst RESERVED_ASYNC_KEYS = ['async', 'subscribeAsync'] as const;\nconst LIFECYCLE_HOOKS = new Set(['onInit', 'onSet', 'onDispose']);\n\n// ── ViewModel ────────────────────────────────────────────────────\n\nexport abstract class ViewModel<S extends object, E extends Record<string, any> = {}> implements Subscribable<S> {\n private _state: Readonly<S>;\n private _initialState: Readonly<S>;\n private _disposed = false;\n private _initialized = false;\n private _listeners = new Set<Listener<S>>();\n private _abortController: AbortController | null = null;\n private _cleanups: (() => void)[] | null = null;\n private _subscriptionCleanups: (() => void)[] | null = null;\n private _eventBus: EventBus<E> | null = null;\n\n // ── Reactive derived state (RFC 1) ─────────────────────────────\n private _revision = 0;\n private _stateTracking: Set<string> | null = null;\n private _sourceTracking: Map<string, TrackedSource> | null = null;\n private _trackedSources = new Map<string, TrackedSource>();\n\n // ── Async tracking (RFC 2) ──────────────────────────────────────\n private _asyncStates = new Map<string, InternalTaskState>();\n private _asyncSnapshots = new Map<string, TaskState>();\n private _asyncListeners = new Set<() => void>();\n private _asyncProxy: AsyncMap<this> | null = null;\n private _activeOps: Map<string, number> | null = null;\n static GHOST_TIMEOUT = 3000;\n\n constructor(initialState: S) {\n this._state = Object.freeze({ ...initialState });\n this._initialState = this._state;\n this._guardReservedKeys();\n }\n\n get state(): Readonly<S> {\n return this._state;\n }\n\n get disposed(): boolean {\n return this._disposed;\n }\n\n get initialized(): boolean {\n return this._initialized;\n }\n\n get disposeSignal(): AbortSignal {\n if (!this._abortController) {\n this._abortController = new AbortController();\n }\n return this._abortController.signal;\n }\n\n get events(): EventBus<E> {\n if (!this._eventBus) {\n this._eventBus = new EventBus<E>();\n }\n return this._eventBus;\n }\n\n init(): void | Promise<void> {\n if (this._initialized || this._disposed) return;\n this._initialized = true;\n this._trackSubscribables();\n this._installStateProxy();\n this._memoizeGetters();\n this._wrapMethods();\n return this.onInit?.();\n }\n\n /**\n * Merges partial state into current state. If no values actually\n * changed by reference, this is a no-op.\n *\n * Triggers React re-render via listener notification. Called when:\n * - User code calls set() to update source state\n *\n * NOT called for subscribable member notifications — those use\n * a separate notification path (see _trackSubscribables).\n */\n protected set(partialOrUpdater: Partial<S> | Updater<S>): void {\n if (this._disposed) return;\n\n // __DEV__ guard: set() inside a getter would cause infinite loops.\n // After init(), getters are auto-memoized; set() → notify → recompute → set() → ∞\n if (__DEV__ && this._stateTracking) {\n console.error(\n '[mvc-kit] set() called inside a getter. ' +\n 'Getters must be pure — they read state and return a value. ' +\n 'They must never call set(), which would cause an infinite ' +\n 'render loop. Move this logic to an action method.'\n );\n return;\n }\n\n const partial =\n typeof partialOrUpdater === 'function'\n ? partialOrUpdater(this._state)\n : partialOrUpdater;\n\n // Check if any values actually changed (shallow equality)\n const keys = Object.keys(partial) as (keyof S)[];\n const hasChanges = keys.some(\n (key) => partial[key] !== this._state[key]\n );\n\n if (!hasChanges) {\n return;\n }\n\n const prev = this._state;\n const next = Object.freeze({ ...prev, ...partial });\n this._state = next;\n this._revision++;\n\n this.onSet?.(prev, next);\n\n for (const listener of this._listeners) {\n listener(next, prev);\n }\n }\n\n protected emit<K extends keyof E>(event: K, payload: E[K]): void {\n // During dispose sequence: _disposed is true but eventBus not yet disposed.\n // Cleanup callbacks can still emit. After eventBus.dispose(), this is a no-op.\n // If eventBus was never created, fall back to _disposed check.\n if (this._eventBus?.disposed ?? this._disposed) return;\n this.events.emit(event, payload);\n }\n\n subscribe(listener: Listener<S>): () => void {\n if (this._disposed) {\n return () => {};\n }\n\n this._listeners.add(listener);\n\n return () => {\n this._listeners.delete(listener);\n };\n }\n\n dispose(): void {\n if (this._disposed) {\n return;\n }\n\n this._disposed = true;\n\n this._teardownSubscriptions();\n\n // Async tracking cleanup — handled by addCleanup registered in _wrapMethods()\n this._abortController?.abort();\n if (this._cleanups) {\n for (const fn of this._cleanups) fn();\n this._cleanups = null;\n }\n this._eventBus?.dispose();\n this.onDispose?.();\n this._listeners.clear();\n }\n\n reset(newState?: S): void | Promise<void> {\n if (this._disposed) return;\n\n // 1. Abort in-flight, lazy-recreate on next disposeSignal access\n this._abortController?.abort();\n this._abortController = null;\n\n this._teardownSubscriptions();\n\n // 2. Reset state\n this._state = newState ? Object.freeze({ ...newState }) : this._initialState;\n this._revision++;\n\n // 3. Clear async tracking (preserve listeners — React still subscribed)\n this._asyncStates.clear();\n this._asyncSnapshots.clear();\n this._notifyAsync();\n\n // 4. Re-track subscribable members (fresh subscriptions)\n this._trackSubscribables();\n\n // 5. Notify state listeners (React re-renders with new state)\n for (const listener of this._listeners) {\n listener(this._state, this._state);\n }\n\n // 6. Re-run onInit\n return this.onInit?.();\n }\n\n protected addCleanup(fn: () => void): void {\n if (!this._cleanups) {\n this._cleanups = [];\n }\n this._cleanups.push(fn);\n }\n\n protected subscribeTo<T>(source: Subscribable<T>, listener: Listener<T>): () => void {\n const unsubscribe = source.subscribe(listener);\n if (!this._subscriptionCleanups) this._subscriptionCleanups = [];\n this._subscriptionCleanups.push(unsubscribe);\n return unsubscribe;\n }\n\n protected onSet?(prev: Readonly<S>, next: Readonly<S>): void;\n protected onInit?(): void | Promise<void>;\n protected onDispose?(): void;\n\n // ── Async tracking API ──────────────────────────────────────────\n\n get async(): AsyncMap<this> {\n if (!this._asyncProxy) {\n const self = this;\n this._asyncProxy = new Proxy({} as AsyncMap<this>, {\n get(_, prop: string) {\n return self._asyncSnapshots.get(prop) ?? DEFAULT_TASK_STATE;\n },\n has(_, prop: string) {\n return self._asyncSnapshots.has(prop);\n },\n ownKeys() {\n return Array.from(self._asyncSnapshots.keys());\n },\n getOwnPropertyDescriptor(_, prop: string) {\n if (self._asyncSnapshots.has(prop)) {\n return { configurable: true, enumerable: true, value: self._asyncSnapshots.get(prop) };\n }\n return undefined;\n },\n });\n }\n return this._asyncProxy;\n }\n\n subscribeAsync(listener: () => void): () => void {\n if (this._disposed) return () => {};\n this._asyncListeners.add(listener);\n return () => { this._asyncListeners.delete(listener); };\n }\n\n private _notifyAsync(): void {\n for (const listener of this._asyncListeners) {\n listener();\n }\n }\n\n // ── Async tracking internals ────────────────────────────────────\n\n private _teardownSubscriptions(): void {\n for (const tracked of this._trackedSources.values()) tracked.unsubscribe();\n this._trackedSources.clear();\n\n if (this._subscriptionCleanups) {\n for (const fn of this._subscriptionCleanups) fn();\n this._subscriptionCleanups = null;\n }\n }\n\n private _guardReservedKeys(): void {\n // Prototype check (runs in constructor — catches method/getter definitions)\n walkPrototypeChain(this, ViewModel.prototype, (key) => {\n if (RESERVED_ASYNC_KEYS.includes(key as any)) {\n throw new Error(\n `[mvc-kit] \"${key}\" is a reserved property on ViewModel and cannot be overridden.`\n );\n }\n });\n }\n\n private _wrapMethods(): void {\n // Instance property check (class fields assigned after super())\n for (const key of RESERVED_ASYNC_KEYS) {\n if (Object.getOwnPropertyDescriptor(this, key)?.value !== undefined) {\n throw new Error(\n `[mvc-kit] \"${key}\" is a reserved property on ViewModel and cannot be overridden.`\n );\n }\n }\n\n const self = this;\n const processed = new Set<string>();\n const wrappedKeys: string[] = [];\n\n if (__DEV__) {\n this._activeOps = new Map();\n }\n\n walkPrototypeChain(this, ViewModel.prototype, (key, desc) => {\n // Skip getters/setters (owned by RFC 1 memoization)\n if (desc.get || desc.set) return;\n // Skip non-functions\n if (typeof desc.value !== 'function') return;\n // Skip _-prefixed (private convention)\n if (key.startsWith('_')) return;\n // Skip lifecycle hooks (managed by framework)\n if (LIFECYCLE_HOOKS.has(key)) return;\n // Most-derived wins\n if (processed.has(key)) return;\n processed.add(key);\n\n const original = desc.value as (...args: unknown[]) => unknown;\n let pruned = false;\n\n const wrapper = function (this: any, ...args: unknown[]) {\n // Disposed guard\n if (self._disposed) {\n if (__DEV__) {\n console.warn(`[mvc-kit] \"${key}\" called after dispose — ignored.`);\n }\n return undefined;\n }\n\n // Pre-init guard (DEV only — method still executes)\n if (__DEV__ && !self._initialized) {\n console.warn(\n `[mvc-kit] \"${key}\" called before init(). ` +\n `Async tracking is active only after init().`\n );\n }\n\n let result: unknown;\n try {\n result = original.apply(self, args);\n } catch (e) {\n // Sync throw — not tracked as async\n throw e;\n }\n\n // Sync detection: if not thenable, prune from async tracking\n if (!result || typeof (result as any).then !== 'function') {\n if (!pruned) {\n pruned = true;\n // Remove from async maps\n self._asyncStates.delete(key);\n self._asyncSnapshots.delete(key);\n // Replace wrapper with bound original for zero overhead\n (self as any)[key] = original.bind(self);\n }\n return result;\n }\n\n // ── Async tracking ──────────────────────────────────────\n let internal = self._asyncStates.get(key);\n if (!internal) {\n internal = { loading: false, error: null, errorCode: null, count: 0 };\n self._asyncStates.set(key, internal);\n }\n\n internal.count++;\n internal.loading = true;\n internal.error = null;\n internal.errorCode = null;\n self._asyncSnapshots.set(key, Object.freeze({ loading: true, error: null, errorCode: null }));\n self._notifyAsync();\n\n if (__DEV__ && self._activeOps) {\n self._activeOps.set(key, (self._activeOps.get(key) ?? 0) + 1);\n }\n\n return (result as Promise<unknown>).then(\n (value) => {\n if (self._disposed) return value;\n\n internal!.count--;\n internal!.loading = internal!.count > 0;\n self._asyncSnapshots.set(\n key,\n Object.freeze({ loading: internal!.loading, error: internal!.error, errorCode: internal!.errorCode }),\n );\n self._notifyAsync();\n\n if (__DEV__ && self._activeOps) {\n const c = (self._activeOps.get(key) ?? 1) - 1;\n if (c <= 0) self._activeOps.delete(key);\n else self._activeOps.set(key, c);\n }\n\n return value;\n },\n (error) => {\n // AbortError — silently swallow\n if (isAbortError(error)) {\n if (!self._disposed) {\n internal!.count--;\n internal!.loading = internal!.count > 0;\n self._asyncSnapshots.set(\n key,\n Object.freeze({ loading: internal!.loading, error: internal!.error, errorCode: internal!.errorCode }),\n );\n self._notifyAsync();\n }\n\n if (__DEV__ && self._activeOps) {\n const c = (self._activeOps.get(key) ?? 1) - 1;\n if (c <= 0) self._activeOps.delete(key);\n else self._activeOps.set(key, c);\n }\n\n return undefined;\n }\n\n // Disposed — fizzle silently\n if (self._disposed) return undefined;\n\n internal!.count--;\n internal!.loading = internal!.count > 0;\n const classified = classifyError(error);\n internal!.error = classified.message;\n internal!.errorCode = classified.code;\n self._asyncSnapshots.set(\n key,\n Object.freeze({ loading: internal!.loading, error: classified.message, errorCode: classified.code }),\n );\n self._notifyAsync();\n\n if (__DEV__ && self._activeOps) {\n const c = (self._activeOps.get(key) ?? 1) - 1;\n if (c <= 0) self._activeOps.delete(key);\n else self._activeOps.set(key, c);\n }\n\n // Re-throw to preserve standard Promise rejection\n throw error;\n },\n );\n };\n\n wrappedKeys.push(key);\n (self as any)[key] = wrapper;\n });\n\n // Register cleanup for disposal\n if (wrappedKeys.length > 0) {\n this.addCleanup(() => {\n // Snapshot active ops for ghost check before clearing\n const opsSnapshot = __DEV__ && self._activeOps ? new Map(self._activeOps) : null;\n\n // Swap all wrapped methods to no-ops (with DEV warning)\n for (const k of wrappedKeys) {\n if (__DEV__) {\n (self as any)[k] = () => {\n console.warn(`[mvc-kit] \"${k}\" called after dispose — ignored.`);\n return undefined;\n };\n } else {\n (self as any)[k] = () => undefined;\n }\n }\n\n // Clear async state\n self._asyncListeners.clear();\n self._asyncStates.clear();\n self._asyncSnapshots.clear();\n\n // DEV: schedule ghost check\n if (__DEV__ && opsSnapshot && opsSnapshot.size > 0) {\n self._scheduleGhostCheck(opsSnapshot);\n }\n });\n }\n }\n\n private _scheduleGhostCheck(opsSnapshot: Map<string, number>): void {\n if (!__DEV__) return;\n setTimeout(() => {\n for (const [key, count] of opsSnapshot) {\n console.warn(\n `[mvc-kit] Ghost async operation detected: \"${key}\" had ${count} ` +\n `pending call(s) when the ViewModel was disposed. ` +\n `Consider using disposeSignal to cancel in-flight work.`\n );\n }\n }, (this.constructor as typeof ViewModel).GHOST_TIMEOUT);\n }\n\n // ── Auto-tracking internals ────────────────────────────────────\n\n /**\n * Installs a context-sensitive state getter on the instance.\n *\n * During getter tracking (_stateTracking is active): returns a Proxy\n * that records which state properties are accessed.\n *\n * Otherwise: returns the frozen state object directly. This is critical\n * for React's useSyncExternalStore — it needs a changing reference to\n * detect state updates and trigger re-renders.\n */\n private _installStateProxy(): void {\n const stateProxy = new Proxy({} as S, {\n get: (_, prop: string) => {\n this._stateTracking?.add(prop);\n return (this._state as any)[prop];\n },\n ownKeys: () => Reflect.ownKeys(this._state as object),\n getOwnPropertyDescriptor: (_, prop) =>\n Reflect.getOwnPropertyDescriptor(this._state as object, prop),\n set: () => {\n throw new Error('Cannot mutate state directly. Use set() instead.');\n },\n has: (_, prop) => prop in (this._state as object),\n });\n\n Object.defineProperty(this, 'state', {\n get: () => {\n if (this._stateTracking) return stateProxy;\n return this._state;\n },\n configurable: true,\n enumerable: true,\n });\n }\n\n /**\n * Scans own instance properties for Subscribable objects and sets up\n * automatic dependency tracking for each one found.\n *\n * For each subscribable member:\n * 1. Subscribe to it. On notification: bump its tracked revision\n * AND the VM's global revision, then force a new state reference\n * and notify listeners so React re-renders.\n * 2. Replace the instance property with a getter that participates\n * in dependency tracking.\n * 3. Register unsubscribe in the dispose chain.\n *\n * Called during init(), AFTER all subclass property initializers\n * have run (they execute during the constructor, before init()).\n */\n private _trackSubscribables(): void {\n for (const key of Object.getOwnPropertyNames(this)) {\n const value = (this as any)[key];\n if (!isAutoTrackable(value)) continue;\n\n const tracked: TrackedSource = {\n source: value,\n revision: 0,\n unsubscribe: value.subscribe(() => {\n if (this._disposed) return;\n\n // Source notified — bump revisions for getter invalidation\n tracked.revision++;\n this._revision++;\n\n // Force a new state reference so React's useSyncExternalStore\n // detects the change and triggers a re-render. State values\n // are unchanged, but getters may return different results.\n this._state = Object.freeze({ ...this._state });\n\n for (const listener of this._listeners) {\n listener(this._state, this._state);\n }\n }),\n };\n\n this._trackedSources.set(key, tracked);\n\n // Replace the instance property with a tracking getter.\n // The original value is captured in the closure.\n Object.defineProperty(this, key, {\n get: () => {\n this._sourceTracking?.set(key, tracked);\n return value;\n },\n configurable: true,\n enumerable: false,\n });\n }\n }\n\n /**\n * Walks the prototype chain from the subclass up to (but not including)\n * ViewModel.prototype. For every getter found, replaces it on the\n * instance with a memoized version that tracks dependencies and caches.\n *\n * Processing order: most-derived class first. If a subclass overrides\n * a parent getter, only the subclass version is memoized.\n */\n private _memoizeGetters(): void {\n const processed = new Set<string>();\n walkPrototypeChain(this, ViewModel.prototype, (key, desc) => {\n if (!desc.get || processed.has(key)) return;\n processed.add(key);\n this._wrapGetter(key, desc.get);\n });\n }\n\n /**\n * Replaces a single prototype getter with a memoized version on this\n * instance. The memoized getter tracks both state dependencies and\n * subscribable member dependencies, caching its result and\n * revalidating through a three-tier strategy:\n *\n * Tier 1 (fast): revision unchanged → return cached (1 int compare)\n * Tier 2 (medium): revision changed but this getter's deps didn't → return cached\n * Tier 3 (slow): at least one dep changed → full recompute with tracking\n */\n private _wrapGetter(key: string, original: () => unknown): void {\n // Per-getter cache state, private to this getter on this instance.\n let cached: unknown;\n let validatedAtRevision = -1;\n let stateDeps: Set<string> | undefined;\n let stateSnapshot: Map<string, unknown> | undefined;\n let sourceDeps: Map<string, number> | undefined;\n\n Object.defineProperty(this, key, {\n get: () => {\n // After dispose, return last cached value without re-executing\n if (this._disposed) return cached;\n\n // ── Tier 1: Fast path ───────────────────────────────────\n if (validatedAtRevision === this._revision) {\n return cached;\n }\n\n // ── Tier 2: Medium path ─────────────────────────────────\n if (stateDeps && stateSnapshot) {\n let fresh = true;\n\n // Check state deps by reference\n for (const [k, v] of stateSnapshot) {\n if ((this._state as any)[k] !== v) {\n fresh = false;\n break;\n }\n }\n\n // Check subscribable deps by revision\n if (fresh && sourceDeps) {\n for (const [memberKey, rev] of sourceDeps) {\n const ts = this._trackedSources.get(memberKey);\n if (ts && ts.revision !== rev) {\n fresh = false;\n break;\n }\n }\n }\n\n if (fresh) {\n validatedAtRevision = this._revision;\n return cached;\n }\n }\n\n // ── Tier 3: Slow path — full recompute ─────────────────\n // Save parent tracking context for nested getter composition\n const parentStateTracking = this._stateTracking;\n const parentSourceTracking = this._sourceTracking;\n\n this._stateTracking = new Set();\n this._sourceTracking = new Map();\n\n try {\n cached = original.call(this);\n } catch (e) {\n // Don't cache failed computations\n this._stateTracking = parentStateTracking;\n this._sourceTracking = parentSourceTracking;\n throw e;\n }\n\n stateDeps = this._stateTracking;\n const capturedSourceDeps = this._sourceTracking;\n\n // Restore parent tracking context\n this._stateTracking = parentStateTracking;\n this._sourceTracking = parentSourceTracking;\n\n // Bubble deps up to parent getter if nested\n if (parentStateTracking) {\n for (const d of stateDeps) parentStateTracking.add(d);\n }\n if (parentSourceTracking) {\n for (const [k, v] of capturedSourceDeps) {\n parentSourceTracking.set(k, v);\n }\n }\n\n // Snapshot state dep values for future medium-path comparison\n stateSnapshot = new Map();\n for (const d of stateDeps) {\n stateSnapshot.set(d, (this._state as any)[d]);\n }\n\n // Snapshot subscribable revisions\n sourceDeps = new Map();\n for (const [memberKey, tracked] of capturedSourceDeps) {\n sourceDeps.set(memberKey, tracked.revision);\n }\n\n validatedAtRevision = this._revision;\n\n return cached;\n },\n configurable: true,\n enumerable: true,\n });\n }\n}\n","import type { Listener, Updater, Subscribable, ValidationErrors } from './types';\n\n/**\n * Reactive entity with validation and dirty tracking.\n */\nexport abstract class Model<S extends object> implements Subscribable<S> {\n private _state: Readonly<S>;\n private _committed: Readonly<S>;\n private _disposed = false;\n private _initialized = false;\n private _listeners = new Set<Listener<S>>();\n private _abortController: AbortController | null = null;\n private _cleanups: (() => void)[] | null = null;\n\n constructor(initialState: S) {\n const frozen = Object.freeze({ ...initialState });\n this._state = frozen;\n this._committed = frozen;\n }\n\n get state(): Readonly<S> {\n return this._state;\n }\n\n /**\n * The baseline state for dirty tracking.\n */\n get committed(): Readonly<S> {\n return this._committed;\n }\n\n /**\n * True if current state differs from committed state.\n */\n get dirty(): boolean {\n return !this.shallowEqual(this._state, this._committed);\n }\n\n /**\n * Validation errors for the current state.\n */\n get errors(): ValidationErrors<S> {\n return this.validate(this._state);\n }\n\n /**\n * True if there are no validation errors.\n */\n get valid(): boolean {\n return Object.keys(this.errors).length === 0;\n }\n\n get disposed(): boolean {\n return this._disposed;\n }\n\n get initialized(): boolean {\n return this._initialized;\n }\n\n get disposeSignal(): AbortSignal {\n if (!this._abortController) {\n this._abortController = new AbortController();\n }\n return this._abortController.signal;\n }\n\n init(): void | Promise<void> {\n if (this._initialized || this._disposed) return;\n this._initialized = true;\n return this.onInit?.();\n }\n\n protected set(partialOrUpdater: Partial<S> | Updater<S>): void {\n if (this._disposed) {\n throw new Error('Cannot set state on disposed Model');\n }\n\n const partial =\n typeof partialOrUpdater === 'function'\n ? partialOrUpdater(this._state)\n : partialOrUpdater;\n\n // Check if any values actually changed (shallow equality)\n const keys = Object.keys(partial) as (keyof S)[];\n const hasChanges = keys.some(\n (key) => partial[key] !== this._state[key]\n );\n\n if (!hasChanges) {\n return;\n }\n\n const prev = this._state;\n const next = Object.freeze({ ...prev, ...partial });\n this._state = next;\n\n this.onSet?.(prev, next);\n\n for (const listener of this._listeners) {\n listener(next, prev);\n }\n }\n\n /**\n * Mark current state as the new baseline (not dirty).\n */\n commit(): void {\n if (this._disposed) {\n throw new Error('Cannot commit on disposed Model');\n }\n this._committed = this._state;\n }\n\n /**\n * Revert state to committed baseline.\n */\n rollback(): void {\n if (this._disposed) {\n throw new Error('Cannot rollback on disposed Model');\n }\n\n if (this.shallowEqual(this._state, this._committed)) {\n return;\n }\n\n const prev = this._state;\n this._state = this._committed;\n\n this.onSet?.(prev, this._state);\n\n for (const listener of this._listeners) {\n listener(this._state, prev);\n }\n }\n\n subscribe(listener: Listener<S>): () => void {\n if (this._disposed) {\n return () => {};\n }\n\n this._listeners.add(listener);\n\n return () => {\n this._listeners.delete(listener);\n };\n }\n\n dispose(): void {\n if (this._disposed) {\n return;\n }\n\n this._disposed = true;\n this._abortController?.abort();\n if (this._cleanups) {\n for (const fn of this._cleanups) fn();\n this._cleanups = null;\n }\n this.onDispose?.();\n this._listeners.clear();\n }\n\n /**\n * Override to provide validation logic.\n * Return an object mapping field keys to error messages.\n */\n protected validate(_state: Readonly<S>): ValidationErrors<S> {\n return {};\n }\n\n protected addCleanup(fn: () => void): void {\n if (!this._cleanups) {\n this._cleanups = [];\n }\n this._cleanups.push(fn);\n }\n\n protected subscribeTo<T>(source: Subscribable<T>, listener: Listener<T>): () => void {\n const unsubscribe = source.subscribe(listener);\n this.addCleanup(unsubscribe);\n return unsubscribe;\n }\n\n protected onSet?(prev: Readonly<S>, next: Readonly<S>): void;\n protected onInit?(): void | Promise<void>;\n protected onDispose?(): void;\n\n private shallowEqual(a: Readonly<S>, b: Readonly<S>): boolean {\n const keysA = Object.keys(a) as (keyof S)[];\n const keysB = Object.keys(b) as (keyof S)[];\n\n if (keysA.length !== keysB.length) {\n return false;\n }\n\n for (const key of keysA) {\n if (a[key] !== b[key]) {\n return false;\n }\n }\n\n return true;\n }\n}\n","import type { Listener, Subscribable } from './types';\n\ntype CollectionState<T> = readonly T[];\ntype CollectionListener<T> = Listener<CollectionState<T>>;\n\n/**\n * Reactive typed array with CRUD and query methods.\n */\nexport class Collection<T extends { id: string | number }> implements Subscribable<CollectionState<T>> {\n private _items: readonly T[] = [];\n private _disposed = false;\n private _listeners = new Set<CollectionListener<T>>();\n private _index = new Map<T['id'], T>();\n private _abortController: AbortController | null = null;\n private _cleanups: (() => void)[] | null = null;\n\n constructor(initialItems: T[] = []) {\n this._items = Object.freeze([...initialItems]);\n this.rebuildIndex();\n }\n\n /**\n * Alias for Subscribable compatibility.\n */\n get state(): readonly T[] {\n return this._items;\n }\n\n get items(): readonly T[] {\n return this._items;\n }\n\n get length(): number {\n return this._items.length;\n }\n\n get disposed(): boolean {\n return this._disposed;\n }\n\n get disposeSignal(): AbortSignal {\n if (!this._abortController) {\n this._abortController = new AbortController();\n }\n return this._abortController.signal;\n }\n\n // ── CRUD Methods (notify listeners) ──\n\n /**\n * Add one or more items.\n */\n add(...items: T[]): void {\n if (this._disposed) {\n throw new Error('Cannot add to disposed Collection');\n }\n\n if (items.length === 0) {\n return;\n }\n\n const prev = this._items;\n this._items = Object.freeze([...prev, ...items]);\n\n for (const item of items) {\n this._index.set(item.id, item);\n }\n\n this.notify(prev);\n }\n\n /**\n * Remove items by id(s).\n */\n remove(...ids: T['id'][]): void {\n if (this._disposed) {\n throw new Error('Cannot remove from disposed Collection');\n }\n\n if (ids.length === 0) {\n return;\n }\n\n const idSet = new Set(ids);\n const filtered = this._items.filter(item => !idSet.has(item.id));\n\n if (filtered.length === this._items.length) {\n return; // No items removed\n }\n\n const prev = this._items;\n this._items = Object.freeze(filtered);\n\n for (const id of ids) {\n this._index.delete(id);\n }\n\n this.notify(prev);\n }\n\n /**\n * Update an item by id with partial changes.\n */\n update(id: T['id'], changes: Partial<T>): void {\n if (this._disposed) {\n throw new Error('Cannot update disposed Collection');\n }\n\n const idx = this._items.findIndex(item => item.id === id);\n if (idx === -1) {\n return;\n }\n\n const existing = this._items[idx];\n const updated = { ...existing, ...changes, id }; // Ensure id is preserved\n\n // Check if anything actually changed\n const keys = Object.keys(changes) as (keyof T)[];\n const hasChanges = keys.some(key => changes[key] !== existing[key]);\n if (!hasChanges) {\n return;\n }\n\n const prev = this._items;\n const newItems = [...prev];\n newItems[idx] = updated;\n this._items = Object.freeze(newItems);\n this._index.set(id, updated);\n\n this.notify(prev);\n }\n\n /**\n * Replace all items.\n */\n reset(items: T[]): void {\n if (this._disposed) {\n throw new Error('Cannot reset disposed Collection');\n }\n\n const prev = this._items;\n this._items = Object.freeze([...items]);\n this.rebuildIndex();\n\n this.notify(prev);\n }\n\n /**\n * Remove all items.\n */\n clear(): void {\n if (this._disposed) {\n throw new Error('Cannot clear disposed Collection');\n }\n\n if (this._items.length === 0) {\n return;\n }\n\n const prev = this._items;\n this._items = Object.freeze([]);\n this._index.clear();\n\n this.notify(prev);\n }\n\n /**\n * Snapshot current state, apply callback mutations, and return a rollback function.\n * Rollback restores items to pre-callback state regardless of later mutations.\n */\n optimistic(callback: () => void): () => void {\n if (this._disposed) {\n throw new Error('Cannot perform optimistic update on disposed Collection');\n }\n\n const snapshot = this._items;\n callback();\n\n let rolledBack = false;\n return () => {\n if (rolledBack || this._disposed) return;\n rolledBack = true;\n\n const prev = this._items;\n this._items = snapshot;\n this.rebuildIndex();\n this.notify(prev);\n };\n }\n\n // ── Query Methods (pure, no notification) ──\n\n /**\n * Get item by id.\n */\n get(id: T['id']): T | undefined {\n return this._index.get(id);\n }\n\n /**\n * Check if item exists by id.\n */\n has(id: T['id']): boolean {\n return this._index.has(id);\n }\n\n /**\n * Find first item matching predicate.\n */\n find(predicate: (item: T) => boolean): T | undefined {\n return this._items.find(predicate);\n }\n\n /**\n * Filter items matching predicate.\n */\n filter(predicate: (item: T) => boolean): readonly T[] {\n return this._items.filter(predicate);\n }\n\n /**\n * Return sorted copy.\n */\n sorted(compareFn: (a: T, b: T) => number): readonly T[] {\n return [...this._items].sort(compareFn);\n }\n\n /**\n * Map items to new array.\n */\n map<U>(fn: (item: T) => U): readonly U[] {\n return this._items.map(fn);\n }\n\n // ── Subscribable interface ──\n\n subscribe(listener: CollectionListener<T>): () => void {\n if (this._disposed) {\n return () => {};\n }\n\n this._listeners.add(listener);\n\n return () => {\n this._listeners.delete(listener);\n };\n }\n\n dispose(): void {\n if (this._disposed) {\n return;\n }\n\n this._disposed = true;\n this._abortController?.abort();\n if (this._cleanups) {\n for (const fn of this._cleanups) fn();\n this._cleanups = null;\n }\n this.onDispose?.();\n this._listeners.clear();\n this._index.clear();\n }\n\n protected addCleanup(fn: () => void): void {\n if (!this._cleanups) {\n this._cleanups = [];\n }\n this._cleanups.push(fn);\n }\n\n protected onDispose?(): void;\n\n private notify(prev: readonly T[]): void {\n for (const listener of this._listeners) {\n listener(this._items, prev);\n }\n }\n\n private rebuildIndex(): void {\n this._index.clear();\n for (const item of this._items) {\n this._index.set(item.id, item);\n }\n }\n}\n","import type { Disposable, Subscribable, Listener } from './types';\n\n/**\n * Base class for stateless orchestrators.\n * Controllers coordinate between ViewModels, Models, and Services.\n */\nexport abstract class Controller implements Disposable {\n private _disposed = false;\n private _initialized = false;\n private _abortController: AbortController | null = null;\n private _cleanups: (() => void)[] | null = null;\n\n get disposed(): boolean {\n return this._disposed;\n }\n\n get initialized(): boolean {\n return this._initialized;\n }\n\n get disposeSignal(): AbortSignal {\n if (!this._abortController) {\n this._abortController = new AbortController();\n }\n return this._abortController.signal;\n }\n\n init(): void | Promise<void> {\n if (this._initialized || this._disposed) return;\n this._initialized = true;\n return this.onInit?.();\n }\n\n dispose(): void {\n if (this._disposed) {\n return;\n }\n\n this._disposed = true;\n this._abortController?.abort();\n if (this._cleanups) {\n for (const fn of this._cleanups) fn();\n this._cleanups = null;\n }\n this.onDispose?.();\n }\n\n protected addCleanup(fn: () => void): void {\n if (!this._cleanups) {\n this._cleanups = [];\n }\n this._cleanups.push(fn);\n }\n\n protected subscribeTo<T>(source: Subscribable<T>, listener: Listener<T>): () => void {\n const unsubscribe = source.subscribe(listener);\n this.addCleanup(unsubscribe);\n return unsubscribe;\n }\n\n protected onInit?(): void | Promise<void>;\n protected onDispose?(): void;\n}\n","import type { Disposable } from './types';\n\n/**\n * Base class for non-reactive infrastructure services.\n * Services encapsulate external dependencies like APIs, storage, etc.\n */\nexport abstract class Service implements Disposable {\n private _disposed = false;\n private _initialized = false;\n private _abortController: AbortController | null = null;\n private _cleanups: (() => void)[] | null = null;\n\n get disposed(): boolean {\n return this._disposed;\n }\n\n get initialized(): boolean {\n return this._initialized;\n }\n\n get disposeSignal(): AbortSignal {\n if (!this._abortController) {\n this._abortController = new AbortController();\n }\n return this._abortController.signal;\n }\n\n init(): void | Promise<void> {\n if (this._initialized || this._disposed) return;\n this._initialized = true;\n return this.onInit?.();\n }\n\n dispose(): void {\n if (this._disposed) {\n return;\n }\n\n this._disposed = true;\n this._abortController?.abort();\n if (this._cleanups) {\n for (const fn of this._cleanups) fn();\n this._cleanups = null;\n }\n this.onDispose?.();\n }\n\n protected addCleanup(fn: () => void): void {\n if (!this._cleanups) {\n this._cleanups = [];\n }\n this._cleanups.push(fn);\n }\n\n protected onInit?(): void | Promise<void>;\n protected onDispose?(): void;\n}\n","import type { Listener, Subscribable, Disposable, Initializable } from './types';\n\nconst __DEV__ = typeof __MVC_KIT_DEV__ !== 'undefined' && __MVC_KIT_DEV__;\n\n// ── Types ─────────────────────────────────────────────────────────\n\nexport interface ChannelStatus {\n readonly connected: boolean;\n readonly reconnecting: boolean;\n readonly attempt: number;\n readonly error: string | null;\n}\n\ntype Handler<T> = (payload: T) => void;\n\nconst enum ConnectionState {\n Idle,\n Connecting,\n Connected,\n Reconnecting,\n Disposed,\n}\n\nconst INITIAL_STATUS: ChannelStatus = Object.freeze({\n connected: false,\n reconnecting: false,\n attempt: 0,\n error: null,\n});\n\n// ── Channel ───────────────────────────────────────────────────────\n\nexport abstract class Channel<M extends Record<string, any>>\n implements Subscribable<ChannelStatus>, Initializable, Disposable\n{\n // Static config (subclass overrides)\n static RECONNECT_BASE = 1000;\n static RECONNECT_MAX = 30000;\n static RECONNECT_FACTOR = 2;\n static MAX_ATTEMPTS = Infinity;\n\n // ── Internal state ──────────────────────────────────────────────\n private _status: ChannelStatus = INITIAL_STATUS;\n private _connState: ConnectionState = ConnectionState.Idle;\n private _disposed = false;\n private _initialized = false;\n private _listeners = new Set<Listener<ChannelStatus>>();\n private _handlers = new Map<keyof M, Set<Handler<unknown>>>();\n private _abortController: AbortController | null = null;\n private _connectAbort: AbortController | null = null;\n private _reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private _cleanups: (() => void)[] | null = null;\n\n // ── Subscribable<ChannelStatus> ─────────────────────────────────\n\n get state(): Readonly<ChannelStatus> {\n return this._status;\n }\n\n subscribe(listener: Listener<ChannelStatus>): () => void {\n if (this._disposed) return () => {};\n this._listeners.add(listener);\n return () => { this._listeners.delete(listener); };\n }\n\n // ── Disposable / Initializable ──────────────────────────────────\n\n get disposed(): boolean {\n return this._disposed;\n }\n\n get initialized(): boolean {\n return this._initialized;\n }\n\n get disposeSignal(): AbortSignal {\n if (!this._abortController) {\n this._abortController = new AbortController();\n }\n return this._abortController.signal;\n }\n\n init(): void | Promise<void> {\n if (this._initialized || this._disposed) return;\n this._initialized = true;\n return this.onInit?.();\n }\n\n dispose(): void {\n if (this._disposed) return;\n this._disposed = true;\n this._connState = ConnectionState.Disposed;\n\n // Cancel pending reconnect\n if (this._reconnectTimer !== null) {\n clearTimeout(this._reconnectTimer);\n this._reconnectTimer = null;\n }\n\n // Abort per-connection signal\n this._connectAbort?.abort();\n this._connectAbort = null;\n\n // Abort dispose signal\n this._abortController?.abort();\n\n // Close transport\n try { this.close(); } catch { /* swallow close errors during dispose */ }\n\n // Run cleanups\n if (this._cleanups) {\n for (const fn of this._cleanups) fn();\n this._cleanups = null;\n }\n\n this.onDispose?.();\n this._listeners.clear();\n this._handlers.clear();\n }\n\n // ── Subclass contract ───────────────────────────────────────────\n\n protected abstract open(signal: AbortSignal): void | Promise<void>;\n protected abstract close(): void;\n\n // ── Connection control ──────────────────────────────────────────\n\n connect(): void {\n if (this._disposed) {\n if (__DEV__) {\n console.warn('[mvc-kit] connect() called after dispose — ignored.');\n }\n return;\n }\n if (__DEV__ && !this._initialized) {\n console.warn('[mvc-kit] connect() called before init().');\n }\n if (\n this._connState === ConnectionState.Connecting ||\n this._connState === ConnectionState.Connected\n ) {\n return;\n }\n\n // Cancel any pending reconnect\n if (this._reconnectTimer !== null) {\n clearTimeout(this._reconnectTimer);\n this._reconnectTimer = null;\n }\n\n this._attemptConnect(0);\n }\n\n disconnect(): void {\n if (this._disposed) return;\n\n // Cancel pending reconnect\n if (this._reconnectTimer !== null) {\n clearTimeout(this._reconnectTimer);\n this._reconnectTimer = null;\n }\n\n // Abort current connection attempt\n this._connectAbort?.abort();\n this._connectAbort = null;\n\n // Close transport\n if (\n this._connState === ConnectionState.Connected ||\n this._connState === ConnectionState.Connecting\n ) {\n this._connState = ConnectionState.Idle;\n try { this.close(); } catch { /* swallow */ }\n } else {\n this._connState = ConnectionState.Idle;\n }\n\n this._setStatus({ connected: false, reconnecting: false, attempt: 0, error: null });\n }\n\n // ── Subclass signals ────────────────────────────────────────────\n\n protected receive<K extends keyof M>(type: K, payload: M[K]): void {\n if (this._disposed) {\n if (__DEV__) {\n console.warn(`[mvc-kit] receive(\"${String(type)}\") called after dispose — ignored.`);\n }\n return;\n }\n\n const handlers = this._handlers.get(type);\n if (handlers) {\n for (const handler of handlers) {\n handler(payload);\n }\n }\n }\n\n protected disconnected(): void {\n if (this._disposed) return;\n // Only trigger reconnect from connected or connecting states\n if (\n this._connState !== ConnectionState.Connected &&\n this._connState !== ConnectionState.Connecting\n ) {\n return;\n }\n\n this._connectAbort?.abort();\n this._connectAbort = null;\n\n this._connState = ConnectionState.Reconnecting;\n this._scheduleReconnect(1);\n }\n\n // ── Consumer API ────────────────────────────────────────────────\n\n on<K extends keyof M>(type: K, handler: Handler<M[K]>): () => void {\n if (this._disposed) return () => {};\n\n let handlers = this._handlers.get(type);\n if (!handlers) {\n handlers = new Set();\n this._handlers.set(type, handlers);\n }\n handlers.add(handler as Handler<unknown>);\n\n return () => { handlers!.delete(handler as Handler<unknown>); };\n }\n\n once<K extends keyof M>(type: K, handler: Handler<M[K]>): () => void {\n const unsubscribe = this.on(type, (payload) => {\n unsubscribe();\n handler(payload);\n });\n return unsubscribe;\n }\n\n // ── Infrastructure ──────────────────────────────────────────────\n\n protected addCleanup(fn: () => void): void {\n if (!this._cleanups) {\n this._cleanups = [];\n }\n this._cleanups.push(fn);\n }\n\n protected subscribeTo<T>(source: Subscribable<T>, listener: Listener<T>): () => void {\n const unsubscribe = source.subscribe(listener);\n this.addCleanup(unsubscribe);\n return unsubscribe;\n }\n\n protected onInit?(): void | Promise<void>;\n protected onDispose?(): void;\n\n // ── Backoff ─────────────────────────────────────────────────────\n\n protected _calculateDelay(attempt: number): number {\n const ctor = this.constructor as typeof Channel;\n const capped = Math.min(\n ctor.RECONNECT_BASE * Math.pow(ctor.RECONNECT_FACTOR, attempt),\n ctor.RECONNECT_MAX,\n );\n return Math.random() * capped;\n }\n\n // ── Internals ───────────────────────────────────────────────────\n\n private _setStatus(next: ChannelStatus): void {\n const prev = this._status;\n if (\n prev.connected === next.connected &&\n prev.reconnecting === next.reconnecting &&\n prev.attempt === next.attempt &&\n prev.error === next.error\n ) {\n return;\n }\n\n this._status = Object.freeze(next);\n for (const listener of this._listeners) {\n listener(this._status, prev);\n }\n }\n\n private _attemptConnect(attempt: number): void {\n if (this._disposed) return;\n\n this._connState = ConnectionState.Connecting;\n\n // Create per-connection abort controller\n this._connectAbort?.abort();\n this._connectAbort = new AbortController();\n\n const signal = this._abortController\n ? AbortSignal.any([this._abortController.signal, this._connectAbort.signal])\n : this._connectAbort.signal;\n\n this._setStatus({\n connected: false,\n reconnecting: attempt > 0,\n attempt,\n error: null,\n });\n\n let result: void | Promise<void>;\n try {\n result = this.open(signal);\n } catch (e) {\n this._onOpenFailed(attempt, e);\n return;\n }\n\n if (result && typeof (result as Promise<void>).then === 'function') {\n (result as Promise<void>).then(\n () => this._onOpenSucceeded(),\n (e) => this._onOpenFailed(attempt, e),\n );\n } else {\n this._onOpenSucceeded();\n }\n }\n\n private _onOpenSucceeded(): void {\n if (this._disposed) return;\n // Only transition if we're still connecting (disconnect may have been called)\n if (this._connState !== ConnectionState.Connecting) return;\n\n this._connState = ConnectionState.Connected;\n this._setStatus({\n connected: true,\n reconnecting: false,\n attempt: 0,\n error: null,\n });\n }\n\n private _onOpenFailed(attempt: number, error: unknown): void {\n if (this._disposed) return;\n // If disconnect was called during open, don't reconnect\n if (this._connState === ConnectionState.Idle) return;\n\n this._connectAbort?.abort();\n this._connectAbort = null;\n\n this._connState = ConnectionState.Reconnecting;\n this._scheduleReconnect(attempt + 1, error);\n }\n\n private _scheduleReconnect(attempt: number, error?: unknown): void {\n const ctor = this.constructor as typeof Channel;\n\n if (attempt > ctor.MAX_ATTEMPTS) {\n this._connState = ConnectionState.Idle;\n this._setStatus({\n connected: false,\n reconnecting: false,\n attempt,\n error: error instanceof Error ? error.message : 'Max reconnection attempts reached',\n });\n return;\n }\n\n const errorMsg = error instanceof Error ? error.message : (error ? String(error) : null);\n\n this._setStatus({\n connected: false,\n reconnecting: true,\n attempt,\n error: errorMsg,\n });\n\n const delay = this._calculateDelay(attempt - 1);\n this._reconnectTimer = setTimeout(() => {\n this._reconnectTimer = null;\n this._attemptConnect(attempt);\n }, delay);\n }\n}\n"],"names":["HttpError","status","message","isAbortError","error","classifyHttpStatus","isResponseLike","value","classifyError","__DEV__","isAutoTrackable","walkPrototypeChain","instance","stopAt","visitor","proto","descriptors","key","desc","DEFAULT_TASK_STATE","RESERVED_ASYNC_KEYS","LIFECYCLE_HOOKS","ViewModel","initialState","EventBus","partialOrUpdater","partial","prev","next","listener","event","payload","fn","newState","source","unsubscribe","self","_","prop","tracked","processed","wrappedKeys","original","pruned","wrapper","args","result","e","internal","c","classified","opsSnapshot","k","count","stateProxy","cached","validatedAtRevision","stateDeps","stateSnapshot","sourceDeps","fresh","v","memberKey","rev","ts","parentStateTracking","parentSourceTracking","capturedSourceDeps","d","Model","frozen","_state","a","b","keysA","keysB","Collection","initialItems","items","item","ids","idSet","filtered","id","changes","idx","existing","updated","newItems","callback","snapshot","rolledBack","predicate","compareFn","Controller","Service","INITIAL_STATUS","Channel","type","handlers","handler","attempt","ctor","capped","signal","errorMsg","delay"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mvc-kit.js","sources":["../src/errors.ts","../src/ViewModel.ts","../src/Model.ts","../src/Collection.ts","../src/Controller.ts","../src/Service.ts","../src/Channel.ts"],"sourcesContent":["/**\n * Canonical application error shape for consistent error handling.\n */\nexport interface AppError {\n code:\n | 'unauthorized'\n | 'forbidden'\n | 'not_found'\n | 'validation'\n | 'rate_limited'\n | 'server_error'\n | 'network'\n | 'timeout'\n | 'abort'\n | 'unknown';\n message: string;\n status?: number;\n original?: unknown;\n}\n\n/**\n * Typed HTTP error for services to throw.\n */\nexport class HttpError extends Error {\n constructor(\n public readonly status: number,\n message?: string\n ) {\n super(message ?? `HTTP ${status}`);\n this.name = 'HttpError';\n }\n}\n\n/**\n * Guard for AbortError — the most-repeated check in async ViewModels.\n * Uses duck-typing so the core lib doesn't require DOM types.\n */\nexport function isAbortError(error: unknown): boolean {\n return error instanceof Error && error.name === 'AbortError';\n}\n\nfunction classifyHttpStatus(\n status: number\n): AppError['code'] {\n if (status === 401) return 'unauthorized';\n if (status === 403) return 'forbidden';\n if (status === 404) return 'not_found';\n if (status === 422) return 'validation';\n if (status === 429) return 'rate_limited';\n if (status >= 500) return 'server_error';\n return 'unknown';\n}\n\nfunction isResponseLike(value: unknown): value is { status: number; statusText: string } {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as Record<string, unknown>).status === 'number' &&\n typeof (value as Record<string, unknown>).statusText === 'string' &&\n !(value instanceof Error)\n );\n}\n\n/**\n * Maps raw errors to a canonical AppError shape.\n */\nexport function classifyError(error: unknown): AppError {\n // AbortError (fetch cancelled / DOMException)\n if (error instanceof Error && error.name === 'AbortError') {\n return {\n code: 'abort',\n message: 'Request was aborted',\n original: error,\n };\n }\n\n // HttpError (thrown by services)\n if (error instanceof HttpError) {\n return {\n code: classifyHttpStatus(error.status),\n message: error.message,\n status: error.status,\n original: error,\n };\n }\n\n // Raw Response object (duck-typed: has status + statusText, is not an Error)\n if (isResponseLike(error)) {\n return {\n code: classifyHttpStatus(error.status),\n message: error.statusText || `HTTP ${error.status}`,\n status: error.status,\n original: error,\n };\n }\n\n // Network error (fetch failure)\n if (\n error instanceof TypeError &&\n error.message.toLowerCase().includes('fetch')\n ) {\n return {\n code: 'network',\n message: error.message,\n original: error,\n };\n }\n\n // Timeout error\n if (error instanceof Error && error.name === 'TimeoutError') {\n return {\n code: 'timeout',\n message: error.message,\n original: error,\n };\n }\n\n // Generic Error fallback\n if (error instanceof Error) {\n return {\n code: 'unknown',\n message: error.message,\n original: error,\n };\n }\n\n // Non-Error fallback\n return {\n code: 'unknown',\n message: String(error),\n original: error,\n };\n}\n","import { EventBus } from './EventBus';\nimport { isAbortError, classifyError } from './errors';\nimport type { Listener, Updater, Subscribable, TaskState } from './types';\n\n// Re-export for backwards compatibility\nexport type { Listener, Updater } from './types';\n\nconst __DEV__ = typeof __MVC_KIT_DEV__ !== 'undefined' && __MVC_KIT_DEV__;\n\n// ── Auto-tracking types ──────────────────────────────────────────\n\ninterface TrackedSource {\n source: { subscribe(cb: () => void): () => void };\n revision: number;\n unsubscribe: () => void;\n}\n\n// ── Auto-tracking utilities ──────────────────────────────────────\n\nfunction isAutoTrackable(value: unknown): boolean {\n return (\n value !== null &&\n typeof value === 'object' &&\n typeof (value as any).subscribe === 'function'\n );\n}\n\n/**\n * Walk the prototype chain from `instance`'s class up to (but not including)\n * `stopAt`. Calls `visitor` for each own property descriptor found.\n *\n * Shared utility — also used by RFC 2's _wrapMethods().\n */\nexport function walkPrototypeChain(\n instance: object,\n stopAt: object,\n visitor: (key: string, desc: PropertyDescriptor, proto: object) => void,\n): void {\n let proto = Object.getPrototypeOf(instance);\n while (proto && proto !== stopAt) {\n const descriptors = Object.getOwnPropertyDescriptors(proto);\n for (const [key, desc] of Object.entries(descriptors)) {\n if (key === 'constructor') continue;\n visitor(key, desc, proto);\n }\n proto = Object.getPrototypeOf(proto);\n }\n}\n\n// ── Async tracking types ─────────────────────────────────────────\n\nconst DEFAULT_TASK_STATE: TaskState = Object.freeze({ loading: false, error: null, errorCode: null });\n\nexport type AsyncMethodKeys<T, Base = ViewModel<any, any>> = {\n [K in Exclude<keyof T, keyof Base>]: T[K] extends (...args: any[]) => Promise<any> ? K : never;\n}[Exclude<keyof T, keyof Base>];\n\ntype AsyncMap<T> = {\n readonly [K in AsyncMethodKeys<T>]: TaskState;\n};\n\ninterface InternalTaskState {\n loading: boolean;\n error: string | null;\n errorCode: TaskState['errorCode'];\n count: number;\n}\n\nconst RESERVED_ASYNC_KEYS = ['async', 'subscribeAsync'] as const;\nconst LIFECYCLE_HOOKS = new Set(['onInit', 'onSet', 'onDispose']);\n\n// ── ViewModel ────────────────────────────────────────────────────\n\n/**\n * Reactive state container with computed getters, automatic async tracking, and typed events.\n * Subclass and define state shape, getters, and action methods. Use with `useLocal` in React.\n */\nexport abstract class ViewModel<S extends object = {}, E extends Record<string, any> = {}> implements Subscribable<S> {\n private _state: Readonly<S>;\n private _initialState: Readonly<S>;\n private _disposed = false;\n private _initialized = false;\n private _listeners = new Set<Listener<S>>();\n private _abortController: AbortController | null = null;\n private _cleanups: (() => void)[] | null = null;\n private _subscriptionCleanups: (() => void)[] | null = null;\n private _eventBus: EventBus<E> | null = null;\n\n // ── Reactive derived state (RFC 1) ─────────────────────────────\n private _revision = 0;\n private _stateTracking: Set<string> | null = null;\n private _sourceTracking: Map<string, TrackedSource> | null = null;\n private _trackedSources = new Map<string, TrackedSource>();\n\n // ── Async tracking (RFC 2) ──────────────────────────────────────\n private _asyncStates = new Map<string, InternalTaskState>();\n private _asyncSnapshots = new Map<string, TaskState>();\n private _asyncListeners = new Set<() => void>();\n private _asyncProxy: AsyncMap<this> | null = null;\n private _activeOps: Map<string, number> | null = null;\n\n /** DEV-only timeout (ms) for detecting ghost async operations after dispose. */\n static GHOST_TIMEOUT = 3000;\n\n constructor(initialState: S) {\n this._state = Object.freeze({ ...initialState });\n this._initialState = this._state;\n this._guardReservedKeys();\n }\n\n /** Current frozen state object. */\n get state(): Readonly<S> {\n return this._state;\n }\n\n /** Whether this instance has been disposed. */\n get disposed(): boolean {\n return this._disposed;\n }\n\n /** Whether init() has been called. */\n get initialized(): boolean {\n return this._initialized;\n }\n\n /** AbortSignal that fires when this instance is disposed. Lazily created. */\n get disposeSignal(): AbortSignal {\n if (!this._abortController) {\n this._abortController = new AbortController();\n }\n return this._abortController.signal;\n }\n\n /** Lazily-created typed EventBus for emitting and subscribing to events. */\n get events(): EventBus<E> {\n if (!this._eventBus) {\n this._eventBus = new EventBus<E>();\n }\n return this._eventBus;\n }\n\n /** Initializes the instance. Called automatically by React hooks after mount. */\n init(): void | Promise<void> {\n if (this._initialized || this._disposed) return;\n this._initialized = true;\n this._trackSubscribables();\n this._installStateProxy();\n this._memoizeGetters();\n this._wrapMethods();\n return this.onInit?.();\n }\n\n /**\n * Merges partial state into current state. If no values actually\n * changed by reference, this is a no-op.\n *\n * Triggers React re-render via listener notification. Called when:\n * - User code calls set() to update source state\n *\n * NOT called for subscribable member notifications — those use\n * a separate notification path (see _trackSubscribables).\n */\n protected set(partialOrUpdater: Partial<S> | Updater<S>): void {\n if (this._disposed) return;\n\n // __DEV__ guard: set() inside a getter would cause infinite loops.\n // After init(), getters are auto-memoized; set() → notify → recompute → set() → ∞\n if (__DEV__ && this._stateTracking) {\n console.error(\n '[mvc-kit] set() called inside a getter. ' +\n 'Getters must be pure — they read state and return a value. ' +\n 'They must never call set(), which would cause an infinite ' +\n 'render loop. Move this logic to an action method.'\n );\n return;\n }\n\n const partial =\n typeof partialOrUpdater === 'function'\n ? partialOrUpdater(this._state)\n : partialOrUpdater;\n\n // Check if any values actually changed (shallow equality)\n const keys = Object.keys(partial) as (keyof S)[];\n const hasChanges = keys.some(\n (key) => partial[key] !== this._state[key]\n );\n\n if (!hasChanges) {\n return;\n }\n\n const prev = this._state;\n const next = Object.freeze({ ...prev, ...partial });\n this._state = next;\n this._revision++;\n\n this.onSet?.(prev, next);\n\n for (const listener of this._listeners) {\n listener(next, prev);\n }\n }\n\n /**\n * Emits a typed event via the internal EventBus.\n * Safe to call during dispose cleanup callbacks.\n * @protected\n */\n protected emit<K extends keyof E>(event: K, payload: E[K]): void {\n // During dispose sequence: _disposed is true but eventBus not yet disposed.\n // Cleanup callbacks can still emit. After eventBus.dispose(), this is a no-op.\n // If eventBus was never created, fall back to _disposed check.\n if (this._eventBus?.disposed ?? this._disposed) return;\n this.events.emit(event, payload);\n }\n\n /** Subscribes to state changes. Returns an unsubscribe function. */\n subscribe(listener: Listener<S>): () => void {\n if (this._disposed) {\n return () => {};\n }\n\n this._listeners.add(listener);\n\n return () => {\n this._listeners.delete(listener);\n };\n }\n\n /** Tears down the instance, releasing all subscriptions and resources. */\n dispose(): void {\n if (this._disposed) {\n return;\n }\n\n this._disposed = true;\n\n this._teardownSubscriptions();\n\n // Async tracking cleanup — handled by addCleanup registered in _wrapMethods()\n this._abortController?.abort();\n if (this._cleanups) {\n for (const fn of this._cleanups) fn();\n this._cleanups = null;\n }\n this._eventBus?.dispose();\n this.onDispose?.();\n this._listeners.clear();\n }\n\n /**\n * Resets state to initial values (or provided state), aborts in-flight work,\n * clears async tracking, and re-runs onInit().\n */\n reset(newState?: S): void | Promise<void> {\n if (this._disposed) return;\n\n // 1. Abort in-flight, lazy-recreate on next disposeSignal access\n this._abortController?.abort();\n this._abortController = null;\n\n this._teardownSubscriptions();\n\n // 2. Reset state\n this._state = newState ? Object.freeze({ ...newState }) : this._initialState;\n this._revision++;\n\n // 3. Clear async tracking (preserve listeners — React still subscribed)\n this._asyncStates.clear();\n this._asyncSnapshots.clear();\n this._notifyAsync();\n\n // 4. Re-track subscribable members (fresh subscriptions)\n this._trackSubscribables();\n\n // 5. Notify state listeners (React re-renders with new state)\n for (const listener of this._listeners) {\n listener(this._state, this._state);\n }\n\n // 6. Re-run onInit\n return this.onInit?.();\n }\n\n /**\n * Registers a cleanup function to be called on dispose. Used internally for things like method wrapper\n * cleanup and event bus disposal, but can also be used by subclasses for custom cleanup logic.\n * @param fn\n * @protected\n */\n protected addCleanup(fn: () => void): void {\n if (!this._cleanups) {\n this._cleanups = [];\n }\n this._cleanups.push(fn);\n }\n\n /** Subscribes to an external Subscribable with automatic cleanup on dispose. @protected */\n protected subscribeTo<T>(source: Subscribable<T>, listener: Listener<T>): () => void {\n const unsubscribe = source.subscribe(listener);\n if (!this._subscriptionCleanups) this._subscriptionCleanups = [];\n this._subscriptionCleanups.push(unsubscribe);\n return unsubscribe;\n }\n\n /** Lifecycle hook called after every set() with the previous state. @protected */\n protected onSet?(prev: Readonly<S>, next: Readonly<S>): void;\n /** Lifecycle hook called at the end of init(). Override to load initial data. @protected */\n protected onInit?(): void | Promise<void>;\n /** Lifecycle hook called during dispose(). Override for custom teardown. @protected */\n protected onDispose?(): void;\n\n // ── Async tracking API ──────────────────────────────────────────\n\n /** Proxy providing `TaskState` (loading, error, errorCode) per async method. */\n get async(): AsyncMap<this> {\n if (!this._asyncProxy) {\n const self = this;\n this._asyncProxy = new Proxy({} as AsyncMap<this>, {\n get(_, prop: string) {\n return self._asyncSnapshots.get(prop) ?? DEFAULT_TASK_STATE;\n },\n has(_, prop: string) {\n return self._asyncSnapshots.has(prop);\n },\n ownKeys() {\n return Array.from(self._asyncSnapshots.keys());\n },\n getOwnPropertyDescriptor(_, prop: string) {\n if (self._asyncSnapshots.has(prop)) {\n return { configurable: true, enumerable: true, value: self._asyncSnapshots.get(prop) };\n }\n return undefined;\n },\n });\n }\n return this._asyncProxy;\n }\n\n /** Subscribes to async state changes. Used by `useAsync` for React integration. */\n subscribeAsync(listener: () => void): () => void {\n if (this._disposed) return () => {};\n this._asyncListeners.add(listener);\n return () => { this._asyncListeners.delete(listener); };\n }\n\n private _notifyAsync(): void {\n for (const listener of this._asyncListeners) {\n listener();\n }\n }\n\n // ── Async tracking internals ────────────────────────────────────\n\n private _teardownSubscriptions(): void {\n for (const tracked of this._trackedSources.values()) tracked.unsubscribe();\n this._trackedSources.clear();\n\n if (this._subscriptionCleanups) {\n for (const fn of this._subscriptionCleanups) fn();\n this._subscriptionCleanups = null;\n }\n }\n\n private _guardReservedKeys(): void {\n // Prototype check (runs in constructor — catches method/getter definitions)\n walkPrototypeChain(this, ViewModel.prototype, (key) => {\n if (RESERVED_ASYNC_KEYS.includes(key as any)) {\n throw new Error(\n `[mvc-kit] \"${key}\" is a reserved property on ViewModel and cannot be overridden.`\n );\n }\n });\n }\n\n private _wrapMethods(): void {\n // Instance property check (class fields assigned after super())\n for (const key of RESERVED_ASYNC_KEYS) {\n if (Object.getOwnPropertyDescriptor(this, key)?.value !== undefined) {\n throw new Error(\n `[mvc-kit] \"${key}\" is a reserved property on ViewModel and cannot be overridden.`\n );\n }\n }\n\n const self = this;\n const processed = new Set<string>();\n const wrappedKeys: string[] = [];\n\n if (__DEV__) {\n this._activeOps = new Map();\n }\n\n walkPrototypeChain(this, ViewModel.prototype, (key, desc) => {\n // Skip getters/setters (owned by RFC 1 memoization)\n if (desc.get || desc.set) return;\n // Skip non-functions\n if (typeof desc.value !== 'function') return;\n // Skip _-prefixed (private convention)\n if (key.startsWith('_')) return;\n // Skip lifecycle hooks (managed by framework)\n if (LIFECYCLE_HOOKS.has(key)) return;\n // Most-derived wins\n if (processed.has(key)) return;\n processed.add(key);\n\n const original = desc.value as (...args: unknown[]) => unknown;\n let pruned = false;\n\n const wrapper = function (this: any, ...args: unknown[]) {\n // Disposed guard\n if (self._disposed) {\n if (__DEV__) {\n console.warn(`[mvc-kit] \"${key}\" called after dispose — ignored.`);\n }\n return undefined;\n }\n\n // Pre-init guard (DEV only — method still executes)\n if (__DEV__ && !self._initialized) {\n console.warn(\n `[mvc-kit] \"${key}\" called before init(). ` +\n `Async tracking is active only after init().`\n );\n }\n\n let result: unknown;\n try {\n result = original.apply(self, args);\n } catch (e) {\n // Sync throw — not tracked as async\n throw e;\n }\n\n // Sync detection: if not thenable, prune from async tracking\n if (!result || typeof (result as any).then !== 'function') {\n if (!pruned) {\n pruned = true;\n // Remove from async maps\n self._asyncStates.delete(key);\n self._asyncSnapshots.delete(key);\n // Replace wrapper with bound original for zero overhead\n (self as any)[key] = original.bind(self);\n }\n return result;\n }\n\n // ── Async tracking ──────────────────────────────────────\n let internal = self._asyncStates.get(key);\n if (!internal) {\n internal = { loading: false, error: null, errorCode: null, count: 0 };\n self._asyncStates.set(key, internal);\n }\n\n internal.count++;\n internal.loading = true;\n internal.error = null;\n internal.errorCode = null;\n self._asyncSnapshots.set(key, Object.freeze({ loading: true, error: null, errorCode: null }));\n self._notifyAsync();\n\n if (__DEV__ && self._activeOps) {\n self._activeOps.set(key, (self._activeOps.get(key) ?? 0) + 1);\n }\n\n return (result as Promise<unknown>).then(\n (value) => {\n if (self._disposed) return value;\n\n internal!.count--;\n internal!.loading = internal!.count > 0;\n self._asyncSnapshots.set(\n key,\n Object.freeze({ loading: internal!.loading, error: internal!.error, errorCode: internal!.errorCode }),\n );\n self._notifyAsync();\n\n if (__DEV__ && self._activeOps) {\n const c = (self._activeOps.get(key) ?? 1) - 1;\n if (c <= 0) self._activeOps.delete(key);\n else self._activeOps.set(key, c);\n }\n\n return value;\n },\n (error) => {\n // AbortError — silently swallow\n if (isAbortError(error)) {\n if (!self._disposed) {\n internal!.count--;\n internal!.loading = internal!.count > 0;\n self._asyncSnapshots.set(\n key,\n Object.freeze({ loading: internal!.loading, error: internal!.error, errorCode: internal!.errorCode }),\n );\n self._notifyAsync();\n }\n\n if (__DEV__ && self._activeOps) {\n const c = (self._activeOps.get(key) ?? 1) - 1;\n if (c <= 0) self._activeOps.delete(key);\n else self._activeOps.set(key, c);\n }\n\n return undefined;\n }\n\n // Disposed — fizzle silently\n if (self._disposed) return undefined;\n\n internal!.count--;\n internal!.loading = internal!.count > 0;\n const classified = classifyError(error);\n internal!.error = classified.message;\n internal!.errorCode = classified.code;\n self._asyncSnapshots.set(\n key,\n Object.freeze({ loading: internal!.loading, error: classified.message, errorCode: classified.code }),\n );\n self._notifyAsync();\n\n if (__DEV__ && self._activeOps) {\n const c = (self._activeOps.get(key) ?? 1) - 1;\n if (c <= 0) self._activeOps.delete(key);\n else self._activeOps.set(key, c);\n }\n\n // Re-throw to preserve standard Promise rejection\n throw error;\n },\n );\n };\n\n wrappedKeys.push(key);\n (self as any)[key] = wrapper;\n });\n\n // Register cleanup for disposal\n if (wrappedKeys.length > 0) {\n this.addCleanup(() => {\n // Snapshot active ops for ghost check before clearing\n const opsSnapshot = __DEV__ && self._activeOps ? new Map(self._activeOps) : null;\n\n // Swap all wrapped methods to no-ops (with DEV warning)\n for (const k of wrappedKeys) {\n if (__DEV__) {\n (self as any)[k] = () => {\n console.warn(`[mvc-kit] \"${k}\" called after dispose — ignored.`);\n return undefined;\n };\n } else {\n (self as any)[k] = () => undefined;\n }\n }\n\n // Clear async state\n self._asyncListeners.clear();\n self._asyncStates.clear();\n self._asyncSnapshots.clear();\n\n // DEV: schedule ghost check\n if (__DEV__ && opsSnapshot && opsSnapshot.size > 0) {\n self._scheduleGhostCheck(opsSnapshot);\n }\n });\n }\n }\n\n private _scheduleGhostCheck(opsSnapshot: Map<string, number>): void {\n if (!__DEV__) return;\n setTimeout(() => {\n for (const [key, count] of opsSnapshot) {\n console.warn(\n `[mvc-kit] Ghost async operation detected: \"${key}\" had ${count} ` +\n `pending call(s) when the ViewModel was disposed. ` +\n `Consider using disposeSignal to cancel in-flight work.`\n );\n }\n }, (this.constructor as typeof ViewModel).GHOST_TIMEOUT);\n }\n\n // ── Auto-tracking internals ────────────────────────────────────\n\n /**\n * Installs a context-sensitive state getter on the instance.\n *\n * During getter tracking (_stateTracking is active): returns a Proxy\n * that records which state properties are accessed.\n *\n * Otherwise: returns the frozen state object directly. This is critical\n * for React's useSyncExternalStore — it needs a changing reference to\n * detect state updates and trigger re-renders.\n */\n private _installStateProxy(): void {\n const stateProxy = new Proxy({} as S, {\n get: (_, prop: string) => {\n this._stateTracking?.add(prop);\n return (this._state as any)[prop];\n },\n ownKeys: () => Reflect.ownKeys(this._state as object),\n getOwnPropertyDescriptor: (_, prop) =>\n Reflect.getOwnPropertyDescriptor(this._state as object, prop),\n set: () => {\n throw new Error('Cannot mutate state directly. Use set() instead.');\n },\n has: (_, prop) => prop in (this._state as object),\n });\n\n Object.defineProperty(this, 'state', {\n get: () => {\n if (this._stateTracking) return stateProxy;\n return this._state;\n },\n configurable: true,\n enumerable: true,\n });\n }\n\n /**\n * Scans own instance properties for Subscribable objects and sets up\n * automatic dependency tracking for each one found.\n *\n * For each subscribable member:\n * 1. Subscribe to it. On notification: bump its tracked revision\n * AND the VM's global revision, then force a new state reference\n * and notify listeners so React re-renders.\n * 2. Replace the instance property with a getter that participates\n * in dependency tracking.\n * 3. Register unsubscribe in the dispose chain.\n *\n * Called during init(), AFTER all subclass property initializers\n * have run (they execute during the constructor, before init()).\n */\n private _trackSubscribables(): void {\n for (const key of Object.getOwnPropertyNames(this)) {\n const value = (this as any)[key];\n if (!isAutoTrackable(value)) continue;\n\n const tracked: TrackedSource = {\n source: value,\n revision: 0,\n unsubscribe: value.subscribe(() => {\n if (this._disposed) return;\n\n // Source notified — bump revisions for getter invalidation\n tracked.revision++;\n this._revision++;\n\n // Force a new state reference so React's useSyncExternalStore\n // detects the change and triggers a re-render. State values\n // are unchanged, but getters may return different results.\n this._state = Object.freeze({ ...this._state });\n\n for (const listener of this._listeners) {\n listener(this._state, this._state);\n }\n }),\n };\n\n this._trackedSources.set(key, tracked);\n\n // Replace the instance property with a tracking getter.\n // The original value is captured in the closure.\n Object.defineProperty(this, key, {\n get: () => {\n this._sourceTracking?.set(key, tracked);\n return value;\n },\n configurable: true,\n enumerable: false,\n });\n }\n }\n\n /**\n * Walks the prototype chain from the subclass up to (but not including)\n * ViewModel.prototype. For every getter found, replaces it on the\n * instance with a memoized version that tracks dependencies and caches.\n *\n * Processing order: most-derived class first. If a subclass overrides\n * a parent getter, only the subclass version is memoized.\n */\n private _memoizeGetters(): void {\n const processed = new Set<string>();\n walkPrototypeChain(this, ViewModel.prototype, (key, desc) => {\n if (!desc.get || processed.has(key)) return;\n processed.add(key);\n this._wrapGetter(key, desc.get);\n });\n }\n\n /**\n * Replaces a single prototype getter with a memoized version on this\n * instance. The memoized getter tracks both state dependencies and\n * subscribable member dependencies, caching its result and\n * revalidating through a three-tier strategy:\n *\n * Tier 1 (fast): revision unchanged → return cached (1 int compare)\n * Tier 2 (medium): revision changed but this getter's deps didn't → return cached\n * Tier 3 (slow): at least one dep changed → full recompute with tracking\n */\n private _wrapGetter(key: string, original: () => unknown): void {\n // Per-getter cache state, private to this getter on this instance.\n let cached: unknown;\n let validatedAtRevision = -1;\n let stateDeps: Set<string> | undefined;\n let stateSnapshot: Map<string, unknown> | undefined;\n let sourceDeps: Map<string, number> | undefined;\n\n Object.defineProperty(this, key, {\n get: () => {\n // After dispose, return last cached value without re-executing\n if (this._disposed) return cached;\n\n // ── Tier 1: Fast path ───────────────────────────────────\n if (validatedAtRevision === this._revision) {\n return cached;\n }\n\n // ── Tier 2: Medium path ─────────────────────────────────\n if (stateDeps && stateSnapshot) {\n let fresh = true;\n\n // Check state deps by reference\n for (const [k, v] of stateSnapshot) {\n if ((this._state as any)[k] !== v) {\n fresh = false;\n break;\n }\n }\n\n // Check subscribable deps by revision\n if (fresh && sourceDeps) {\n for (const [memberKey, rev] of sourceDeps) {\n const ts = this._trackedSources.get(memberKey);\n if (ts && ts.revision !== rev) {\n fresh = false;\n break;\n }\n }\n }\n\n if (fresh) {\n validatedAtRevision = this._revision;\n return cached;\n }\n }\n\n // ── Tier 3: Slow path — full recompute ─────────────────\n // Save parent tracking context for nested getter composition\n const parentStateTracking = this._stateTracking;\n const parentSourceTracking = this._sourceTracking;\n\n this._stateTracking = new Set();\n this._sourceTracking = new Map();\n\n try {\n cached = original.call(this);\n } catch (e) {\n // Don't cache failed computations\n this._stateTracking = parentStateTracking;\n this._sourceTracking = parentSourceTracking;\n throw e;\n }\n\n stateDeps = this._stateTracking;\n const capturedSourceDeps = this._sourceTracking;\n\n // Restore parent tracking context\n this._stateTracking = parentStateTracking;\n this._sourceTracking = parentSourceTracking;\n\n // Bubble deps up to parent getter if nested\n if (parentStateTracking) {\n for (const d of stateDeps) parentStateTracking.add(d);\n }\n if (parentSourceTracking) {\n for (const [k, v] of capturedSourceDeps) {\n parentSourceTracking.set(k, v);\n }\n }\n\n // Snapshot state dep values for future medium-path comparison\n stateSnapshot = new Map();\n for (const d of stateDeps) {\n stateSnapshot.set(d, (this._state as any)[d]);\n }\n\n // Snapshot subscribable revisions\n sourceDeps = new Map();\n for (const [memberKey, tracked] of capturedSourceDeps) {\n sourceDeps.set(memberKey, tracked.revision);\n }\n\n validatedAtRevision = this._revision;\n\n return cached;\n },\n configurable: true,\n enumerable: true,\n });\n }\n}\n","import type { Listener, Updater, Subscribable, ValidationErrors } from './types';\n\n/**\n * Reactive entity with validation and dirty tracking.\n */\nexport abstract class Model<S extends object> implements Subscribable<S> {\n private _state: Readonly<S>;\n private _committed: Readonly<S>;\n private _disposed = false;\n private _initialized = false;\n private _listeners = new Set<Listener<S>>();\n private _abortController: AbortController | null = null;\n private _cleanups: (() => void)[] | null = null;\n\n constructor(initialState: S) {\n const frozen = Object.freeze({ ...initialState });\n this._state = frozen;\n this._committed = frozen;\n }\n\n /** Current frozen state object. */\n get state(): Readonly<S> {\n return this._state;\n }\n\n /**\n * The baseline state for dirty tracking.\n */\n get committed(): Readonly<S> {\n return this._committed;\n }\n\n /**\n * True if current state differs from committed state.\n */\n get dirty(): boolean {\n return !this.shallowEqual(this._state, this._committed);\n }\n\n /**\n * Validation errors for the current state.\n */\n get errors(): ValidationErrors<S> {\n return this.validate(this._state);\n }\n\n /**\n * True if there are no validation errors.\n */\n get valid(): boolean {\n return Object.keys(this.errors).length === 0;\n }\n\n /** Whether this instance has been disposed. */\n get disposed(): boolean {\n return this._disposed;\n }\n\n /** Whether init() has been called. */\n get initialized(): boolean {\n return this._initialized;\n }\n\n /** AbortSignal that fires when this instance is disposed. Lazily created. */\n get disposeSignal(): AbortSignal {\n if (!this._abortController) {\n this._abortController = new AbortController();\n }\n return this._abortController.signal;\n }\n\n /** Initializes the instance. Called automatically by React hooks after mount. */\n init(): void | Promise<void> {\n if (this._initialized || this._disposed) return;\n this._initialized = true;\n return this.onInit?.();\n }\n\n /**\n * Merges partial state with validation. No-op if no values changed by reference.\n * @protected\n */\n protected set(partialOrUpdater: Partial<S> | Updater<S>): void {\n if (this._disposed) {\n throw new Error('Cannot set state on disposed Model');\n }\n\n const partial =\n typeof partialOrUpdater === 'function'\n ? partialOrUpdater(this._state)\n : partialOrUpdater;\n\n // Check if any values actually changed (shallow equality)\n const keys = Object.keys(partial) as (keyof S)[];\n const hasChanges = keys.some(\n (key) => partial[key] !== this._state[key]\n );\n\n if (!hasChanges) {\n return;\n }\n\n const prev = this._state;\n const next = Object.freeze({ ...prev, ...partial });\n this._state = next;\n\n this.onSet?.(prev, next);\n\n for (const listener of this._listeners) {\n listener(next, prev);\n }\n }\n\n /**\n * Mark current state as the new baseline (not dirty).\n */\n commit(): void {\n if (this._disposed) {\n throw new Error('Cannot commit on disposed Model');\n }\n this._committed = this._state;\n }\n\n /**\n * Revert state to committed baseline.\n */\n rollback(): void {\n if (this._disposed) {\n throw new Error('Cannot rollback on disposed Model');\n }\n\n if (this.shallowEqual(this._state, this._committed)) {\n return;\n }\n\n const prev = this._state;\n this._state = this._committed;\n\n this.onSet?.(prev, this._state);\n\n for (const listener of this._listeners) {\n listener(this._state, prev);\n }\n }\n\n /** Subscribes to state changes. Returns an unsubscribe function. */\n subscribe(listener: Listener<S>): () => void {\n if (this._disposed) {\n return () => {};\n }\n\n this._listeners.add(listener);\n\n return () => {\n this._listeners.delete(listener);\n };\n }\n\n /** Tears down the instance, releasing all subscriptions and resources. */\n dispose(): void {\n if (this._disposed) {\n return;\n }\n\n this._disposed = true;\n this._abortController?.abort();\n if (this._cleanups) {\n for (const fn of this._cleanups) fn();\n this._cleanups = null;\n }\n this.onDispose?.();\n this._listeners.clear();\n }\n\n /**\n * Override to provide validation logic.\n * Return an object mapping field keys to error messages.\n */\n protected validate(_state: Readonly<S>): ValidationErrors<S> {\n return {};\n }\n\n /** Registers a cleanup function to be called on dispose. @protected */\n protected addCleanup(fn: () => void): void {\n if (!this._cleanups) {\n this._cleanups = [];\n }\n this._cleanups.push(fn);\n }\n\n /** Subscribes to an external Subscribable with automatic cleanup on dispose. @protected */\n protected subscribeTo<T>(source: Subscribable<T>, listener: Listener<T>): () => void {\n const unsubscribe = source.subscribe(listener);\n this.addCleanup(unsubscribe);\n return unsubscribe;\n }\n\n /** Lifecycle hook called after every set() with the previous state. @protected */\n protected onSet?(prev: Readonly<S>, next: Readonly<S>): void;\n /** Lifecycle hook called at the end of init(). Override to load initial data. @protected */\n protected onInit?(): void | Promise<void>;\n /** Lifecycle hook called during dispose(). Override for custom teardown. @protected */\n protected onDispose?(): void;\n\n private shallowEqual(a: Readonly<S>, b: Readonly<S>): boolean {\n const keysA = Object.keys(a) as (keyof S)[];\n const keysB = Object.keys(b) as (keyof S)[];\n\n if (keysA.length !== keysB.length) {\n return false;\n }\n\n for (const key of keysA) {\n if (a[key] !== b[key]) {\n return false;\n }\n }\n\n return true;\n }\n}\n","import type { Listener, Subscribable } from './types';\n\ntype CollectionState<T> = readonly T[];\ntype CollectionListener<T> = Listener<CollectionState<T>>;\n\n/**\n * Reactive typed array with CRUD and query methods.\n */\nexport class Collection<T extends { id: string | number }> implements Subscribable<CollectionState<T>> {\n private _items: readonly T[] = [];\n private _disposed = false;\n private _listeners = new Set<CollectionListener<T>>();\n private _index = new Map<T['id'], T>();\n private _abortController: AbortController | null = null;\n private _cleanups: (() => void)[] | null = null;\n\n constructor(initialItems: T[] = []) {\n this._items = Object.freeze([...initialItems]);\n this.rebuildIndex();\n }\n\n /**\n * Alias for Subscribable compatibility.\n */\n get state(): readonly T[] {\n return this._items;\n }\n\n /** The raw readonly array of items. */\n get items(): readonly T[] {\n return this._items;\n }\n\n /** Number of items in the collection. */\n get length(): number {\n return this._items.length;\n }\n\n /** Whether this instance has been disposed. */\n get disposed(): boolean {\n return this._disposed;\n }\n\n /** AbortSignal that fires when this instance is disposed. Lazily created. */\n get disposeSignal(): AbortSignal {\n if (!this._abortController) {\n this._abortController = new AbortController();\n }\n return this._abortController.signal;\n }\n\n // ── CRUD Methods (notify listeners) ──\n\n /**\n * Add one or more items. Items with existing IDs are silently skipped.\n */\n add(...items: T[]): void {\n if (this._disposed) {\n throw new Error('Cannot add to disposed Collection');\n }\n\n if (items.length === 0) {\n return;\n }\n\n const seen = new Set<T['id']>();\n const newItems: T[] = [];\n for (const item of items) {\n if (!this._index.has(item.id) && !seen.has(item.id)) {\n newItems.push(item);\n seen.add(item.id);\n }\n }\n if (newItems.length === 0) return;\n\n const prev = this._items;\n this._items = Object.freeze([...prev, ...newItems]);\n\n for (const item of newItems) {\n this._index.set(item.id, item);\n }\n\n this.notify(prev);\n }\n\n /**\n * Add or replace items by ID. Existing items are replaced in-place\n * (preserving array position); new items are appended. Deduplicates\n * input — last occurrence wins. No-op if nothing changed (reference\n * comparison).\n */\n upsert(...items: T[]): void {\n if (this._disposed) {\n throw new Error('Cannot upsert on disposed Collection');\n }\n if (items.length === 0) return;\n\n // Deduplicate input — last occurrence wins\n const incoming = new Map<T['id'], T>();\n for (const item of items) {\n incoming.set(item.id, item);\n }\n\n const prev = this._items;\n let changed = false;\n const replaced = new Set<T['id']>();\n const newArray: T[] = [];\n\n // Replace existing items in-place\n for (const existing of prev) {\n if (incoming.has(existing.id)) {\n const replacement = incoming.get(existing.id)!;\n if (replacement !== existing) changed = true;\n newArray.push(replacement);\n replaced.add(existing.id);\n } else {\n newArray.push(existing);\n }\n }\n\n // Append genuinely new items\n for (const [id, item] of incoming) {\n if (!replaced.has(id)) {\n newArray.push(item);\n changed = true;\n }\n }\n\n if (!changed) return;\n\n this._items = Object.freeze(newArray);\n for (const [id, item] of incoming) {\n this._index.set(id, item);\n }\n this.notify(prev);\n }\n\n /**\n * Remove items by id(s).\n */\n remove(...ids: T['id'][]): void {\n if (this._disposed) {\n throw new Error('Cannot remove from disposed Collection');\n }\n\n if (ids.length === 0) {\n return;\n }\n\n const idSet = new Set(ids);\n const filtered = this._items.filter(item => !idSet.has(item.id));\n\n if (filtered.length === this._items.length) {\n return; // No items removed\n }\n\n const prev = this._items;\n this._items = Object.freeze(filtered);\n\n for (const id of ids) {\n this._index.delete(id);\n }\n\n this.notify(prev);\n }\n\n /**\n * Update an item by id with partial changes.\n */\n update(id: T['id'], changes: Partial<T>): void {\n if (this._disposed) {\n throw new Error('Cannot update disposed Collection');\n }\n\n const idx = this._items.findIndex(item => item.id === id);\n if (idx === -1) {\n return;\n }\n\n const existing = this._items[idx];\n const updated = { ...existing, ...changes, id }; // Ensure id is preserved\n\n // Check if anything actually changed\n const keys = Object.keys(changes) as (keyof T)[];\n const hasChanges = keys.some(key => changes[key] !== existing[key]);\n if (!hasChanges) {\n return;\n }\n\n const prev = this._items;\n const newItems = [...prev];\n newItems[idx] = updated;\n this._items = Object.freeze(newItems);\n this._index.set(id, updated);\n\n this.notify(prev);\n }\n\n /**\n * Replace all items.\n */\n reset(items: T[]): void {\n if (this._disposed) {\n throw new Error('Cannot reset disposed Collection');\n }\n\n const prev = this._items;\n this._items = Object.freeze([...items]);\n this.rebuildIndex();\n\n this.notify(prev);\n }\n\n /**\n * Remove all items.\n */\n clear(): void {\n if (this._disposed) {\n throw new Error('Cannot clear disposed Collection');\n }\n\n if (this._items.length === 0) {\n return;\n }\n\n const prev = this._items;\n this._items = Object.freeze([]);\n this._index.clear();\n\n this.notify(prev);\n }\n\n /**\n * Snapshot current state, apply callback mutations, and return a rollback function.\n * Rollback restores items to pre-callback state regardless of later mutations.\n */\n optimistic(callback: () => void): () => void {\n if (this._disposed) {\n throw new Error('Cannot perform optimistic update on disposed Collection');\n }\n\n const snapshot = this._items;\n callback();\n\n let rolledBack = false;\n return () => {\n if (rolledBack || this._disposed) return;\n rolledBack = true;\n\n const prev = this._items;\n this._items = snapshot;\n this.rebuildIndex();\n this.notify(prev);\n };\n }\n\n // ── Query Methods (pure, no notification) ──\n\n /**\n * Get item by id.\n */\n get(id: T['id']): T | undefined {\n return this._index.get(id);\n }\n\n /**\n * Check if item exists by id.\n */\n has(id: T['id']): boolean {\n return this._index.has(id);\n }\n\n /**\n * Find first item matching predicate.\n */\n find(predicate: (item: T) => boolean): T | undefined {\n return this._items.find(predicate);\n }\n\n /**\n * Filter items matching predicate.\n */\n filter(predicate: (item: T) => boolean): readonly T[] {\n return this._items.filter(predicate);\n }\n\n /**\n * Return sorted copy.\n */\n sorted(compareFn: (a: T, b: T) => number): readonly T[] {\n return [...this._items].sort(compareFn);\n }\n\n /**\n * Map items to new array.\n */\n map<U>(fn: (item: T) => U): readonly U[] {\n return this._items.map(fn);\n }\n\n // ── Subscribable interface ──\n\n /** Subscribes to state changes. Returns an unsubscribe function. */\n subscribe(listener: CollectionListener<T>): () => void {\n if (this._disposed) {\n return () => {};\n }\n\n this._listeners.add(listener);\n\n return () => {\n this._listeners.delete(listener);\n };\n }\n\n /** Tears down the instance, releasing all subscriptions and resources. */\n dispose(): void {\n if (this._disposed) {\n return;\n }\n\n this._disposed = true;\n this._abortController?.abort();\n if (this._cleanups) {\n for (const fn of this._cleanups) fn();\n this._cleanups = null;\n }\n this.onDispose?.();\n this._listeners.clear();\n this._index.clear();\n }\n\n /** Registers a cleanup function to be called on dispose. @protected */\n protected addCleanup(fn: () => void): void {\n if (!this._cleanups) {\n this._cleanups = [];\n }\n this._cleanups.push(fn);\n }\n\n /** Lifecycle hook called during dispose(). Override for custom teardown. @protected */\n protected onDispose?(): void;\n\n private notify(prev: readonly T[]): void {\n for (const listener of this._listeners) {\n listener(this._items, prev);\n }\n }\n\n private rebuildIndex(): void {\n this._index.clear();\n for (const item of this._items) {\n this._index.set(item.id, item);\n }\n }\n}\n","import type { Disposable, Subscribable, Listener } from './types';\n\n/**\n * Base class for stateless orchestrators.\n * Controllers coordinate between ViewModels, Models, and Services.\n */\nexport abstract class Controller implements Disposable {\n private _disposed = false;\n private _initialized = false;\n private _abortController: AbortController | null = null;\n private _cleanups: (() => void)[] | null = null;\n\n /** Whether this instance has been disposed. */\n get disposed(): boolean {\n return this._disposed;\n }\n\n /** Whether init() has been called. */\n get initialized(): boolean {\n return this._initialized;\n }\n\n /** AbortSignal that fires when this instance is disposed. Lazily created. */\n get disposeSignal(): AbortSignal {\n if (!this._abortController) {\n this._abortController = new AbortController();\n }\n return this._abortController.signal;\n }\n\n /** Initializes the instance. Called automatically by React hooks after mount. */\n init(): void | Promise<void> {\n if (this._initialized || this._disposed) return;\n this._initialized = true;\n return this.onInit?.();\n }\n\n /** Tears down the instance, releasing all subscriptions and resources. */\n dispose(): void {\n if (this._disposed) {\n return;\n }\n\n this._disposed = true;\n this._abortController?.abort();\n if (this._cleanups) {\n for (const fn of this._cleanups) fn();\n this._cleanups = null;\n }\n this.onDispose?.();\n }\n\n /** Registers a cleanup function to be called on dispose. @protected */\n protected addCleanup(fn: () => void): void {\n if (!this._cleanups) {\n this._cleanups = [];\n }\n this._cleanups.push(fn);\n }\n\n /** Subscribes to an external Subscribable with automatic cleanup on dispose. @protected */\n protected subscribeTo<T>(source: Subscribable<T>, listener: Listener<T>): () => void {\n const unsubscribe = source.subscribe(listener);\n this.addCleanup(unsubscribe);\n return unsubscribe;\n }\n\n /** Lifecycle hook called at the end of init(). Override to load initial data. @protected */\n protected onInit?(): void | Promise<void>;\n /** Lifecycle hook called during dispose(). Override for custom teardown. @protected */\n protected onDispose?(): void;\n}\n","import type { Disposable } from './types';\n\n/**\n * Base class for non-reactive infrastructure services.\n * Services encapsulate external dependencies like APIs, storage, etc.\n */\nexport abstract class Service implements Disposable {\n private _disposed = false;\n private _initialized = false;\n private _abortController: AbortController | null = null;\n private _cleanups: (() => void)[] | null = null;\n\n /** Whether this instance has been disposed. */\n get disposed(): boolean {\n return this._disposed;\n }\n\n /** Whether init() has been called. */\n get initialized(): boolean {\n return this._initialized;\n }\n\n /** AbortSignal that fires when this instance is disposed. Lazily created. */\n get disposeSignal(): AbortSignal {\n if (!this._abortController) {\n this._abortController = new AbortController();\n }\n return this._abortController.signal;\n }\n\n /** Initializes the instance. Called automatically by React hooks after mount. */\n init(): void | Promise<void> {\n if (this._initialized || this._disposed) return;\n this._initialized = true;\n return this.onInit?.();\n }\n\n /** Tears down the instance, releasing all subscriptions and resources. */\n dispose(): void {\n if (this._disposed) {\n return;\n }\n\n this._disposed = true;\n this._abortController?.abort();\n if (this._cleanups) {\n for (const fn of this._cleanups) fn();\n this._cleanups = null;\n }\n this.onDispose?.();\n }\n\n /** Registers a cleanup function to be called on dispose. @protected */\n protected addCleanup(fn: () => void): void {\n if (!this._cleanups) {\n this._cleanups = [];\n }\n this._cleanups.push(fn);\n }\n\n /** Lifecycle hook called at the end of init(). Override to load initial data. @protected */\n protected onInit?(): void | Promise<void>;\n /** Lifecycle hook called during dispose(). Override for custom teardown. @protected */\n protected onDispose?(): void;\n}\n","import type { Listener, Subscribable, Disposable, Initializable } from './types';\n\nconst __DEV__ = typeof __MVC_KIT_DEV__ !== 'undefined' && __MVC_KIT_DEV__;\n\n// ── Types ─────────────────────────────────────────────────────────\n\n/** Describes the current connection state of a Channel. */\nexport interface ChannelStatus {\n readonly connected: boolean;\n readonly reconnecting: boolean;\n readonly attempt: number;\n readonly error: string | null;\n}\n\ntype Handler<T> = (payload: T) => void;\n\nconst enum ConnectionState {\n Idle,\n Connecting,\n Connected,\n Reconnecting,\n Disposed,\n}\n\nconst INITIAL_STATUS: ChannelStatus = Object.freeze({\n connected: false,\n reconnecting: false,\n attempt: 0,\n error: null,\n});\n\n// ── Channel ───────────────────────────────────────────────────────\n\n/**\n * Abstract persistent connection with automatic reconnection and exponential backoff.\n * Subclass to implement WebSocket, SSE, or other transport protocols.\n */\nexport abstract class Channel<M extends Record<string, any>>\n implements Subscribable<ChannelStatus>, Initializable, Disposable\n{\n // Static config (subclass overrides)\n /** Base delay (ms) for reconnection backoff. */\n static RECONNECT_BASE = 1000;\n /** Maximum delay cap (ms) for reconnection backoff. */\n static RECONNECT_MAX = 30000;\n /** Exponential backoff multiplier for reconnection delay. */\n static RECONNECT_FACTOR = 2;\n /** Maximum number of reconnection attempts before giving up. */\n static MAX_ATTEMPTS = Infinity;\n\n // ── Internal state ──────────────────────────────────────────────\n private _status: ChannelStatus = INITIAL_STATUS;\n private _connState: ConnectionState = ConnectionState.Idle;\n private _disposed = false;\n private _initialized = false;\n private _listeners = new Set<Listener<ChannelStatus>>();\n private _handlers = new Map<keyof M, Set<Handler<unknown>>>();\n private _abortController: AbortController | null = null;\n private _connectAbort: AbortController | null = null;\n private _reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private _cleanups: (() => void)[] | null = null;\n\n // ── Subscribable<ChannelStatus> ─────────────────────────────────\n\n /** Current connection status. */\n get state(): Readonly<ChannelStatus> {\n return this._status;\n }\n\n /** Subscribes to connection status changes. Returns an unsubscribe function. */\n subscribe(listener: Listener<ChannelStatus>): () => void {\n if (this._disposed) return () => {};\n this._listeners.add(listener);\n return () => { this._listeners.delete(listener); };\n }\n\n // ── Disposable / Initializable ──────────────────────────────────\n\n /** Whether this instance has been disposed. */\n get disposed(): boolean {\n return this._disposed;\n }\n\n /** Whether init() has been called. */\n get initialized(): boolean {\n return this._initialized;\n }\n\n /** AbortSignal that fires when this instance is disposed. Lazily created. */\n get disposeSignal(): AbortSignal {\n if (!this._abortController) {\n this._abortController = new AbortController();\n }\n return this._abortController.signal;\n }\n\n /** Initializes the instance. Called automatically by React hooks after mount. */\n init(): void | Promise<void> {\n if (this._initialized || this._disposed) return;\n this._initialized = true;\n return this.onInit?.();\n }\n\n /** Tears down the instance, releasing all subscriptions and resources. */\n dispose(): void {\n if (this._disposed) return;\n this._disposed = true;\n this._connState = ConnectionState.Disposed;\n\n // Cancel pending reconnect\n if (this._reconnectTimer !== null) {\n clearTimeout(this._reconnectTimer);\n this._reconnectTimer = null;\n }\n\n // Abort per-connection signal\n this._connectAbort?.abort();\n this._connectAbort = null;\n\n // Abort dispose signal\n this._abortController?.abort();\n\n // Close transport\n try { this.close(); } catch { /* swallow close errors during dispose */ }\n\n // Run cleanups\n if (this._cleanups) {\n for (const fn of this._cleanups) fn();\n this._cleanups = null;\n }\n\n this.onDispose?.();\n this._listeners.clear();\n this._handlers.clear();\n }\n\n // ── Subclass contract ───────────────────────────────────────────\n\n /** Establishes the underlying connection. Called internally by connect(). @protected */\n protected abstract open(signal: AbortSignal): void | Promise<void>;\n /** Tears down the underlying connection. Called internally by disconnect() and dispose(). @protected */\n protected abstract close(): void;\n\n // ── Connection control ──────────────────────────────────────────\n\n /** Initiates a connection with automatic reconnection on failure. */\n connect(): void {\n if (this._disposed) {\n if (__DEV__) {\n console.warn('[mvc-kit] connect() called after dispose — ignored.');\n }\n return;\n }\n if (__DEV__ && !this._initialized) {\n console.warn('[mvc-kit] connect() called before init().');\n }\n if (\n this._connState === ConnectionState.Connecting ||\n this._connState === ConnectionState.Connected\n ) {\n return;\n }\n\n // Cancel any pending reconnect\n if (this._reconnectTimer !== null) {\n clearTimeout(this._reconnectTimer);\n this._reconnectTimer = null;\n }\n\n this._attemptConnect(0);\n }\n\n /** Closes the connection and cancels any pending reconnection. */\n disconnect(): void {\n if (this._disposed) return;\n\n // Cancel pending reconnect\n if (this._reconnectTimer !== null) {\n clearTimeout(this._reconnectTimer);\n this._reconnectTimer = null;\n }\n\n // Abort current connection attempt\n this._connectAbort?.abort();\n this._connectAbort = null;\n\n // Close transport\n if (\n this._connState === ConnectionState.Connected ||\n this._connState === ConnectionState.Connecting\n ) {\n this._connState = ConnectionState.Idle;\n try { this.close(); } catch { /* swallow */ }\n } else {\n this._connState = ConnectionState.Idle;\n }\n\n this._setStatus({ connected: false, reconnecting: false, attempt: 0, error: null });\n }\n\n // ── Subclass signals ────────────────────────────────────────────\n\n /** Call from subclass when a message arrives from the transport. @protected */\n protected receive<K extends keyof M>(type: K, payload: M[K]): void {\n if (this._disposed) {\n if (__DEV__) {\n console.warn(`[mvc-kit] receive(\"${String(type)}\") called after dispose — ignored.`);\n }\n return;\n }\n\n const handlers = this._handlers.get(type);\n if (handlers) {\n for (const handler of handlers) {\n handler(payload);\n }\n }\n }\n\n /** Call from subclass when the transport connection drops unexpectedly. Triggers reconnection. @protected */\n protected disconnected(): void {\n if (this._disposed) return;\n // Only trigger reconnect from connected or connecting states\n if (\n this._connState !== ConnectionState.Connected &&\n this._connState !== ConnectionState.Connecting\n ) {\n return;\n }\n\n this._connectAbort?.abort();\n this._connectAbort = null;\n\n this._connState = ConnectionState.Reconnecting;\n this._scheduleReconnect(1);\n }\n\n // ── Consumer API ────────────────────────────────────────────────\n\n /** Subscribes to a specific message type. Returns an unsubscribe function. */\n on<K extends keyof M>(type: K, handler: Handler<M[K]>): () => void {\n if (this._disposed) return () => {};\n\n let handlers = this._handlers.get(type);\n if (!handlers) {\n handlers = new Set();\n this._handlers.set(type, handlers);\n }\n handlers.add(handler as Handler<unknown>);\n\n return () => { handlers!.delete(handler as Handler<unknown>); };\n }\n\n /** Subscribes to a message type, auto-removing the handler after the first invocation. */\n once<K extends keyof M>(type: K, handler: Handler<M[K]>): () => void {\n const unsubscribe = this.on(type, (payload) => {\n unsubscribe();\n handler(payload);\n });\n return unsubscribe;\n }\n\n // ── Infrastructure ──────────────────────────────────────────────\n\n /** Registers a cleanup function to be called on dispose. @protected */\n protected addCleanup(fn: () => void): void {\n if (!this._cleanups) {\n this._cleanups = [];\n }\n this._cleanups.push(fn);\n }\n\n /** Subscribes to an external Subscribable with automatic cleanup on dispose. @protected */\n protected subscribeTo<T>(source: Subscribable<T>, listener: Listener<T>): () => void {\n const unsubscribe = source.subscribe(listener);\n this.addCleanup(unsubscribe);\n return unsubscribe;\n }\n\n /** Lifecycle hook called at the end of init(). Override to load initial data. @protected */\n protected onInit?(): void | Promise<void>;\n /** Lifecycle hook called during dispose(). Override for custom teardown. @protected */\n protected onDispose?(): void;\n\n // ── Backoff ─────────────────────────────────────────────────────\n\n /** Computes the reconnect backoff delay with jitter for the given attempt number. @protected */\n protected _calculateDelay(attempt: number): number {\n const ctor = this.constructor as typeof Channel;\n const capped = Math.min(\n ctor.RECONNECT_BASE * Math.pow(ctor.RECONNECT_FACTOR, attempt),\n ctor.RECONNECT_MAX,\n );\n return Math.random() * capped;\n }\n\n // ── Internals ───────────────────────────────────────────────────\n\n private _setStatus(next: ChannelStatus): void {\n const prev = this._status;\n if (\n prev.connected === next.connected &&\n prev.reconnecting === next.reconnecting &&\n prev.attempt === next.attempt &&\n prev.error === next.error\n ) {\n return;\n }\n\n this._status = Object.freeze(next);\n for (const listener of this._listeners) {\n listener(this._status, prev);\n }\n }\n\n private _attemptConnect(attempt: number): void {\n if (this._disposed) return;\n\n this._connState = ConnectionState.Connecting;\n\n // Create per-connection abort controller\n this._connectAbort?.abort();\n this._connectAbort = new AbortController();\n\n const signal = this._abortController\n ? AbortSignal.any([this._abortController.signal, this._connectAbort.signal])\n : this._connectAbort.signal;\n\n this._setStatus({\n connected: false,\n reconnecting: attempt > 0,\n attempt,\n error: null,\n });\n\n let result: void | Promise<void>;\n try {\n result = this.open(signal);\n } catch (e) {\n this._onOpenFailed(attempt, e);\n return;\n }\n\n if (result && typeof (result as Promise<void>).then === 'function') {\n (result as Promise<void>).then(\n () => this._onOpenSucceeded(),\n (e) => this._onOpenFailed(attempt, e),\n );\n } else {\n this._onOpenSucceeded();\n }\n }\n\n private _onOpenSucceeded(): void {\n if (this._disposed) return;\n // Only transition if we're still connecting (disconnect may have been called)\n if (this._connState !== ConnectionState.Connecting) return;\n\n this._connState = ConnectionState.Connected;\n this._setStatus({\n connected: true,\n reconnecting: false,\n attempt: 0,\n error: null,\n });\n }\n\n private _onOpenFailed(attempt: number, error: unknown): void {\n if (this._disposed) return;\n // If disconnect was called during open, don't reconnect\n if (this._connState === ConnectionState.Idle) return;\n\n this._connectAbort?.abort();\n this._connectAbort = null;\n\n this._connState = ConnectionState.Reconnecting;\n this._scheduleReconnect(attempt + 1, error);\n }\n\n private _scheduleReconnect(attempt: number, error?: unknown): void {\n const ctor = this.constructor as typeof Channel;\n\n if (attempt > ctor.MAX_ATTEMPTS) {\n this._connState = ConnectionState.Idle;\n this._setStatus({\n connected: false,\n reconnecting: false,\n attempt,\n error: error instanceof Error ? error.message : 'Max reconnection attempts reached',\n });\n return;\n }\n\n const errorMsg = error instanceof Error ? error.message : (error ? String(error) : null);\n\n this._setStatus({\n connected: false,\n reconnecting: true,\n attempt,\n error: errorMsg,\n });\n\n const delay = this._calculateDelay(attempt - 1);\n this._reconnectTimer = setTimeout(() => {\n this._reconnectTimer = null;\n this._attemptConnect(attempt);\n }, delay);\n }\n}\n"],"names":["HttpError","status","message","isAbortError","error","classifyHttpStatus","isResponseLike","value","classifyError","__DEV__","isAutoTrackable","walkPrototypeChain","instance","stopAt","visitor","proto","descriptors","key","desc","DEFAULT_TASK_STATE","RESERVED_ASYNC_KEYS","LIFECYCLE_HOOKS","ViewModel","initialState","EventBus","partialOrUpdater","partial","prev","next","listener","event","payload","fn","newState","source","unsubscribe","self","_","prop","tracked","processed","wrappedKeys","original","pruned","wrapper","args","result","e","internal","c","classified","opsSnapshot","k","count","stateProxy","cached","validatedAtRevision","stateDeps","stateSnapshot","sourceDeps","fresh","v","memberKey","rev","ts","parentStateTracking","parentSourceTracking","capturedSourceDeps","d","Model","frozen","_state","a","b","keysA","keysB","Collection","initialItems","items","seen","newItems","item","incoming","changed","replaced","newArray","existing","replacement","id","ids","idSet","filtered","changes","idx","updated","callback","snapshot","rolledBack","predicate","compareFn","Controller","Service","INITIAL_STATUS","Channel","type","handlers","handler","attempt","ctor","capped","signal","errorMsg","delay"],"mappings":"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"}
|
package/dist/react/provider.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/react/provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAsC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAO3E,MAAM,WAAW,aAAa;IAE5B,OAAO,EAAE,KAAK,CAAC,CAAC,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;IACnD,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,aAAa,GAAG,SAAS,CAcxE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,IAAI,SAAS,OAAO,EAAE,GAAG,OAAO,EAAE,EAC9D,KAAK,EAAE,KAAK,GAAG,IAAI,EAAE,IAAI,KAAK,CAAC,EAC/B,GAAG,IAAI,EAAE,IAAI,GACZ,CAAC,CAOH"}
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/react/provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAsC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAO3E,qFAAqF;AACrF,MAAM,WAAW,aAAa;IAE5B,OAAO,EAAE,KAAK,CAAC,CAAC,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;IACnD,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,aAAa,GAAG,SAAS,CAcxE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,IAAI,SAAS,OAAO,EAAE,GAAG,OAAO,EAAE,EAC9D,KAAK,EAAE,KAAK,GAAG,IAAI,EAAE,IAAI,KAAK,CAAC,EAC/B,GAAG,IAAI,EAAE,IAAI,GACZ,CAAC,CAOH"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Model } from '../Model';
|
|
2
2
|
import type { ValidationErrors } from '../types';
|
|
3
3
|
import type { StateOf } from './types';
|
|
4
|
+
/** Return type of `useModel`, providing state, validation, and model access. */
|
|
4
5
|
export interface ModelHandle<S extends object, M extends Model<S>> {
|
|
5
6
|
state: Readonly<S>;
|
|
6
7
|
errors: ValidationErrors<S>;
|
|
@@ -12,6 +13,7 @@ export interface ModelHandle<S extends object, M extends Model<S>> {
|
|
|
12
13
|
* Bind to a component-scoped Model with validation and dirty state exposed.
|
|
13
14
|
*/
|
|
14
15
|
export declare function useModel<M extends Model<any>>(factory: () => M): ModelHandle<StateOf<M>, M>;
|
|
16
|
+
/** Return type of `useField`, providing a single field's value, error, and setter. */
|
|
15
17
|
export interface FieldHandle<V> {
|
|
16
18
|
value: V;
|
|
17
19
|
error: string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-model.d.ts","sourceRoot":"","sources":["../../src/react/use-model.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGvC,MAAM,WAAW,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC;IAC/D,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IACnB,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAC5B,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,CAAC,CAAC;CACV;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,KAAK,CAAC,GAAG,CAAC,EAC3C,OAAO,EAAE,MAAM,CAAC,GACf,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAsC5B;AAED,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;CACzB;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,CAAC,EAC1D,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EACf,KAAK,EAAE,CAAC,GACP,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAiDnB"}
|
|
1
|
+
{"version":3,"file":"use-model.d.ts","sourceRoot":"","sources":["../../src/react/use-model.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGvC,gFAAgF;AAChF,MAAM,WAAW,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC;IAC/D,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IACnB,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAC5B,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,CAAC,CAAC;CACV;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,KAAK,CAAC,GAAG,CAAC,EAC3C,OAAO,EAAE,MAAM,CAAC,GACf,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAsC5B;AAED,sFAAsF;AACtF,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;CACzB;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,CAAC,EAC1D,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EACf,KAAK,EAAE,CAAC,GACP,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAiDnB"}
|
package/dist/react.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.cjs","sources":["../src/react/use-instance.ts","../src/react/guards.ts","../src/react/use-local.ts","../src/react/use-singleton.ts","../src/react/use-model.ts","../src/react/use-event-bus.ts","../src/react/use-teardown.ts","../src/react/provider.tsx"],"sourcesContent":["import { useSyncExternalStore, useRef } from 'react';\nimport type { Subscribable } from '../types';\n\nfunction hasAsyncSubscription(obj: unknown): obj is { subscribeAsync(cb: () => void): () => void } {\n return (\n obj !== null &&\n typeof obj === 'object' &&\n typeof (obj as any).subscribeAsync === 'function'\n );\n}\n\n/**\n * Subscribe to an existing Subscribable instance.\n * No ownership - caller manages the instance lifecycle.\n *\n * If the instance has a `subscribeAsync` method (duck-typed),\n * a second subscription ensures async state changes also\n * trigger React re-renders.\n */\nexport function useInstance<S>(subscribable: Subscribable<S>): Readonly<S> {\n const state = useSyncExternalStore(\n (onStoreChange) => subscribable.subscribe(onStoreChange),\n () => subscribable.state,\n () => subscribable.state // SSR snapshot\n );\n\n // Async subscription — forces re-render when any async status changes.\n // Duck-typed: safe for Collection/Model (they don't have subscribeAsync).\n const versionRef = useRef(0);\n useSyncExternalStore(\n (onStoreChange) => {\n if (!hasAsyncSubscription(subscribable)) return () => {};\n return subscribable.subscribeAsync(() => {\n versionRef.current++;\n onStoreChange();\n });\n },\n () => versionRef.current,\n () => 0 // SSR: no async ops server-side\n );\n\n return state;\n}\n","import type { Subscribable } from '../types';\n\n/** @internal Type guard for Subscribable */\nexport const isSubscribable = (obj: unknown): obj is Subscribable<unknown> =>\n obj !== null &&\n typeof obj === 'object' &&\n 'state' in obj &&\n 'subscribe' in obj &&\n typeof (obj as Subscribable<unknown>).subscribe === 'function';\n\n/** @internal Type guard for Initializable */\nexport const isInitializable = (obj: unknown): obj is { init(): void | Promise<void> } =>\n obj !== null &&\n typeof obj === 'object' &&\n 'init' in obj &&\n typeof (obj as any).init === 'function';\n","import { useRef, useEffect } from 'react';\nimport type { DependencyList } from 'react';\nimport type { Subscribable, Disposable } from '../types';\nimport { isSubscribable, isInitializable } from './guards';\nimport { useInstance } from './use-instance';\nimport type { StateOf } from './types';\n\nfunction depsChanged(prev: DependencyList | undefined, next: DependencyList): boolean {\n if (prev === undefined) return false;\n if (prev.length !== next.length) return true;\n for (let i = 0; i < prev.length; i++) {\n if (!Object.is(prev[i], next[i])) return true;\n }\n return false;\n}\n\n// ── With deps (class + initialState + deps) ────────────────────────\n\n/**\n * Create component-scoped Subscribable instance, auto-disposed on unmount.\n * Disposes and recreates when deps change.\n * Returns [state, instance] tuple.\n */\nexport function useLocal<T extends Subscribable<any> & Disposable>(\n Class: new (initialState: StateOf<T>) => T,\n initialState: StateOf<T>,\n deps: DependencyList,\n): [Readonly<StateOf<T>>, T];\n\n/**\n * Create component-scoped Subscribable instance via factory, auto-disposed on unmount.\n * Disposes and recreates when deps change.\n * Returns [state, instance] tuple.\n */\nexport function useLocal<T extends Subscribable<S> & Disposable, S = StateOf<T>>(\n factory: () => T,\n deps: DependencyList,\n): [Readonly<S>, T];\n\n/**\n * Create component-scoped Disposable instance via factory (non-Subscribable), auto-disposed on unmount.\n * Disposes and recreates when deps change.\n * Returns the instance directly.\n */\nexport function useLocal<T extends Disposable>(\n factory: () => T,\n deps: DependencyList,\n): T;\n\n// ── Without deps (existing overloads, unchanged) ───────────────────\n\n/**\n * Create component-scoped Subscribable instance, auto-disposed on unmount.\n * Returns [state, instance] tuple.\n */\nexport function useLocal<\n T extends Subscribable<S> & Disposable,\n S = StateOf<T>,\n Args extends unknown[] = unknown[]\n>(\n Class: new (...args: Args) => T,\n ...args: Args\n): [Readonly<S>, T];\n\n/**\n * Create component-scoped Disposable instance (non-Subscribable), auto-disposed on unmount.\n * Returns the instance directly.\n */\nexport function useLocal<T extends Disposable, Args extends unknown[] = unknown[]>(\n Class: new (...args: Args) => T,\n ...args: Args\n): T;\n\n/**\n * Create component-scoped Subscribable instance via factory, auto-disposed on unmount.\n * Returns [state, instance] tuple.\n */\nexport function useLocal<T extends Subscribable<S> & Disposable, S = StateOf<T>>(\n factory: () => T\n): [Readonly<S>, T];\n\n/**\n * Create component-scoped Disposable instance via factory (non-Subscribable), auto-disposed on unmount.\n * Returns the instance directly.\n */\nexport function useLocal<T extends Disposable>(factory: () => T): T;\n\n// ── Implementation ─────────────────────────────────────────────────\n\nexport function useLocal<T extends Disposable, S = StateOf<T>>(\n classOrFactory: (new (...args: unknown[]) => T) | (() => T),\n ...rest: unknown[]\n): [Readonly<S>, T] | T {\n // ── Detect deps: last arg is an array → treat as deps ──\n let args: unknown[];\n let deps: DependencyList | undefined;\n\n if (rest.length > 0 && Array.isArray(rest[rest.length - 1])) {\n deps = rest[rest.length - 1] as DependencyList;\n args = rest.slice(0, -1);\n } else {\n args = rest;\n deps = undefined;\n }\n\n const instanceRef = useRef<T | null>(null);\n const mountedRef = useRef(false);\n const prevDepsRef = useRef<DependencyList | undefined>(undefined);\n\n // ── Render phase: dep-change detection ──\n if (deps !== undefined && depsChanged(prevDepsRef.current, deps)) {\n instanceRef.current?.dispose();\n instanceRef.current = null;\n }\n if (deps !== undefined) {\n prevDepsRef.current = deps;\n }\n\n // ── Create instance if needed ──\n if (!instanceRef.current || instanceRef.current.disposed) {\n const isClass =\n typeof classOrFactory === 'function' &&\n classOrFactory.prototype &&\n classOrFactory.prototype.constructor === classOrFactory;\n\n if (isClass) {\n instanceRef.current = new (classOrFactory as new (...a: unknown[]) => T)(...args);\n } else {\n instanceRef.current = (classOrFactory as () => T)();\n }\n }\n\n // ── Effect: init + deferred cleanup ──\n useEffect(() => {\n const instance = instanceRef.current!; // capture for cleanup closure\n mountedRef.current = true;\n if (isInitializable(instance)) {\n instance.init();\n }\n return () => {\n mountedRef.current = false;\n setTimeout(() => {\n if (!mountedRef.current) {\n instance.dispose();\n }\n }, 0);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, deps ?? []);\n\n // ── Subscribe to state if Subscribable ──\n if (isSubscribable(instanceRef.current)) {\n const state = useInstance(instanceRef.current as unknown as Subscribable<S>);\n return [state, instanceRef.current];\n }\n\n return instanceRef.current;\n}\n","import { useEffect } from 'react';\nimport type { Subscribable, Disposable } from '../types';\nimport { singleton } from '../singleton';\nimport { useInstance } from './use-instance';\nimport { isSubscribable, isInitializable } from './guards';\nimport type { StateOf } from './types';\n\n/**\n * Get singleton Subscribable instance and subscribe to its state.\n * Returns [state, instance] tuple.\n */\nexport function useSingleton<\n T extends Subscribable<S> & Disposable,\n S = StateOf<T>,\n Args extends unknown[] = unknown[]\n>(\n Class: new (...args: Args) => T,\n ...args: Args\n): [Readonly<S>, T];\n\n/**\n * Get singleton Disposable instance (non-Subscribable).\n * Returns the instance directly.\n */\nexport function useSingleton<T extends Disposable, Args extends unknown[] = unknown[]>(\n Class: new (...args: Args) => T,\n ...args: Args\n): T;\n\n// Implementation\nexport function useSingleton<T extends Disposable, S = StateOf<T>, Args extends unknown[] = unknown[]>(\n Class: new (...args: Args) => T,\n ...args: Args\n): [Readonly<S>, T] | T {\n const instance = singleton(Class, ...args);\n\n useEffect(() => {\n if (isInitializable(instance)) {\n instance.init();\n }\n }, [instance]);\n\n if (isSubscribable(instance)) {\n const state = useInstance(instance) as Readonly<S>;\n return [state, instance];\n }\n\n return instance;\n}\n","import { useRef, useEffect, useSyncExternalStore, useCallback } from 'react';\nimport type { Model } from '../Model';\nimport type { ValidationErrors } from '../types';\nimport type { StateOf } from './types';\nimport { isInitializable } from './guards';\n\nexport interface ModelHandle<S extends object, M extends Model<S>> {\n state: Readonly<S>;\n errors: ValidationErrors<S>;\n valid: boolean;\n dirty: boolean;\n model: M;\n}\n\n/**\n * Bind to a component-scoped Model with validation and dirty state exposed.\n */\nexport function useModel<M extends Model<any>>(\n factory: () => M\n): ModelHandle<StateOf<M>, M> {\n const modelRef = useRef<M | null>(null);\n const mountedRef = useRef(false);\n\n if (!modelRef.current || modelRef.current.disposed) {\n modelRef.current = factory();\n }\n\n useSyncExternalStore(\n (onStoreChange) => modelRef.current!.subscribe(onStoreChange),\n () => modelRef.current!.state,\n () => modelRef.current!.state,\n );\n\n useEffect(() => {\n mountedRef.current = true;\n if (isInitializable(modelRef.current)) {\n modelRef.current.init();\n }\n return () => {\n mountedRef.current = false;\n setTimeout(() => {\n if (!mountedRef.current) {\n modelRef.current?.dispose();\n }\n }, 0);\n };\n }, []);\n\n const model = modelRef.current;\n\n return {\n state: model.state,\n errors: model.errors,\n valid: model.valid,\n dirty: model.dirty,\n model,\n };\n}\n\nexport interface FieldHandle<V> {\n value: V;\n error: string | undefined;\n set: (value: V) => void;\n}\n\n/**\n * Bind to a single Model field with surgical re-renders.\n */\nexport function useField<S extends object, K extends keyof S>(\n model: Model<S>,\n field: K\n): FieldHandle<S[K]> {\n // Track the field value and error for comparison\n const getSnapshot = useCallback(() => {\n return {\n value: model.state[field],\n error: model.errors[field],\n };\n }, [model, field]);\n\n // Use object comparison for subscription\n const cachedRef = useRef(getSnapshot());\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n return model.subscribe(() => {\n const next = getSnapshot();\n const current = cachedRef.current;\n\n // Only trigger re-render if field value or error changed\n if (next.value !== current.value || next.error !== current.error) {\n cachedRef.current = next;\n onStoreChange();\n }\n });\n },\n [model, getSnapshot]\n );\n\n const snapshot = useSyncExternalStore(\n subscribe,\n () => cachedRef.current,\n () => cachedRef.current\n );\n\n const set = useCallback(\n (value: S[K]) => {\n // Access the protected set method through type assertion\n // The Model subclass should expose a setter method\n const partial: Partial<S> = { [field]: value } as unknown as Partial<S>;\n (model as unknown as { set: (partial: Partial<S>) => void }).set(partial);\n },\n [model, field]\n );\n\n return {\n value: snapshot.value,\n error: snapshot.error,\n set,\n };\n}\n","import { useEffect, useCallback, useRef } from 'react';\nimport { EventBus } from '../EventBus';\n\n/**\n * Subscribe to a typed event, auto-unsubscribes on unmount.\n * Accepts an EventBus directly or any object with an `events` property (e.g. a ViewModel).\n */\nexport function useEvent<E extends Record<string, any>, K extends keyof E>(\n source: EventBus<E> | { events: EventBus<E> },\n event: K,\n handler: (payload: E[K]) => void\n): void {\n const bus = source instanceof EventBus ? source : source.events;\n\n // Use ref to keep handler stable across re-renders\n const handlerRef = useRef(handler);\n handlerRef.current = handler;\n\n useEffect(() => {\n const unsubscribe = bus.on(event, (payload) => {\n handlerRef.current(payload);\n });\n\n return unsubscribe;\n }, [bus, event]);\n}\n\n/**\n * Get a stable emit function for an EventBus.\n */\nexport function useEmit<E extends Record<string, any>>(\n bus: EventBus<E>\n): <K extends keyof E>(event: K, payload: E[K]) => void {\n return useCallback(\n <K extends keyof E>(event: K, payload: E[K]) => {\n bus.emit(event, payload);\n },\n [bus]\n );\n}\n","import { useEffect, useRef } from 'react';\nimport type { Disposable } from '../types';\nimport { teardown } from '../singleton';\n\n/**\n * Teardown singleton class(es) on unmount.\n * Uses deferred disposal to handle StrictMode's double-mount cycle.\n */\nexport function useTeardown(\n ...Classes: Array<new (...args: unknown[]) => Disposable>\n): void {\n const mountedRef = useRef(false);\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n setTimeout(() => {\n if (!mountedRef.current) {\n for (const Class of Classes) {\n teardown(Class);\n }\n }\n }, 0);\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n}\n","import { createContext, useContext, useMemo, type ReactNode } from 'react';\nimport { singleton } from '../singleton';\nimport type { Disposable } from '../types';\nimport type { ProviderRegistry } from './types';\n\nconst ProviderContext = createContext<ProviderRegistry | null>(null);\n\nexport interface ProviderProps {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n provide: Array<[new (...args: any[]) => any, any]>;\n children: ReactNode;\n}\n\n/**\n * DI container for testing and Storybook.\n */\nexport function Provider({ provide, children }: ProviderProps): ReactNode {\n const registry = useMemo(() => {\n const map: ProviderRegistry = new Map();\n for (const [Class, instance] of provide) {\n map.set(Class, instance);\n }\n return map;\n }, [provide]);\n\n return (\n <ProviderContext.Provider value={registry}>\n {children}\n </ProviderContext.Provider>\n );\n}\n\n/**\n * Resolve from Provider context or fallback to singleton().\n */\nexport function useResolve<T, Args extends unknown[] = unknown[]>(\n Class: new (...args: Args) => T,\n ...args: Args\n): T {\n const registry = useContext(ProviderContext);\n\n if (registry?.has(Class)) {\n return registry.get(Class) as T;\n }\n return singleton(Class as new (...args: Args) => T & Disposable, ...args);\n}\n"],"names":["hasAsyncSubscription","obj","useInstance","subscribable","state","useSyncExternalStore","onStoreChange","versionRef","useRef","isSubscribable","isInitializable","depsChanged","prev","next","i","useLocal","classOrFactory","rest","args","deps","instanceRef","mountedRef","prevDepsRef","useEffect","instance","useSingleton","Class","singleton","useModel","factory","modelRef","model","useField","field","getSnapshot","useCallback","cachedRef","subscribe","current","snapshot","set","value","partial","useEvent","source","event","handler","bus","EventBus","handlerRef","payload","useEmit","useTeardown","Classes","teardown","ProviderContext","createContext","Provider","provide","children","registry","useMemo","map","useResolve","useContext"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"react.cjs","sources":["../src/react/use-instance.ts","../src/react/guards.ts","../src/react/use-local.ts","../src/react/use-singleton.ts","../src/react/use-model.ts","../src/react/use-event-bus.ts","../src/react/use-teardown.ts","../src/react/provider.tsx"],"sourcesContent":["import { useSyncExternalStore, useRef } from 'react';\nimport type { Subscribable } from '../types';\n\nfunction hasAsyncSubscription(obj: unknown): obj is { subscribeAsync(cb: () => void): () => void } {\n return (\n obj !== null &&\n typeof obj === 'object' &&\n typeof (obj as any).subscribeAsync === 'function'\n );\n}\n\n/**\n * Subscribe to an existing Subscribable instance.\n * No ownership - caller manages the instance lifecycle.\n *\n * If the instance has a `subscribeAsync` method (duck-typed),\n * a second subscription ensures async state changes also\n * trigger React re-renders.\n */\nexport function useInstance<S>(subscribable: Subscribable<S>): Readonly<S> {\n const state = useSyncExternalStore(\n (onStoreChange) => subscribable.subscribe(onStoreChange),\n () => subscribable.state,\n () => subscribable.state // SSR snapshot\n );\n\n // Async subscription — forces re-render when any async status changes.\n // Duck-typed: safe for Collection/Model (they don't have subscribeAsync).\n const versionRef = useRef(0);\n useSyncExternalStore(\n (onStoreChange) => {\n if (!hasAsyncSubscription(subscribable)) return () => {};\n return subscribable.subscribeAsync(() => {\n versionRef.current++;\n onStoreChange();\n });\n },\n () => versionRef.current,\n () => 0 // SSR: no async ops server-side\n );\n\n return state;\n}\n","import type { Subscribable } from '../types';\n\n/** @internal Type guard for Subscribable */\nexport const isSubscribable = (obj: unknown): obj is Subscribable<unknown> =>\n obj !== null &&\n typeof obj === 'object' &&\n 'state' in obj &&\n 'subscribe' in obj &&\n typeof (obj as Subscribable<unknown>).subscribe === 'function';\n\n/** @internal Type guard for Initializable */\nexport const isInitializable = (obj: unknown): obj is { init(): void | Promise<void> } =>\n obj !== null &&\n typeof obj === 'object' &&\n 'init' in obj &&\n typeof (obj as any).init === 'function';\n","import { useRef, useEffect } from 'react';\nimport type { DependencyList } from 'react';\nimport type { Subscribable, Disposable } from '../types';\nimport { isSubscribable, isInitializable } from './guards';\nimport { useInstance } from './use-instance';\nimport type { StateOf } from './types';\n\nfunction depsChanged(prev: DependencyList | undefined, next: DependencyList): boolean {\n if (prev === undefined) return false;\n if (prev.length !== next.length) return true;\n for (let i = 0; i < prev.length; i++) {\n if (!Object.is(prev[i], next[i])) return true;\n }\n return false;\n}\n\n// ── With deps (class + initialState + deps) ────────────────────────\n\n/**\n * Create component-scoped Subscribable instance, auto-disposed on unmount.\n * Disposes and recreates when deps change.\n * Returns [state, instance] tuple.\n */\nexport function useLocal<T extends Subscribable<any> & Disposable>(\n Class: new (initialState: StateOf<T>) => T,\n initialState: StateOf<T>,\n deps: DependencyList,\n): [Readonly<StateOf<T>>, T];\n\n/**\n * Create component-scoped Subscribable instance via factory, auto-disposed on unmount.\n * Disposes and recreates when deps change.\n * Returns [state, instance] tuple.\n */\nexport function useLocal<T extends Subscribable<S> & Disposable, S = StateOf<T>>(\n factory: () => T,\n deps: DependencyList,\n): [Readonly<S>, T];\n\n/**\n * Create component-scoped Disposable instance via factory (non-Subscribable), auto-disposed on unmount.\n * Disposes and recreates when deps change.\n * Returns the instance directly.\n */\nexport function useLocal<T extends Disposable>(\n factory: () => T,\n deps: DependencyList,\n): T;\n\n// ── Without deps (existing overloads, unchanged) ───────────────────\n\n/**\n * Create component-scoped Subscribable instance, auto-disposed on unmount.\n * Returns [state, instance] tuple.\n */\nexport function useLocal<\n T extends Subscribable<S> & Disposable,\n S = StateOf<T>,\n Args extends unknown[] = unknown[]\n>(\n Class: new (...args: Args) => T,\n ...args: Args\n): [Readonly<S>, T];\n\n/**\n * Create component-scoped Disposable instance (non-Subscribable), auto-disposed on unmount.\n * Returns the instance directly.\n */\nexport function useLocal<T extends Disposable, Args extends unknown[] = unknown[]>(\n Class: new (...args: Args) => T,\n ...args: Args\n): T;\n\n/**\n * Create component-scoped Subscribable instance via factory, auto-disposed on unmount.\n * Returns [state, instance] tuple.\n */\nexport function useLocal<T extends Subscribable<S> & Disposable, S = StateOf<T>>(\n factory: () => T\n): [Readonly<S>, T];\n\n/**\n * Create component-scoped Disposable instance via factory (non-Subscribable), auto-disposed on unmount.\n * Returns the instance directly.\n */\nexport function useLocal<T extends Disposable>(factory: () => T): T;\n\n// ── Implementation ─────────────────────────────────────────────────\n\nexport function useLocal<T extends Disposable, S = StateOf<T>>(\n classOrFactory: (new (...args: unknown[]) => T) | (() => T),\n ...rest: unknown[]\n): [Readonly<S>, T] | T {\n // ── Detect deps: last arg is an array → treat as deps ──\n let args: unknown[];\n let deps: DependencyList | undefined;\n\n if (rest.length > 0 && Array.isArray(rest[rest.length - 1])) {\n deps = rest[rest.length - 1] as DependencyList;\n args = rest.slice(0, -1);\n } else {\n args = rest;\n deps = undefined;\n }\n\n const instanceRef = useRef<T | null>(null);\n const mountedRef = useRef(false);\n const prevDepsRef = useRef<DependencyList | undefined>(undefined);\n\n // ── Render phase: dep-change detection ──\n if (deps !== undefined && depsChanged(prevDepsRef.current, deps)) {\n instanceRef.current?.dispose();\n instanceRef.current = null;\n }\n if (deps !== undefined) {\n prevDepsRef.current = deps;\n }\n\n // ── Create instance if needed ──\n if (!instanceRef.current || instanceRef.current.disposed) {\n const isClass =\n typeof classOrFactory === 'function' &&\n classOrFactory.prototype &&\n classOrFactory.prototype.constructor === classOrFactory;\n\n if (isClass) {\n instanceRef.current = new (classOrFactory as new (...a: unknown[]) => T)(...args);\n } else {\n instanceRef.current = (classOrFactory as () => T)();\n }\n }\n\n // ── Effect: init + deferred cleanup ──\n useEffect(() => {\n const instance = instanceRef.current!; // capture for cleanup closure\n mountedRef.current = true;\n if (isInitializable(instance)) {\n instance.init();\n }\n return () => {\n mountedRef.current = false;\n setTimeout(() => {\n if (!mountedRef.current) {\n instance.dispose();\n }\n }, 0);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, deps ?? []);\n\n // ── Subscribe to state if Subscribable ──\n if (isSubscribable(instanceRef.current)) {\n const state = useInstance(instanceRef.current as unknown as Subscribable<S>);\n return [state, instanceRef.current];\n }\n\n return instanceRef.current;\n}\n","import { useEffect } from 'react';\nimport type { Subscribable, Disposable } from '../types';\nimport { singleton } from '../singleton';\nimport { useInstance } from './use-instance';\nimport { isSubscribable, isInitializable } from './guards';\nimport type { StateOf } from './types';\n\n/**\n * Get singleton Subscribable instance and subscribe to its state.\n * Returns [state, instance] tuple.\n */\nexport function useSingleton<\n T extends Subscribable<S> & Disposable,\n S = StateOf<T>,\n Args extends unknown[] = unknown[]\n>(\n Class: new (...args: Args) => T,\n ...args: Args\n): [Readonly<S>, T];\n\n/**\n * Get singleton Disposable instance (non-Subscribable).\n * Returns the instance directly.\n */\nexport function useSingleton<T extends Disposable, Args extends unknown[] = unknown[]>(\n Class: new (...args: Args) => T,\n ...args: Args\n): T;\n\n// Implementation\nexport function useSingleton<T extends Disposable, S = StateOf<T>, Args extends unknown[] = unknown[]>(\n Class: new (...args: Args) => T,\n ...args: Args\n): [Readonly<S>, T] | T {\n const instance = singleton(Class, ...args);\n\n useEffect(() => {\n if (isInitializable(instance)) {\n instance.init();\n }\n }, [instance]);\n\n if (isSubscribable(instance)) {\n const state = useInstance(instance) as Readonly<S>;\n return [state, instance];\n }\n\n return instance;\n}\n","import { useRef, useEffect, useSyncExternalStore, useCallback } from 'react';\nimport type { Model } from '../Model';\nimport type { ValidationErrors } from '../types';\nimport type { StateOf } from './types';\nimport { isInitializable } from './guards';\n\n/** Return type of `useModel`, providing state, validation, and model access. */\nexport interface ModelHandle<S extends object, M extends Model<S>> {\n state: Readonly<S>;\n errors: ValidationErrors<S>;\n valid: boolean;\n dirty: boolean;\n model: M;\n}\n\n/**\n * Bind to a component-scoped Model with validation and dirty state exposed.\n */\nexport function useModel<M extends Model<any>>(\n factory: () => M\n): ModelHandle<StateOf<M>, M> {\n const modelRef = useRef<M | null>(null);\n const mountedRef = useRef(false);\n\n if (!modelRef.current || modelRef.current.disposed) {\n modelRef.current = factory();\n }\n\n useSyncExternalStore(\n (onStoreChange) => modelRef.current!.subscribe(onStoreChange),\n () => modelRef.current!.state,\n () => modelRef.current!.state,\n );\n\n useEffect(() => {\n mountedRef.current = true;\n if (isInitializable(modelRef.current)) {\n modelRef.current.init();\n }\n return () => {\n mountedRef.current = false;\n setTimeout(() => {\n if (!mountedRef.current) {\n modelRef.current?.dispose();\n }\n }, 0);\n };\n }, []);\n\n const model = modelRef.current;\n\n return {\n state: model.state,\n errors: model.errors,\n valid: model.valid,\n dirty: model.dirty,\n model,\n };\n}\n\n/** Return type of `useField`, providing a single field's value, error, and setter. */\nexport interface FieldHandle<V> {\n value: V;\n error: string | undefined;\n set: (value: V) => void;\n}\n\n/**\n * Bind to a single Model field with surgical re-renders.\n */\nexport function useField<S extends object, K extends keyof S>(\n model: Model<S>,\n field: K\n): FieldHandle<S[K]> {\n // Track the field value and error for comparison\n const getSnapshot = useCallback(() => {\n return {\n value: model.state[field],\n error: model.errors[field],\n };\n }, [model, field]);\n\n // Use object comparison for subscription\n const cachedRef = useRef(getSnapshot());\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n return model.subscribe(() => {\n const next = getSnapshot();\n const current = cachedRef.current;\n\n // Only trigger re-render if field value or error changed\n if (next.value !== current.value || next.error !== current.error) {\n cachedRef.current = next;\n onStoreChange();\n }\n });\n },\n [model, getSnapshot]\n );\n\n const snapshot = useSyncExternalStore(\n subscribe,\n () => cachedRef.current,\n () => cachedRef.current\n );\n\n const set = useCallback(\n (value: S[K]) => {\n // Access the protected set method through type assertion\n // The Model subclass should expose a setter method\n const partial: Partial<S> = { [field]: value } as unknown as Partial<S>;\n (model as unknown as { set: (partial: Partial<S>) => void }).set(partial);\n },\n [model, field]\n );\n\n return {\n value: snapshot.value,\n error: snapshot.error,\n set,\n };\n}\n","import { useEffect, useCallback, useRef } from 'react';\nimport { EventBus } from '../EventBus';\n\n/**\n * Subscribe to a typed event, auto-unsubscribes on unmount.\n * Accepts an EventBus directly or any object with an `events` property (e.g. a ViewModel).\n */\nexport function useEvent<E extends Record<string, any>, K extends keyof E>(\n source: EventBus<E> | { events: EventBus<E> },\n event: K,\n handler: (payload: E[K]) => void\n): void {\n const bus = source instanceof EventBus ? source : source.events;\n\n // Use ref to keep handler stable across re-renders\n const handlerRef = useRef(handler);\n handlerRef.current = handler;\n\n useEffect(() => {\n const unsubscribe = bus.on(event, (payload) => {\n handlerRef.current(payload);\n });\n\n return unsubscribe;\n }, [bus, event]);\n}\n\n/**\n * Get a stable emit function for an EventBus.\n */\nexport function useEmit<E extends Record<string, any>>(\n bus: EventBus<E>\n): <K extends keyof E>(event: K, payload: E[K]) => void {\n return useCallback(\n <K extends keyof E>(event: K, payload: E[K]) => {\n bus.emit(event, payload);\n },\n [bus]\n );\n}\n","import { useEffect, useRef } from 'react';\nimport type { Disposable } from '../types';\nimport { teardown } from '../singleton';\n\n/**\n * Teardown singleton class(es) on unmount.\n * Uses deferred disposal to handle StrictMode's double-mount cycle.\n */\nexport function useTeardown(\n ...Classes: Array<new (...args: unknown[]) => Disposable>\n): void {\n const mountedRef = useRef(false);\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n setTimeout(() => {\n if (!mountedRef.current) {\n for (const Class of Classes) {\n teardown(Class);\n }\n }\n }, 0);\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n}\n","import { createContext, useContext, useMemo, type ReactNode } from 'react';\nimport { singleton } from '../singleton';\nimport type { Disposable } from '../types';\nimport type { ProviderRegistry } from './types';\n\nconst ProviderContext = createContext<ProviderRegistry | null>(null);\n\n/** Props for the `Provider` component used to inject test/Storybook dependencies. */\nexport interface ProviderProps {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n provide: Array<[new (...args: any[]) => any, any]>;\n children: ReactNode;\n}\n\n/**\n * DI container for testing and Storybook.\n */\nexport function Provider({ provide, children }: ProviderProps): ReactNode {\n const registry = useMemo(() => {\n const map: ProviderRegistry = new Map();\n for (const [Class, instance] of provide) {\n map.set(Class, instance);\n }\n return map;\n }, [provide]);\n\n return (\n <ProviderContext.Provider value={registry}>\n {children}\n </ProviderContext.Provider>\n );\n}\n\n/**\n * Resolve from Provider context or fallback to singleton().\n */\nexport function useResolve<T, Args extends unknown[] = unknown[]>(\n Class: new (...args: Args) => T,\n ...args: Args\n): T {\n const registry = useContext(ProviderContext);\n\n if (registry?.has(Class)) {\n return registry.get(Class) as T;\n }\n return singleton(Class as new (...args: Args) => T & Disposable, ...args);\n}\n"],"names":["hasAsyncSubscription","obj","useInstance","subscribable","state","useSyncExternalStore","onStoreChange","versionRef","useRef","isSubscribable","isInitializable","depsChanged","prev","next","i","useLocal","classOrFactory","rest","args","deps","instanceRef","mountedRef","prevDepsRef","useEffect","instance","useSingleton","Class","singleton","useModel","factory","modelRef","model","useField","field","getSnapshot","useCallback","cachedRef","subscribe","current","snapshot","set","value","partial","useEvent","source","event","handler","bus","EventBus","handlerRef","payload","useEmit","useTeardown","Classes","teardown","ProviderContext","createContext","Provider","provide","children","registry","useMemo","map","useResolve","useContext"],"mappings":"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"}
|
package/dist/react.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useSyncExternalStore as p, useRef as i, useEffect as a, useCallback as l, useMemo as R, useContext as b, createContext as C } from "react";
|
|
2
|
-
import { s as g, E as x, t as E } from "./singleton-
|
|
2
|
+
import { s as g, E as x, t as E } from "./singleton-CaEXSbYg.js";
|
|
3
3
|
import { jsx as S } from "react/jsx-runtime";
|
|
4
4
|
function A(t) {
|
|
5
5
|
return t !== null && typeof t == "object" && typeof t.subscribeAsync == "function";
|