mvc-kit 2.3.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +83 -2
- package/agent-config/claude-code/agents/mvc-kit-architect.md +7 -5
- package/agent-config/claude-code/skills/guide/anti-patterns.md +114 -1
- package/agent-config/claude-code/skills/guide/api-reference.md +74 -2
- package/agent-config/claude-code/skills/guide/patterns.md +65 -0
- package/agent-config/copilot/copilot-instructions.md +7 -2
- package/agent-config/cursor/cursorrules +7 -2
- package/dist/PersistentCollection-B8kNECDj.cjs +2 -0
- package/dist/PersistentCollection-B8kNECDj.cjs.map +1 -0
- package/dist/PersistentCollection-BFrgskju.js +542 -0
- package/dist/PersistentCollection-BFrgskju.js.map +1 -0
- package/dist/PersistentCollection.d.ts +69 -0
- package/dist/PersistentCollection.d.ts.map +1 -0
- package/dist/Resource.d.ts +60 -0
- package/dist/Resource.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.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 +328 -442
- package/dist/mvc-kit.js.map +1 -1
- package/dist/react-native/NativeCollection.d.ts +65 -0
- package/dist/react-native/NativeCollection.d.ts.map +1 -0
- package/dist/react-native/index.d.ts +2 -0
- package/dist/react-native/index.d.ts.map +1 -0
- package/dist/react-native.cjs +2 -0
- package/dist/react-native.cjs.map +1 -0
- package/dist/react-native.js +63 -0
- package/dist/react-native.js.map +1 -0
- package/dist/web/IndexedDBCollection.d.ts +37 -0
- package/dist/web/IndexedDBCollection.d.ts.map +1 -0
- package/dist/web/WebStorageCollection.d.ts +33 -0
- package/dist/web/WebStorageCollection.d.ts.map +1 -0
- package/dist/web/idb.d.ts +16 -0
- package/dist/web/idb.d.ts.map +1 -0
- package/dist/web/index.d.ts +3 -0
- package/dist/web/index.d.ts.map +1 -0
- package/dist/web.cjs +2 -0
- package/dist/web.cjs.map +1 -0
- package/dist/web.js +181 -0
- package/dist/web.js.map +1 -0
- package/package.json +22 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Collection } from './Collection';
|
|
2
|
+
/**
|
|
3
|
+
* Abstract base for Collections that persist to external storage.
|
|
4
|
+
* Tracks deltas per mutation and flushes via debounced writes.
|
|
5
|
+
* Subclasses implement the storage-specific `persist*` methods.
|
|
6
|
+
*/
|
|
7
|
+
export declare abstract class PersistentCollection<T extends {
|
|
8
|
+
id: string | number;
|
|
9
|
+
}> extends Collection<T> {
|
|
10
|
+
/** Debounce delay in ms for storage writes. 0 = immediate. */
|
|
11
|
+
static WRITE_DELAY: number;
|
|
12
|
+
/** Unique key identifying this collection in storage. */
|
|
13
|
+
protected abstract readonly storageKey: string;
|
|
14
|
+
protected abstract persistGet(id: T['id']): T | null | Promise<T | null>;
|
|
15
|
+
protected abstract persistGetAll(): T[] | Promise<T[]>;
|
|
16
|
+
/** Upsert semantics — insert or replace the given items. */
|
|
17
|
+
protected abstract persistSet(items: T[]): void | Promise<void>;
|
|
18
|
+
protected abstract persistRemove(ids: T['id'][]): void | Promise<void>;
|
|
19
|
+
protected abstract persistClear(): void | Promise<void>;
|
|
20
|
+
/** Serialize items to a string. Used by string-based adapters (WebStorage, NativeCollection). */
|
|
21
|
+
protected serialize(items: readonly T[]): string;
|
|
22
|
+
/** Deserialize a string back to items. Used by string-based adapters. */
|
|
23
|
+
protected deserialize(raw: string): T[];
|
|
24
|
+
/** Called when a storage operation fails. Override for custom error handling. */
|
|
25
|
+
protected onPersistError?(error: unknown): void;
|
|
26
|
+
private _hydrated;
|
|
27
|
+
private _hydrating;
|
|
28
|
+
private _persistenceReady;
|
|
29
|
+
private _preHydrationWarned;
|
|
30
|
+
private _pendingWrites;
|
|
31
|
+
private _pendingRemoves;
|
|
32
|
+
private _pendingClear;
|
|
33
|
+
private _flushTimer;
|
|
34
|
+
constructor(initialItems?: T[]);
|
|
35
|
+
/**
|
|
36
|
+
* DEV check for duplicate storageKey. Called lazily since storageKey is an abstract
|
|
37
|
+
* field that isn't available during the parent constructor chain.
|
|
38
|
+
*/
|
|
39
|
+
private _ensurePersistenceReady;
|
|
40
|
+
/** Whether storage data has been loaded. */
|
|
41
|
+
get hydrated(): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Load data from storage into the collection. Idempotent — subsequent calls return current items.
|
|
44
|
+
* Returns the items after hydration.
|
|
45
|
+
*/
|
|
46
|
+
hydrate(): Promise<readonly T[]>;
|
|
47
|
+
/**
|
|
48
|
+
* Synchronous hydration for sync adapters (e.g., WebStorage).
|
|
49
|
+
* Call from the **leaf class** constructor (after field initializers have run).
|
|
50
|
+
*/
|
|
51
|
+
protected _hydrateSync(): void;
|
|
52
|
+
/**
|
|
53
|
+
* Clear all data from storage AND from the in-memory collection.
|
|
54
|
+
*/
|
|
55
|
+
clearStorage(): void | Promise<void>;
|
|
56
|
+
reset(items: T[]): void;
|
|
57
|
+
clear(): void;
|
|
58
|
+
get items(): readonly T[];
|
|
59
|
+
get state(): readonly T[];
|
|
60
|
+
dispose(): void;
|
|
61
|
+
private _diffAndQueue;
|
|
62
|
+
private _hasPending;
|
|
63
|
+
private _scheduleSave;
|
|
64
|
+
private _cancelSave;
|
|
65
|
+
private _doFlush;
|
|
66
|
+
private _flush;
|
|
67
|
+
private _handlePersistError;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=PersistentCollection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PersistentCollection.d.ts","sourceRoot":"","sources":["../src/PersistentCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAO1C;;;;GAIG;AACH,8BAAsB,oBAAoB,CACxC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CACjC,SAAQ,UAAU,CAAC,CAAC,CAAC;IACrB,8DAA8D;IAC9D,MAAM,CAAC,WAAW,SAAO;IAEzB,yDAAyD;IACzD,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAI/C,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IACxE,SAAS,CAAC,QAAQ,CAAC,aAAa,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IACtD,4DAA4D;IAC5D,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAC/D,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IACtE,SAAS,CAAC,QAAQ,CAAC,YAAY,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvD,iGAAiG;IACjG,SAAS,CAAC,SAAS,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,GAAG,MAAM;IAIhD,yEAAyE;IACzE,SAAS,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,EAAE;IAMvC,iFAAiF;IACjF,SAAS,CAAC,cAAc,CAAC,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAI/C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,cAAc,CAAyB;IAC/C,OAAO,CAAC,eAAe,CAAsB;IAC7C,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,WAAW,CAA8C;gBAErD,YAAY,GAAE,CAAC,EAAO;IAelC;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAmB/B,4CAA4C;IAC5C,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;IAqBtC;;;OAGG;IACH,SAAS,CAAC,YAAY,IAAI,IAAI;IAsB9B;;OAEG;IACH,YAAY,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IA0BpC,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI;IAgBvB,KAAK,IAAI,IAAI;IAeb,IAAI,KAAK,IAAI,SAAS,CAAC,EAAE,CASxB;IAED,IAAI,KAAK,IAAI,SAAS,CAAC,EAAE,CAExB;IAID,OAAO,IAAI,IAAI;IA0Bf,OAAO,CAAC,aAAa;IA6BrB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,QAAQ;IAYhB,OAAO,CAAC,MAAM;IAuCd,OAAO,CAAC,mBAAmB;CAS5B"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Collection } from './Collection';
|
|
2
|
+
import type { Listener, TaskState } from './types';
|
|
3
|
+
export type ResourceAsyncMethodKeys<T> = {
|
|
4
|
+
[K in Exclude<keyof T, keyof Resource<any>>]: T[K] extends (...args: any[]) => Promise<any> ? K : never;
|
|
5
|
+
}[Exclude<keyof T, keyof Resource<any>>];
|
|
6
|
+
type ResourceAsyncMap<T> = {
|
|
7
|
+
readonly [K in ResourceAsyncMethodKeys<T>]: TaskState;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Collection + async tracking toolkit. Extends Collection with lifecycle
|
|
11
|
+
* (init/dispose) and automatic async method tracking. Optionally delegates
|
|
12
|
+
* to an external Collection for shared data scenarios.
|
|
13
|
+
*/
|
|
14
|
+
export declare class Resource<T extends {
|
|
15
|
+
id: string | number;
|
|
16
|
+
}> extends Collection<T> {
|
|
17
|
+
private _external;
|
|
18
|
+
private _initialized;
|
|
19
|
+
private _asyncStates;
|
|
20
|
+
private _asyncSnapshots;
|
|
21
|
+
private _asyncListeners;
|
|
22
|
+
private _asyncProxy;
|
|
23
|
+
private _activeOps;
|
|
24
|
+
/** DEV-only timeout (ms) for detecting ghost async operations after dispose. */
|
|
25
|
+
static GHOST_TIMEOUT: number;
|
|
26
|
+
constructor(collectionOrItems?: Collection<T> | T[]);
|
|
27
|
+
/** Whether init() has been called. */
|
|
28
|
+
get initialized(): boolean;
|
|
29
|
+
/** Initializes the instance. Called automatically by React hooks after mount. */
|
|
30
|
+
init(): void | Promise<void>;
|
|
31
|
+
/** Lifecycle hook called at the end of init(). Override to load initial data. @protected */
|
|
32
|
+
protected onInit?(): void | Promise<void>;
|
|
33
|
+
get state(): readonly T[];
|
|
34
|
+
get items(): readonly T[];
|
|
35
|
+
get length(): number;
|
|
36
|
+
add(...items: T[]): void;
|
|
37
|
+
upsert(...items: T[]): void;
|
|
38
|
+
update(id: T['id'], changes: Partial<T>): void;
|
|
39
|
+
remove(...ids: T['id'][]): void;
|
|
40
|
+
reset(items: T[]): void;
|
|
41
|
+
clear(): void;
|
|
42
|
+
optimistic(callback: () => void): () => void;
|
|
43
|
+
get(id: T['id']): T | undefined;
|
|
44
|
+
has(id: T['id']): boolean;
|
|
45
|
+
find(predicate: (item: T) => boolean): T | undefined;
|
|
46
|
+
filter(predicate: (item: T) => boolean): readonly T[];
|
|
47
|
+
sorted(compareFn: (a: T, b: T) => number): readonly T[];
|
|
48
|
+
map<U>(fn: (item: T) => U): readonly U[];
|
|
49
|
+
subscribe(listener: Listener<readonly T[]>): () => void;
|
|
50
|
+
/** Proxy providing `TaskState` (loading, error, errorCode) per async method. */
|
|
51
|
+
get async(): ResourceAsyncMap<this>;
|
|
52
|
+
/** Subscribes to async state changes. Used by `useAsync` and `useInstance` for React integration. */
|
|
53
|
+
subscribeAsync(listener: () => void): () => void;
|
|
54
|
+
private _notifyAsync;
|
|
55
|
+
private _guardReservedKeys;
|
|
56
|
+
private _wrapMethods;
|
|
57
|
+
private _scheduleGhostCheck;
|
|
58
|
+
}
|
|
59
|
+
export {};
|
|
60
|
+
//# sourceMappingURL=Resource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Resource.d.ts","sourceRoot":"","sources":["../src/Resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAQnD,MAAM,MAAM,uBAAuB,CAAC,CAAC,IAAI;KACtC,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK;CACxG,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAEzC,KAAK,gBAAgB,CAAC,CAAC,IAAI;IACzB,QAAQ,EAAE,CAAC,IAAI,uBAAuB,CAAC,CAAC,CAAC,GAAG,SAAS;CACtD,CAAC;AAcF;;;;GAIG;AACH,qBAAa,QAAQ,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAAE,SAAQ,UAAU,CAAC,CAAC,CAAC;IAC5E,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,YAAY,CAAS;IAG7B,OAAO,CAAC,YAAY,CAAwC;IAC5D,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,eAAe,CAAyB;IAChD,OAAO,CAAC,WAAW,CAAuC;IAC1D,OAAO,CAAC,UAAU,CAAoC;IAEtD,gFAAgF;IAChF,MAAM,CAAC,aAAa,SAAQ;gBAEhB,iBAAiB,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE;IAuBnD,sCAAsC;IACtC,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,iFAAiF;IACjF,IAAI,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAO5B,4FAA4F;IAC5F,SAAS,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC,IAAI,KAAK,IAAI,SAAS,CAAC,EAAE,CAExB;IAED,IAAI,KAAK,IAAI,SAAS,CAAC,EAAE,CAExB;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,GAAG,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI;IAIxB,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI;IAI3B,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI;IAI9C,MAAM,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI;IAI/B,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI;IAIvB,KAAK,IAAI,IAAI;IAIb,UAAU,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAI5C,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,SAAS;IAI/B,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO;IAIzB,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,GAAG,CAAC,GAAG,SAAS;IAIpD,MAAM,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,GAAG,SAAS,CAAC,EAAE;IAIrD,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,MAAM,GAAG,SAAS,CAAC,EAAE;IAIvD,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,EAAE;IAIxC,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,MAAM,IAAI;IAOvD,gFAAgF;IAChF,IAAI,KAAK,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAsBlC;IAED,qGAAqG;IACrG,cAAc,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAQhD,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,YAAY;IAiMpB,OAAO,CAAC,mBAAmB;CAY5B"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
export type { Listener, Updater, Subscribable, Disposable, Initializable, ValidationErrors, TaskState, } from './types';
|
|
2
2
|
export type { AsyncMethodKeys } from './ViewModel';
|
|
3
|
+
export type { ResourceAsyncMethodKeys } from './Resource';
|
|
3
4
|
export { ViewModel } from './ViewModel';
|
|
4
5
|
export { Model } from './Model';
|
|
5
6
|
export { Collection } from './Collection';
|
|
7
|
+
export { PersistentCollection } from './PersistentCollection';
|
|
8
|
+
export { Resource } from './Resource';
|
|
6
9
|
export { Controller } from './Controller';
|
|
7
10
|
export { Service } from './Service';
|
|
8
11
|
export { EventBus } from './EventBus';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,QAAQ,EACR,OAAO,EACP,YAAY,EACZ,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,SAAS,GACV,MAAM,SAAS,CAAC;AAEjB,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,QAAQ,EACR,OAAO,EACP,YAAY,EACZ,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,SAAS,GACV,MAAM,SAAS,CAAC;AAEjB,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,YAAY,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAG1D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,YAAY,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG/C,YAAY,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGlE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/mvc-kit.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const m=require("./singleton-L-u2W_lX.cjs");class C extends Error{constructor(t,s){super(s??`HTTP ${t}`),this.status=t,this.name="HttpError"}}function y(r){return r instanceof Error&&r.name==="AbortError"}function v(r){return r===401?"unauthorized":r===403?"forbidden":r===404?"not_found":r===422?"validation":r===429?"rate_limited":r>=500?"server_error":"unknown"}function E(r){return typeof r=="object"&&r!==null&&typeof r.status=="number"&&typeof r.statusText=="string"&&!(r instanceof Error)}function T(r){return r instanceof Error&&r.name==="AbortError"?{code:"abort",message:"Request was aborted",original:r}:r instanceof C?{code:v(r.status),message:r.message,status:r.status,original:r}:E(r)?{code:v(r.status),message:r.statusText||`HTTP ${r.status}`,status:r.status,original:r}:r instanceof TypeError&&r.message.toLowerCase().includes("fetch")?{code:"network",message:r.message,original:r}:r instanceof Error&&r.name==="TimeoutError"?{code:"timeout",message:r.message,original:r}:r instanceof Error?{code:"unknown",message:r.message,original:r}:{code:"unknown",message:String(r),original:r}}const d=typeof __MVC_KIT_DEV__<"u"&&__MVC_KIT_DEV__;function O(r){return r!==null&&typeof r=="object"&&typeof r.subscribe=="function"}function g(r,t,s){let e=Object.getPrototypeOf(r);for(;e&&e!==t;){const i=Object.getOwnPropertyDescriptors(e);for(const[n,a]of Object.entries(i))n!=="constructor"&&s(n,a,e);e=Object.getPrototypeOf(e)}}const z=Object.freeze({loading:!1,error:null,errorCode:null}),w=["async","subscribeAsync"],A=new Set(["onInit","onSet","onDispose"]);class b{_state;_initialState;_disposed=!1;_initialized=!1;_listeners=new Set;_abortController=null;_cleanups=null;_subscriptionCleanups=null;_eventBus=null;_revision=0;_stateTracking=null;_sourceTracking=null;_trackedSources=new Map;_asyncStates=new Map;_asyncSnapshots=new Map;_asyncListeners=new Set;_asyncProxy=null;_activeOps=null;static GHOST_TIMEOUT=3e3;constructor(t){this._state=Object.freeze({...t}),this._initialState=this._state,this._guardReservedKeys()}get state(){return this._state}get disposed(){return this._disposed}get initialized(){return this._initialized}get disposeSignal(){return this._abortController||(this._abortController=new AbortController),this._abortController.signal}get events(){return this._eventBus||(this._eventBus=new m.EventBus),this._eventBus}init(){if(!(this._initialized||this._disposed))return this._initialized=!0,this._trackSubscribables(),this._installStateProxy(),this._memoizeGetters(),this._wrapMethods(),this.onInit?.()}set(t){if(this._disposed)return;if(d&&this._stateTracking){console.error("[mvc-kit] set() called inside a getter. Getters must be pure — they read state and return a value. They must never call set(), which would cause an infinite render loop. Move this logic to an action method.");return}const s=typeof t=="function"?t(this._state):t;if(!Object.keys(s).some(o=>s[o]!==this._state[o]))return;const n=this._state,a=Object.freeze({...n,...s});this._state=a,this._revision++,this.onSet?.(n,a);for(const o of this._listeners)o(a,n)}emit(t,s){(this._eventBus?.disposed??this._disposed)||this.events.emit(t,s)}subscribe(t){return this._disposed?()=>{}:(this._listeners.add(t),()=>{this._listeners.delete(t)})}dispose(){if(!this._disposed){if(this._disposed=!0,this._teardownSubscriptions(),this._abortController?.abort(),this._cleanups){for(const t of this._cleanups)t();this._cleanups=null}this._eventBus?.dispose(),this.onDispose?.(),this._listeners.clear()}}reset(t){if(!this._disposed){this._abortController?.abort(),this._abortController=null,this._teardownSubscriptions(),this._state=t?Object.freeze({...t}):this._initialState,this._revision++,this._asyncStates.clear(),this._asyncSnapshots.clear(),this._notifyAsync(),this._trackSubscribables();for(const s of this._listeners)s(this._state,this._state);return this.onInit?.()}}addCleanup(t){this._cleanups||(this._cleanups=[]),this._cleanups.push(t)}subscribeTo(t,s){const e=t.subscribe(s);return this._subscriptionCleanups||(this._subscriptionCleanups=[]),this._subscriptionCleanups.push(e),e}get async(){if(!this._asyncProxy){const t=this;this._asyncProxy=new Proxy({},{get(s,e){return t._asyncSnapshots.get(e)??z},has(s,e){return t._asyncSnapshots.has(e)},ownKeys(){return Array.from(t._asyncSnapshots.keys())},getOwnPropertyDescriptor(s,e){if(t._asyncSnapshots.has(e))return{configurable:!0,enumerable:!0,value:t._asyncSnapshots.get(e)}}})}return this._asyncProxy}subscribeAsync(t){return this._disposed?()=>{}:(this._asyncListeners.add(t),()=>{this._asyncListeners.delete(t)})}_notifyAsync(){for(const t of this._asyncListeners)t()}_teardownSubscriptions(){for(const t of this._trackedSources.values())t.unsubscribe();if(this._trackedSources.clear(),this._subscriptionCleanups){for(const t of this._subscriptionCleanups)t();this._subscriptionCleanups=null}}_guardReservedKeys(){g(this,b.prototype,t=>{if(w.includes(t))throw new Error(`[mvc-kit] "${t}" is a reserved property on ViewModel and cannot be overridden.`)})}_wrapMethods(){for(const i of w)if(Object.getOwnPropertyDescriptor(this,i)?.value!==void 0)throw new Error(`[mvc-kit] "${i}" is a reserved property on ViewModel and cannot be overridden.`);const t=this,s=new Set,e=[];d&&(this._activeOps=new Map),g(this,b.prototype,(i,n)=>{if(n.get||n.set||typeof n.value!="function"||i.startsWith("_")||A.has(i)||s.has(i))return;s.add(i);const a=n.value;let o=!1;const l=function(...h){if(t._disposed){d&&console.warn(`[mvc-kit] "${i}" called after dispose — ignored.`);return}d&&!t._initialized&&console.warn(`[mvc-kit] "${i}" called before init(). Async tracking is active only after init().`);let u;try{u=a.apply(t,h)}catch(_){throw _}if(!u||typeof u.then!="function")return o||(o=!0,t._asyncStates.delete(i),t._asyncSnapshots.delete(i),t[i]=a.bind(t)),u;let c=t._asyncStates.get(i);return c||(c={loading:!1,error:null,errorCode:null,count:0},t._asyncStates.set(i,c)),c.count++,c.loading=!0,c.error=null,c.errorCode=null,t._asyncSnapshots.set(i,Object.freeze({loading:!0,error:null,errorCode:null})),t._notifyAsync(),d&&t._activeOps&&t._activeOps.set(i,(t._activeOps.get(i)??0)+1),u.then(_=>{if(t._disposed)return _;if(c.count--,c.loading=c.count>0,t._asyncSnapshots.set(i,Object.freeze({loading:c.loading,error:c.error,errorCode:c.errorCode})),t._notifyAsync(),d&&t._activeOps){const f=(t._activeOps.get(i)??1)-1;f<=0?t._activeOps.delete(i):t._activeOps.set(i,f)}return _},_=>{if(y(_)){if(t._disposed||(c.count--,c.loading=c.count>0,t._asyncSnapshots.set(i,Object.freeze({loading:c.loading,error:c.error,errorCode:c.errorCode})),t._notifyAsync()),d&&t._activeOps){const p=(t._activeOps.get(i)??1)-1;p<=0?t._activeOps.delete(i):t._activeOps.set(i,p)}return}if(t._disposed)return;c.count--,c.loading=c.count>0;const f=T(_);if(c.error=f.message,c.errorCode=f.code,t._asyncSnapshots.set(i,Object.freeze({loading:c.loading,error:f.message,errorCode:f.code})),t._notifyAsync(),d&&t._activeOps){const p=(t._activeOps.get(i)??1)-1;p<=0?t._activeOps.delete(i):t._activeOps.set(i,p)}throw _})};e.push(i),t[i]=l}),e.length>0&&this.addCleanup(()=>{const i=d&&t._activeOps?new Map(t._activeOps):null;for(const n of e)d?t[n]=()=>{console.warn(`[mvc-kit] "${n}" called after dispose — ignored.`)}:t[n]=()=>{};t._asyncListeners.clear(),t._asyncStates.clear(),t._asyncSnapshots.clear(),d&&i&&i.size>0&&t._scheduleGhostCheck(i)})}_scheduleGhostCheck(t){d&&setTimeout(()=>{for(const[s,e]of t)console.warn(`[mvc-kit] Ghost async operation detected: "${s}" had ${e} pending call(s) when the ViewModel was disposed. Consider using disposeSignal to cancel in-flight work.`)},this.constructor.GHOST_TIMEOUT)}_installStateProxy(){const t=new Proxy({},{get:(s,e)=>(this._stateTracking?.add(e),this._state[e]),ownKeys:()=>Reflect.ownKeys(this._state),getOwnPropertyDescriptor:(s,e)=>Reflect.getOwnPropertyDescriptor(this._state,e),set:()=>{throw new Error("Cannot mutate state directly. Use set() instead.")},has:(s,e)=>e in this._state});Object.defineProperty(this,"state",{get:()=>this._stateTracking?t:this._state,configurable:!0,enumerable:!0})}_trackSubscribables(){for(const t of Object.getOwnPropertyNames(this)){const s=this[t];if(!O(s))continue;const e={source:s,revision:0,unsubscribe:s.subscribe(()=>{if(!this._disposed){e.revision++,this._revision++,this._state=Object.freeze({...this._state});for(const i of this._listeners)i(this._state,this._state)}})};this._trackedSources.set(t,e),Object.defineProperty(this,t,{get:()=>(this._sourceTracking?.set(t,e),s),configurable:!0,enumerable:!1})}}_memoizeGetters(){const t=new Set;g(this,b.prototype,(s,e)=>{!e.get||t.has(s)||(t.add(s),this._wrapGetter(s,e.get))})}_wrapGetter(t,s){let e,i=-1,n,a,o;Object.defineProperty(this,t,{get:()=>{if(this._disposed||i===this._revision)return e;if(n&&a){let c=!0;for(const[_,f]of a)if(this._state[_]!==f){c=!1;break}if(c&&o)for(const[_,f]of o){const p=this._trackedSources.get(_);if(p&&p.revision!==f){c=!1;break}}if(c)return i=this._revision,e}const l=this._stateTracking,h=this._sourceTracking;this._stateTracking=new Set,this._sourceTracking=new Map;try{e=s.call(this)}catch(c){throw this._stateTracking=l,this._sourceTracking=h,c}n=this._stateTracking;const u=this._sourceTracking;if(this._stateTracking=l,this._sourceTracking=h,l)for(const c of n)l.add(c);if(h)for(const[c,_]of u)h.set(c,_);a=new Map;for(const c of n)a.set(c,this._state[c]);o=new Map;for(const[c,_]of u)o.set(c,_.revision);return i=this._revision,e},configurable:!0,enumerable:!0})}}class x{_state;_committed;_disposed=!1;_initialized=!1;_listeners=new Set;_abortController=null;_cleanups=null;constructor(t){const s=Object.freeze({...t});this._state=s,this._committed=s}get state(){return this._state}get committed(){return this._committed}get dirty(){return!this.shallowEqual(this._state,this._committed)}get errors(){return this.validate(this._state)}get valid(){return Object.keys(this.errors).length===0}get disposed(){return this._disposed}get initialized(){return this._initialized}get disposeSignal(){return this._abortController||(this._abortController=new AbortController),this._abortController.signal}init(){if(!(this._initialized||this._disposed))return this._initialized=!0,this.onInit?.()}set(t){if(this._disposed)throw new Error("Cannot set state on disposed Model");const s=typeof t=="function"?t(this._state):t;if(!Object.keys(s).some(o=>s[o]!==this._state[o]))return;const n=this._state,a=Object.freeze({...n,...s});this._state=a,this.onSet?.(n,a);for(const o of this._listeners)o(a,n)}commit(){if(this._disposed)throw new Error("Cannot commit on disposed Model");this._committed=this._state}rollback(){if(this._disposed)throw new Error("Cannot rollback on disposed Model");if(this.shallowEqual(this._state,this._committed))return;const t=this._state;this._state=this._committed,this.onSet?.(t,this._state);for(const s of this._listeners)s(this._state,t)}subscribe(t){return this._disposed?()=>{}:(this._listeners.add(t),()=>{this._listeners.delete(t)})}dispose(){if(!this._disposed){if(this._disposed=!0,this._abortController?.abort(),this._cleanups){for(const t of this._cleanups)t();this._cleanups=null}this.onDispose?.(),this._listeners.clear()}}validate(t){return{}}addCleanup(t){this._cleanups||(this._cleanups=[]),this._cleanups.push(t)}subscribeTo(t,s){const e=t.subscribe(s);return this.addCleanup(e),e}shallowEqual(t,s){const e=Object.keys(t),i=Object.keys(s);if(e.length!==i.length)return!1;for(const n of e)if(t[n]!==s[n])return!1;return!0}}const M=typeof __MVC_KIT_DEV__<"u"&&__MVC_KIT_DEV__;class k{static MAX_SIZE=0;static TTL=0;_items=[];_disposed=!1;_listeners=new Set;_index=new Map;_abortController=null;_cleanups=null;_timestamps=null;_evictionTimer=null;constructor(t=[]){let s=[...t];if(this._ttl>0){this._timestamps=new Map;const e=Date.now();for(const i of s)this._timestamps.set(i.id,e)}if(this._maxSize>0&&s.length>this._maxSize){const e=s.length-this._maxSize,i=s.slice(0,e);s=s.slice(e);for(const n of i)this._timestamps?.delete(n.id)}this._items=Object.freeze(s),this.rebuildIndex(),this._scheduleEvictionTimer()}get state(){return this._items}get items(){return this._items}get length(){return this._items.length}get disposed(){return this._disposed}get disposeSignal(){return this._abortController||(this._abortController=new AbortController),this._abortController.signal}get _maxSize(){return this.constructor.MAX_SIZE}get _ttl(){return this.constructor.TTL}add(...t){if(this._disposed)throw new Error("Cannot add to disposed Collection");if(t.length===0)return;const s=new Set,e=[];for(const a of t)!this._index.has(a.id)&&!s.has(a.id)&&(e.push(a),s.add(a.id));if(e.length===0)return;const i=this._items;let n=[...i,...e];for(const a of e)this._index.set(a.id,a);if(this._timestamps){const a=Date.now();for(const o of e)this._timestamps.set(o.id,a)}this._maxSize>0&&n.length>this._maxSize&&(n=this._evictForCapacity(n)),this._items=Object.freeze(n),this.notify(i),this._scheduleEvictionTimer()}upsert(...t){if(this._disposed)throw new Error("Cannot upsert on disposed Collection");if(t.length===0)return;const s=new Map;for(const l of t)s.set(l.id,l);const e=this._items;let i=!1;const n=new Set,a=[];for(const l of e)if(s.has(l.id)){const h=s.get(l.id);h!==l&&(i=!0),a.push(h),n.add(l.id)}else a.push(l);for(const[l,h]of s)n.has(l)||(a.push(h),i=!0);if(!i)return;if(this._timestamps){const l=Date.now();for(const[h]of s)this._timestamps.set(h,l)}for(const[l,h]of s)this._index.set(l,h);let o=a;this._maxSize>0&&o.length>this._maxSize&&(o=this._evictForCapacity(o)),this._items=Object.freeze(o),this.notify(e),this._scheduleEvictionTimer()}remove(...t){if(this._disposed)throw new Error("Cannot remove from disposed Collection");if(t.length===0)return;const s=new Set(t),e=this._items.filter(n=>!s.has(n.id));if(e.length===this._items.length)return;const i=this._items;this._items=Object.freeze(e);for(const n of t)this._index.delete(n),this._timestamps?.delete(n);this.notify(i),this._scheduleEvictionTimer()}update(t,s){if(this._disposed)throw new Error("Cannot update disposed Collection");const e=this._items.findIndex(u=>u.id===t);if(e===-1)return;const i=this._items[e],n={...i,...s,id:t};if(!Object.keys(s).some(u=>s[u]!==i[u]))return;const l=this._items,h=[...l];h[e]=n,this._items=Object.freeze(h),this._index.set(t,n),this.notify(l)}reset(t){if(this._disposed)throw new Error("Cannot reset disposed Collection");const s=this._items;if(this._timestamps){this._timestamps.clear();const i=Date.now();for(const n of t)this._timestamps.set(n.id,i)}let e=[...t];this._maxSize>0&&e.length>this._maxSize&&(e=this._evictForCapacity(e)),this._items=Object.freeze(e),this.rebuildIndex(),this.notify(s),this._scheduleEvictionTimer()}clear(){if(this._disposed)throw new Error("Cannot clear disposed Collection");if(this._items.length===0)return;const t=this._items;this._items=Object.freeze([]),this._index.clear(),this._timestamps?.clear(),this._clearEvictionTimer(),this.notify(t)}optimistic(t){if(this._disposed)throw new Error("Cannot perform optimistic update on disposed Collection");const s=this._items,e=this._timestamps?new Map(this._timestamps):null;t();let i=!1;return()=>{if(i||this._disposed)return;i=!0;const n=this._items;this._items=s,e&&(this._timestamps=e),this.rebuildIndex(),this.notify(n),this._scheduleEvictionTimer()}}get(t){return this._index.get(t)}has(t){return this._index.has(t)}find(t){return this._items.find(t)}filter(t){return this._items.filter(t)}sorted(t){return[...this._items].sort(t)}map(t){return this._items.map(t)}subscribe(t){return this._disposed?()=>{}:(this._listeners.add(t),()=>{this._listeners.delete(t)})}dispose(){if(!this._disposed){if(this._disposed=!0,this._clearEvictionTimer(),this._abortController?.abort(),this._cleanups){for(const t of this._cleanups)t();this._cleanups=null}this.onDispose?.(),this._listeners.clear(),this._index.clear(),this._timestamps?.clear()}}addCleanup(t){this._cleanups||(this._cleanups=[]),this._cleanups.push(t)}notify(t){for(const s of this._listeners)s(this._items,t)}rebuildIndex(){this._index.clear();for(const t of this._items)this._index.set(t.id,t)}_evictForCapacity(t){const s=t.length-this._maxSize;if(s<=0)return t;const e=t.slice(0,s),i=this._applyOnEvict(e,"capacity");if(i===!1||i.length===0)return t;const n=new Set(i.map(o=>o.id)),a=t.filter(o=>!n.has(o.id));for(const o of i)this._index.delete(o.id),this._timestamps?.delete(o.id);return a}_applyOnEvict(t,s){if(!this.onEvict)return t;const e=this.onEvict(t,s);if(e===!1){if(M&&s==="capacity"&&this._maxSize>0){const i=this._items.length+t.length;i>this._maxSize*2&&console.warn(`[mvc-kit] Collection exceeded 2x MAX_SIZE (${i}/${this._maxSize}). onEvict is vetoing eviction — this may cause unbounded growth.`)}return!1}if(Array.isArray(e)){const i=new Set(t.map(n=>n.id));return e.filter(n=>i.has(n.id))}return t}_sweepExpired(){if(this._disposed||!this._timestamps||this._ttl<=0)return;const t=Date.now(),s=this._ttl,e=[];for(const o of this._items){const l=this._timestamps.get(o.id);l!==void 0&&t-l>=s&&e.push(o)}if(e.length===0){this._scheduleEvictionTimer();return}const i=this._applyOnEvict(e,"ttl");if(i===!1){this._scheduleEvictionTimer();return}if(i.length===0){this._scheduleEvictionTimer();return}const n=new Set(i.map(o=>o.id)),a=this._items;this._items=Object.freeze(a.filter(o=>!n.has(o.id)));for(const o of i)this._index.delete(o.id),this._timestamps.delete(o.id);this.notify(a),this._scheduleEvictionTimer()}_scheduleEvictionTimer(){if(this._clearEvictionTimer(),this._disposed||!this._timestamps||this._ttl<=0||this._timestamps.size===0)return;const t=Date.now(),s=this._ttl;let e=1/0;for(const n of this._timestamps.values())n<e&&(e=n);const i=Math.max(0,e+s-t);this._evictionTimer=setTimeout(()=>this._sweepExpired(),i)}_clearEvictionTimer(){this._evictionTimer!==null&&(clearTimeout(this._evictionTimer),this._evictionTimer=null)}}class j{_disposed=!1;_initialized=!1;_abortController=null;_cleanups=null;get disposed(){return this._disposed}get initialized(){return this._initialized}get disposeSignal(){return this._abortController||(this._abortController=new AbortController),this._abortController.signal}init(){if(!(this._initialized||this._disposed))return this._initialized=!0,this.onInit?.()}dispose(){if(!this._disposed){if(this._disposed=!0,this._abortController?.abort(),this._cleanups){for(const t of this._cleanups)t();this._cleanups=null}this.onDispose?.()}}addCleanup(t){this._cleanups||(this._cleanups=[]),this._cleanups.push(t)}subscribeTo(t,s){const e=t.subscribe(s);return this.addCleanup(e),e}}class D{_disposed=!1;_initialized=!1;_abortController=null;_cleanups=null;get disposed(){return this._disposed}get initialized(){return this._initialized}get disposeSignal(){return this._abortController||(this._abortController=new AbortController),this._abortController.signal}init(){if(!(this._initialized||this._disposed))return this._initialized=!0,this.onInit?.()}dispose(){if(!this._disposed){if(this._disposed=!0,this._abortController?.abort(),this._cleanups){for(const t of this._cleanups)t();this._cleanups=null}this.onDispose?.()}}addCleanup(t){this._cleanups||(this._cleanups=[]),this._cleanups.push(t)}}const S=typeof __MVC_KIT_DEV__<"u"&&__MVC_KIT_DEV__,I=Object.freeze({connected:!1,reconnecting:!1,attempt:0,error:null});class P{static RECONNECT_BASE=1e3;static RECONNECT_MAX=3e4;static RECONNECT_FACTOR=2;static MAX_ATTEMPTS=1/0;_status=I;_connState=0;_disposed=!1;_initialized=!1;_listeners=new Set;_handlers=new Map;_abortController=null;_connectAbort=null;_reconnectTimer=null;_cleanups=null;get state(){return this._status}subscribe(t){return this._disposed?()=>{}:(this._listeners.add(t),()=>{this._listeners.delete(t)})}get disposed(){return this._disposed}get initialized(){return this._initialized}get disposeSignal(){return this._abortController||(this._abortController=new AbortController),this._abortController.signal}init(){if(!(this._initialized||this._disposed))return this._initialized=!0,this.onInit?.()}dispose(){if(!this._disposed){this._disposed=!0,this._connState=4,this._reconnectTimer!==null&&(clearTimeout(this._reconnectTimer),this._reconnectTimer=null),this._connectAbort?.abort(),this._connectAbort=null,this._abortController?.abort();try{this.close()}catch{}if(this._cleanups){for(const t of this._cleanups)t();this._cleanups=null}this.onDispose?.(),this._listeners.clear(),this._handlers.clear()}}connect(){if(this._disposed){S&&console.warn("[mvc-kit] connect() called after dispose — ignored.");return}S&&!this._initialized&&console.warn("[mvc-kit] connect() called before init()."),!(this._connState===1||this._connState===2)&&(this._reconnectTimer!==null&&(clearTimeout(this._reconnectTimer),this._reconnectTimer=null),this._attemptConnect(0))}disconnect(){if(!this._disposed){if(this._reconnectTimer!==null&&(clearTimeout(this._reconnectTimer),this._reconnectTimer=null),this._connectAbort?.abort(),this._connectAbort=null,this._connState===2||this._connState===1){this._connState=0;try{this.close()}catch{}}else this._connState=0;this._setStatus({connected:!1,reconnecting:!1,attempt:0,error:null})}}receive(t,s){if(this._disposed){S&&console.warn(`[mvc-kit] receive("${String(t)}") called after dispose — ignored.`);return}const e=this._handlers.get(t);if(e)for(const i of e)i(s)}disconnected(){this._disposed||this._connState!==2&&this._connState!==1||(this._connectAbort?.abort(),this._connectAbort=null,this._connState=3,this._scheduleReconnect(1))}on(t,s){if(this._disposed)return()=>{};let e=this._handlers.get(t);return e||(e=new Set,this._handlers.set(t,e)),e.add(s),()=>{e.delete(s)}}once(t,s){const e=this.on(t,i=>{e(),s(i)});return e}addCleanup(t){this._cleanups||(this._cleanups=[]),this._cleanups.push(t)}subscribeTo(t,s){const e=t.subscribe(s);return this.addCleanup(e),e}_calculateDelay(t){const s=this.constructor,e=Math.min(s.RECONNECT_BASE*Math.pow(s.RECONNECT_FACTOR,t),s.RECONNECT_MAX);return Math.random()*e}_setStatus(t){const s=this._status;if(!(s.connected===t.connected&&s.reconnecting===t.reconnecting&&s.attempt===t.attempt&&s.error===t.error)){this._status=Object.freeze(t);for(const e of this._listeners)e(this._status,s)}}_attemptConnect(t){if(this._disposed)return;this._connState=1,this._connectAbort?.abort(),this._connectAbort=new AbortController;const s=this._abortController?AbortSignal.any([this._abortController.signal,this._connectAbort.signal]):this._connectAbort.signal;this._setStatus({connected:!1,reconnecting:t>0,attempt:t,error:null});let e;try{e=this.open(s)}catch(i){this._onOpenFailed(t,i);return}e&&typeof e.then=="function"?e.then(()=>this._onOpenSucceeded(),i=>this._onOpenFailed(t,i)):this._onOpenSucceeded()}_onOpenSucceeded(){this._disposed||this._connState===1&&(this._connState=2,this._setStatus({connected:!0,reconnecting:!1,attempt:0,error:null}))}_onOpenFailed(t,s){this._disposed||this._connState!==0&&(this._connectAbort?.abort(),this._connectAbort=null,this._connState=3,this._scheduleReconnect(t+1,s))}_scheduleReconnect(t,s){const e=this.constructor;if(t>e.MAX_ATTEMPTS){this._connState=0,this._setStatus({connected:!1,reconnecting:!1,attempt:t,error:s instanceof Error?s.message:"Max reconnection attempts reached"});return}const i=s instanceof Error?s.message:s?String(s):null;this._setStatus({connected:!1,reconnecting:!0,attempt:t,error:i});const n=this._calculateDelay(t-1);this._reconnectTimer=setTimeout(()=>{this._reconnectTimer=null,this._attemptConnect(t)},n)}}exports.EventBus=m.EventBus;exports.hasSingleton=m.hasSingleton;exports.singleton=m.singleton;exports.teardown=m.teardown;exports.teardownAll=m.teardownAll;exports.Channel=P;exports.Collection=k;exports.Controller=j;exports.HttpError=C;exports.Model=x;exports.Service=D;exports.ViewModel=b;exports.classifyError=T;exports.isAbortError=y;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const b=require("./singleton-L-u2W_lX.cjs"),w=require("./PersistentCollection-B8kNECDj.cjs");class z extends Error{constructor(t,s){super(s??`HTTP ${t}`),this.status=t,this.name="HttpError"}}function m(r){return r instanceof Error&&r.name==="AbortError"}function T(r){return r===401?"unauthorized":r===403?"forbidden":r===404?"not_found":r===422?"validation":r===429?"rate_limited":r>=500?"server_error":"unknown"}function x(r){return typeof r=="object"&&r!==null&&typeof r.status=="number"&&typeof r.statusText=="string"&&!(r instanceof Error)}function O(r){return r instanceof Error&&r.name==="AbortError"?{code:"abort",message:"Request was aborted",original:r}:r instanceof z?{code:T(r.status),message:r.message,status:r.status,original:r}:x(r)?{code:T(r.status),message:r.statusText||`HTTP ${r.status}`,status:r.status,original:r}:r instanceof TypeError&&r.message.toLowerCase().includes("fetch")?{code:"network",message:r.message,original:r}:r instanceof Error&&r.name==="TimeoutError"?{code:"timeout",message:r.message,original:r}:r instanceof Error?{code:"unknown",message:r.message,original:r}:{code:"unknown",message:String(r),original:r}}const d=typeof __MVC_KIT_DEV__<"u"&&__MVC_KIT_DEV__;function M(r){return r!==null&&typeof r=="object"&&typeof r.subscribe=="function"}function S(r,t,s){let e=Object.getPrototypeOf(r);for(;e&&e!==t;){const n=Object.getOwnPropertyDescriptors(e);for(const[o,c]of Object.entries(n))o!=="constructor"&&s(o,c,e);e=Object.getPrototypeOf(e)}}const j=Object.freeze({loading:!1,error:null,errorCode:null}),E=["async","subscribeAsync"],P=new Set(["onInit","onSet","onDispose"]);class y{_state;_initialState;_disposed=!1;_initialized=!1;_listeners=new Set;_abortController=null;_cleanups=null;_subscriptionCleanups=null;_eventBus=null;_revision=0;_stateTracking=null;_sourceTracking=null;_trackedSources=new Map;_asyncStates=new Map;_asyncSnapshots=new Map;_asyncListeners=new Set;_asyncProxy=null;_activeOps=null;static GHOST_TIMEOUT=3e3;constructor(t){this._state=Object.freeze({...t}),this._initialState=this._state,this._guardReservedKeys()}get state(){return this._state}get disposed(){return this._disposed}get initialized(){return this._initialized}get disposeSignal(){return this._abortController||(this._abortController=new AbortController),this._abortController.signal}get events(){return this._eventBus||(this._eventBus=new b.EventBus),this._eventBus}init(){if(!(this._initialized||this._disposed))return this._initialized=!0,this._trackSubscribables(),this._installStateProxy(),this._memoizeGetters(),this._wrapMethods(),this.onInit?.()}set(t){if(this._disposed)return;if(d&&this._stateTracking){console.error("[mvc-kit] set() called inside a getter. Getters must be pure — they read state and return a value. They must never call set(), which would cause an infinite render loop. Move this logic to an action method.");return}const s=typeof t=="function"?t(this._state):t;if(!Object.keys(s).some(l=>s[l]!==this._state[l]))return;const o=this._state,c=Object.freeze({...o,...s});this._state=c,this._revision++,this.onSet?.(o,c);for(const l of this._listeners)l(c,o)}emit(t,s){(this._eventBus?.disposed??this._disposed)||this.events.emit(t,s)}subscribe(t){return this._disposed?()=>{}:(this._listeners.add(t),()=>{this._listeners.delete(t)})}dispose(){if(!this._disposed){if(this._disposed=!0,this._teardownSubscriptions(),this._abortController?.abort(),this._cleanups){for(const t of this._cleanups)t();this._cleanups=null}this._eventBus?.dispose(),this.onDispose?.(),this._listeners.clear()}}reset(t){if(!this._disposed){this._abortController?.abort(),this._abortController=null,this._teardownSubscriptions(),this._state=t?Object.freeze({...t}):this._initialState,this._revision++,this._asyncStates.clear(),this._asyncSnapshots.clear(),this._notifyAsync(),this._trackSubscribables();for(const s of this._listeners)s(this._state,this._state);return this.onInit?.()}}addCleanup(t){this._cleanups||(this._cleanups=[]),this._cleanups.push(t)}subscribeTo(t,s){const e=t.subscribe(s);return this._subscriptionCleanups||(this._subscriptionCleanups=[]),this._subscriptionCleanups.push(e),e}get async(){if(!this._asyncProxy){const t=this;this._asyncProxy=new Proxy({},{get(s,e){return t._asyncSnapshots.get(e)??j},has(s,e){return t._asyncSnapshots.has(e)},ownKeys(){return Array.from(t._asyncSnapshots.keys())},getOwnPropertyDescriptor(s,e){if(t._asyncSnapshots.has(e))return{configurable:!0,enumerable:!0,value:t._asyncSnapshots.get(e)}}})}return this._asyncProxy}subscribeAsync(t){return this._disposed?()=>{}:(this._asyncListeners.add(t),()=>{this._asyncListeners.delete(t)})}_notifyAsync(){for(const t of this._asyncListeners)t()}_teardownSubscriptions(){for(const t of this._trackedSources.values())t.unsubscribe();if(this._trackedSources.clear(),this._subscriptionCleanups){for(const t of this._subscriptionCleanups)t();this._subscriptionCleanups=null}}_guardReservedKeys(){S(this,y.prototype,t=>{if(E.includes(t))throw new Error(`[mvc-kit] "${t}" is a reserved property on ViewModel and cannot be overridden.`)})}_wrapMethods(){for(const n of E)if(Object.getOwnPropertyDescriptor(this,n)?.value!==void 0)throw new Error(`[mvc-kit] "${n}" is a reserved property on ViewModel and cannot be overridden.`);const t=this,s=new Set,e=[];d&&(this._activeOps=new Map),S(this,y.prototype,(n,o)=>{if(o.get||o.set||typeof o.value!="function"||n.startsWith("_")||P.has(n)||s.has(n))return;s.add(n);const c=o.value;let l=!1;const p=function(...g){if(t._disposed){d&&console.warn(`[mvc-kit] "${n}" called after dispose — ignored.`);return}d&&!t._initialized&&console.warn(`[mvc-kit] "${n}" called before init(). Async tracking is active only after init().`);let u;try{u=c.apply(t,g)}catch(a){throw a}if(!u||typeof u.then!="function")return l||(l=!0,t._asyncStates.delete(n),t._asyncSnapshots.delete(n),t[n]=c.bind(t)),u;let i=t._asyncStates.get(n);return i||(i={loading:!1,error:null,errorCode:null,count:0},t._asyncStates.set(n,i)),i.count++,i.loading=!0,i.error=null,i.errorCode=null,t._asyncSnapshots.set(n,Object.freeze({loading:!0,error:null,errorCode:null})),t._notifyAsync(),d&&t._activeOps&&t._activeOps.set(n,(t._activeOps.get(n)??0)+1),u.then(a=>{if(t._disposed)return a;if(i.count--,i.loading=i.count>0,t._asyncSnapshots.set(n,Object.freeze({loading:i.loading,error:i.error,errorCode:i.errorCode})),t._notifyAsync(),d&&t._activeOps){const _=(t._activeOps.get(n)??1)-1;_<=0?t._activeOps.delete(n):t._activeOps.set(n,_)}return a},a=>{if(m(a)){if(t._disposed||(i.count--,i.loading=i.count>0,t._asyncSnapshots.set(n,Object.freeze({loading:i.loading,error:i.error,errorCode:i.errorCode})),t._notifyAsync()),d&&t._activeOps){const h=(t._activeOps.get(n)??1)-1;h<=0?t._activeOps.delete(n):t._activeOps.set(n,h)}return}if(t._disposed)return;i.count--,i.loading=i.count>0;const _=O(a);if(i.error=_.message,i.errorCode=_.code,t._asyncSnapshots.set(n,Object.freeze({loading:i.loading,error:_.message,errorCode:_.code})),t._notifyAsync(),d&&t._activeOps){const h=(t._activeOps.get(n)??1)-1;h<=0?t._activeOps.delete(n):t._activeOps.set(n,h)}throw a})};e.push(n),t[n]=p}),e.length>0&&this.addCleanup(()=>{const n=d&&t._activeOps?new Map(t._activeOps):null;for(const o of e)d?t[o]=()=>{console.warn(`[mvc-kit] "${o}" called after dispose — ignored.`)}:t[o]=()=>{};t._asyncListeners.clear(),t._asyncStates.clear(),t._asyncSnapshots.clear(),d&&n&&n.size>0&&t._scheduleGhostCheck(n)})}_scheduleGhostCheck(t){d&&setTimeout(()=>{for(const[s,e]of t)console.warn(`[mvc-kit] Ghost async operation detected: "${s}" had ${e} pending call(s) when the ViewModel was disposed. Consider using disposeSignal to cancel in-flight work.`)},this.constructor.GHOST_TIMEOUT)}_installStateProxy(){const t=new Proxy({},{get:(s,e)=>(this._stateTracking?.add(e),this._state[e]),ownKeys:()=>Reflect.ownKeys(this._state),getOwnPropertyDescriptor:(s,e)=>Reflect.getOwnPropertyDescriptor(this._state,e),set:()=>{throw new Error("Cannot mutate state directly. Use set() instead.")},has:(s,e)=>e in this._state});Object.defineProperty(this,"state",{get:()=>this._stateTracking?t:this._state,configurable:!0,enumerable:!0})}_trackSubscribables(){for(const t of Object.getOwnPropertyNames(this)){const s=this[t];if(!M(s))continue;const e={source:s,revision:0,unsubscribe:s.subscribe(()=>{if(!this._disposed){e.revision++,this._revision++,this._state=Object.freeze({...this._state});for(const n of this._listeners)n(this._state,this._state)}})};this._trackedSources.set(t,e),Object.defineProperty(this,t,{get:()=>(this._sourceTracking?.set(t,e),s),configurable:!0,enumerable:!1})}}_memoizeGetters(){const t=new Set;S(this,y.prototype,(s,e)=>{!e.get||t.has(s)||(t.add(s),this._wrapGetter(s,e.get))})}_wrapGetter(t,s){let e,n=-1,o,c,l;Object.defineProperty(this,t,{get:()=>{if(this._disposed||n===this._revision)return e;if(o&&c){let i=!0;for(const[a,_]of c)if(this._state[a]!==_){i=!1;break}if(i&&l)for(const[a,_]of l){const h=this._trackedSources.get(a);if(h&&h.revision!==_){i=!1;break}}if(i)return n=this._revision,e}const p=this._stateTracking,g=this._sourceTracking;this._stateTracking=new Set,this._sourceTracking=new Map;try{e=s.call(this)}catch(i){throw this._stateTracking=p,this._sourceTracking=g,i}o=this._stateTracking;const u=this._sourceTracking;if(this._stateTracking=p,this._sourceTracking=g,p)for(const i of o)p.add(i);if(g)for(const[i,a]of u)g.set(i,a);c=new Map;for(const i of o)c.set(i,this._state[i]);l=new Map;for(const[i,a]of u)l.set(i,a.revision);return n=this._revision,e},configurable:!0,enumerable:!0})}}class D{_state;_committed;_disposed=!1;_initialized=!1;_listeners=new Set;_abortController=null;_cleanups=null;constructor(t){const s=Object.freeze({...t});this._state=s,this._committed=s}get state(){return this._state}get committed(){return this._committed}get dirty(){return!this.shallowEqual(this._state,this._committed)}get errors(){return this.validate(this._state)}get valid(){return Object.keys(this.errors).length===0}get disposed(){return this._disposed}get initialized(){return this._initialized}get disposeSignal(){return this._abortController||(this._abortController=new AbortController),this._abortController.signal}init(){if(!(this._initialized||this._disposed))return this._initialized=!0,this.onInit?.()}set(t){if(this._disposed)throw new Error("Cannot set state on disposed Model");const s=typeof t=="function"?t(this._state):t;if(!Object.keys(s).some(l=>s[l]!==this._state[l]))return;const o=this._state,c=Object.freeze({...o,...s});this._state=c,this.onSet?.(o,c);for(const l of this._listeners)l(c,o)}commit(){if(this._disposed)throw new Error("Cannot commit on disposed Model");this._committed=this._state}rollback(){if(this._disposed)throw new Error("Cannot rollback on disposed Model");if(this.shallowEqual(this._state,this._committed))return;const t=this._state;this._state=this._committed,this.onSet?.(t,this._state);for(const s of this._listeners)s(this._state,t)}subscribe(t){return this._disposed?()=>{}:(this._listeners.add(t),()=>{this._listeners.delete(t)})}dispose(){if(!this._disposed){if(this._disposed=!0,this._abortController?.abort(),this._cleanups){for(const t of this._cleanups)t();this._cleanups=null}this.onDispose?.(),this._listeners.clear()}}validate(t){return{}}addCleanup(t){this._cleanups||(this._cleanups=[]),this._cleanups.push(t)}subscribeTo(t,s){const e=t.subscribe(s);return this.addCleanup(e),e}shallowEqual(t,s){const e=Object.keys(t),n=Object.keys(s);if(e.length!==n.length)return!1;for(const o of e)if(t[o]!==s[o])return!1;return!0}}const f=typeof __MVC_KIT_DEV__<"u"&&__MVC_KIT_DEV__,k=Object.freeze({loading:!1,error:null,errorCode:null}),A=["async","subscribeAsync"],R=new Set(["onInit","onDispose"]);class v extends w.Collection{_external=null;_initialized=!1;_asyncStates=new Map;_asyncSnapshots=new Map;_asyncListeners=new Set;_asyncProxy=null;_activeOps=null;static GHOST_TIMEOUT=3e3;constructor(t){const s=t!=null&&!Array.isArray(t);if(super(s?[]:t??[]),s&&(this._external=t,f)){const e=this.constructor;(e.MAX_SIZE>0||e.TTL>0)&&console.warn(`[mvc-kit] Resource "${e.name}" has MAX_SIZE or TTL set but uses an injected Collection. Configure these on the Collection instead.`)}this._guardReservedKeys()}get initialized(){return this._initialized}init(){if(!(this._initialized||this.disposed))return this._initialized=!0,this._wrapMethods(),this.onInit?.()}get state(){return this._external?this._external.state:super.state}get items(){return this._external?this._external.items:super.items}get length(){return this._external?this._external.length:super.length}add(...t){this._external?this._external.add(...t):super.add(...t)}upsert(...t){this._external?this._external.upsert(...t):super.upsert(...t)}update(t,s){this._external?this._external.update(t,s):super.update(t,s)}remove(...t){this._external?this._external.remove(...t):super.remove(...t)}reset(t){this._external?this._external.reset(t):super.reset(t)}clear(){this._external?this._external.clear():super.clear()}optimistic(t){return this._external?this._external.optimistic(t):super.optimistic(t)}get(t){return this._external?this._external.get(t):super.get(t)}has(t){return this._external?this._external.has(t):super.has(t)}find(t){return this._external?this._external.find(t):super.find(t)}filter(t){return this._external?this._external.filter(t):super.filter(t)}sorted(t){return this._external?this._external.sorted(t):super.sorted(t)}map(t){return this._external?this._external.map(t):super.map(t)}subscribe(t){return this.disposed?()=>{}:this._external?this._external.subscribe(t):super.subscribe(t)}get async(){if(!this._asyncProxy){const t=this;this._asyncProxy=new Proxy({},{get(s,e){return t._asyncSnapshots.get(e)??k},has(s,e){return t._asyncSnapshots.has(e)},ownKeys(){return Array.from(t._asyncSnapshots.keys())},getOwnPropertyDescriptor(s,e){if(t._asyncSnapshots.has(e))return{configurable:!0,enumerable:!0,value:t._asyncSnapshots.get(e)}}})}return this._asyncProxy}subscribeAsync(t){return this.disposed?()=>{}:(this._asyncListeners.add(t),()=>{this._asyncListeners.delete(t)})}_notifyAsync(){for(const t of this._asyncListeners)t()}_guardReservedKeys(){S(this,v.prototype,t=>{if(A.includes(t))throw new Error(`[mvc-kit] "${t}" is a reserved property on Resource and cannot be overridden.`)})}_wrapMethods(){for(const n of A)if(Object.getOwnPropertyDescriptor(this,n)?.value!==void 0)throw new Error(`[mvc-kit] "${n}" is a reserved property on Resource and cannot be overridden.`);const t=this,s=new Set,e=[];f&&(this._activeOps=new Map),S(this,v.prototype,(n,o)=>{if(o.get||o.set||typeof o.value!="function"||n.startsWith("_")||R.has(n)||s.has(n))return;s.add(n);const c=o.value;let l=!1;const p=function(...g){if(t.disposed){f&&console.warn(`[mvc-kit] "${n}" called after dispose — ignored.`);return}f&&!t._initialized&&console.warn(`[mvc-kit] "${n}" called before init(). Async tracking is active only after init().`);let u;try{u=c.apply(t,g)}catch(a){throw a}if(!u||typeof u.then!="function")return l||(l=!0,t._asyncStates.delete(n),t._asyncSnapshots.delete(n),t[n]=c.bind(t)),u;let i=t._asyncStates.get(n);return i||(i={loading:!1,error:null,errorCode:null,count:0},t._asyncStates.set(n,i)),i.count++,i.loading=!0,i.error=null,i.errorCode=null,t._asyncSnapshots.set(n,Object.freeze({loading:!0,error:null,errorCode:null})),t._notifyAsync(),f&&t._activeOps&&t._activeOps.set(n,(t._activeOps.get(n)??0)+1),u.then(a=>{if(t.disposed)return a;if(i.count--,i.loading=i.count>0,t._asyncSnapshots.set(n,Object.freeze({loading:i.loading,error:i.error,errorCode:i.errorCode})),t._notifyAsync(),f&&t._activeOps){const _=(t._activeOps.get(n)??1)-1;_<=0?t._activeOps.delete(n):t._activeOps.set(n,_)}return a},a=>{if(m(a)){if(t.disposed||(i.count--,i.loading=i.count>0,t._asyncSnapshots.set(n,Object.freeze({loading:i.loading,error:i.error,errorCode:i.errorCode})),t._notifyAsync()),f&&t._activeOps){const h=(t._activeOps.get(n)??1)-1;h<=0?t._activeOps.delete(n):t._activeOps.set(n,h)}return}if(t.disposed)return;i.count--,i.loading=i.count>0;const _=O(a);if(i.error=_.message,i.errorCode=_.code,t._asyncSnapshots.set(n,Object.freeze({loading:i.loading,error:_.message,errorCode:_.code})),t._notifyAsync(),f&&t._activeOps){const h=(t._activeOps.get(n)??1)-1;h<=0?t._activeOps.delete(n):t._activeOps.set(n,h)}throw a})};e.push(n),t[n]=p}),e.length>0&&this.addCleanup(()=>{const n=f&&t._activeOps?new Map(t._activeOps):null;for(const o of e)f?t[o]=()=>{console.warn(`[mvc-kit] "${o}" called after dispose — ignored.`)}:t[o]=()=>{};t._asyncListeners.clear(),t._asyncStates.clear(),t._asyncSnapshots.clear(),f&&n&&n.size>0&&t._scheduleGhostCheck(n)})}_scheduleGhostCheck(t){f&&setTimeout(()=>{for(const[s,e]of t)console.warn(`[mvc-kit] Ghost async operation detected: "${s}" had ${e} pending call(s) when the Resource was disposed. Consider using disposeSignal to cancel in-flight work.`)},this.constructor.GHOST_TIMEOUT)}}class I{_disposed=!1;_initialized=!1;_abortController=null;_cleanups=null;get disposed(){return this._disposed}get initialized(){return this._initialized}get disposeSignal(){return this._abortController||(this._abortController=new AbortController),this._abortController.signal}init(){if(!(this._initialized||this._disposed))return this._initialized=!0,this.onInit?.()}dispose(){if(!this._disposed){if(this._disposed=!0,this._abortController?.abort(),this._cleanups){for(const t of this._cleanups)t();this._cleanups=null}this.onDispose?.()}}addCleanup(t){this._cleanups||(this._cleanups=[]),this._cleanups.push(t)}subscribeTo(t,s){const e=t.subscribe(s);return this.addCleanup(e),e}}class K{_disposed=!1;_initialized=!1;_abortController=null;_cleanups=null;get disposed(){return this._disposed}get initialized(){return this._initialized}get disposeSignal(){return this._abortController||(this._abortController=new AbortController),this._abortController.signal}init(){if(!(this._initialized||this._disposed))return this._initialized=!0,this.onInit?.()}dispose(){if(!this._disposed){if(this._disposed=!0,this._abortController?.abort(),this._cleanups){for(const t of this._cleanups)t();this._cleanups=null}this.onDispose?.()}}addCleanup(t){this._cleanups||(this._cleanups=[]),this._cleanups.push(t)}}const C=typeof __MVC_KIT_DEV__<"u"&&__MVC_KIT_DEV__,$=Object.freeze({connected:!1,reconnecting:!1,attempt:0,error:null});class L{static RECONNECT_BASE=1e3;static RECONNECT_MAX=3e4;static RECONNECT_FACTOR=2;static MAX_ATTEMPTS=1/0;_status=$;_connState=0;_disposed=!1;_initialized=!1;_listeners=new Set;_handlers=new Map;_abortController=null;_connectAbort=null;_reconnectTimer=null;_cleanups=null;get state(){return this._status}subscribe(t){return this._disposed?()=>{}:(this._listeners.add(t),()=>{this._listeners.delete(t)})}get disposed(){return this._disposed}get initialized(){return this._initialized}get disposeSignal(){return this._abortController||(this._abortController=new AbortController),this._abortController.signal}init(){if(!(this._initialized||this._disposed))return this._initialized=!0,this.onInit?.()}dispose(){if(!this._disposed){this._disposed=!0,this._connState=4,this._reconnectTimer!==null&&(clearTimeout(this._reconnectTimer),this._reconnectTimer=null),this._connectAbort?.abort(),this._connectAbort=null,this._abortController?.abort();try{this.close()}catch{}if(this._cleanups){for(const t of this._cleanups)t();this._cleanups=null}this.onDispose?.(),this._listeners.clear(),this._handlers.clear()}}connect(){if(this._disposed){C&&console.warn("[mvc-kit] connect() called after dispose — ignored.");return}C&&!this._initialized&&console.warn("[mvc-kit] connect() called before init()."),!(this._connState===1||this._connState===2)&&(this._reconnectTimer!==null&&(clearTimeout(this._reconnectTimer),this._reconnectTimer=null),this._attemptConnect(0))}disconnect(){if(!this._disposed){if(this._reconnectTimer!==null&&(clearTimeout(this._reconnectTimer),this._reconnectTimer=null),this._connectAbort?.abort(),this._connectAbort=null,this._connState===2||this._connState===1){this._connState=0;try{this.close()}catch{}}else this._connState=0;this._setStatus({connected:!1,reconnecting:!1,attempt:0,error:null})}}receive(t,s){if(this._disposed){C&&console.warn(`[mvc-kit] receive("${String(t)}") called after dispose — ignored.`);return}const e=this._handlers.get(t);if(e)for(const n of e)n(s)}disconnected(){this._disposed||this._connState!==2&&this._connState!==1||(this._connectAbort?.abort(),this._connectAbort=null,this._connState=3,this._scheduleReconnect(1))}on(t,s){if(this._disposed)return()=>{};let e=this._handlers.get(t);return e||(e=new Set,this._handlers.set(t,e)),e.add(s),()=>{e.delete(s)}}once(t,s){const e=this.on(t,n=>{e(),s(n)});return e}addCleanup(t){this._cleanups||(this._cleanups=[]),this._cleanups.push(t)}subscribeTo(t,s){const e=t.subscribe(s);return this.addCleanup(e),e}_calculateDelay(t){const s=this.constructor,e=Math.min(s.RECONNECT_BASE*Math.pow(s.RECONNECT_FACTOR,t),s.RECONNECT_MAX);return Math.random()*e}_setStatus(t){const s=this._status;if(!(s.connected===t.connected&&s.reconnecting===t.reconnecting&&s.attempt===t.attempt&&s.error===t.error)){this._status=Object.freeze(t);for(const e of this._listeners)e(this._status,s)}}_attemptConnect(t){if(this._disposed)return;this._connState=1,this._connectAbort?.abort(),this._connectAbort=new AbortController;const s=this._abortController?AbortSignal.any([this._abortController.signal,this._connectAbort.signal]):this._connectAbort.signal;this._setStatus({connected:!1,reconnecting:t>0,attempt:t,error:null});let e;try{e=this.open(s)}catch(n){this._onOpenFailed(t,n);return}e&&typeof e.then=="function"?e.then(()=>this._onOpenSucceeded(),n=>this._onOpenFailed(t,n)):this._onOpenSucceeded()}_onOpenSucceeded(){this._disposed||this._connState===1&&(this._connState=2,this._setStatus({connected:!0,reconnecting:!1,attempt:0,error:null}))}_onOpenFailed(t,s){this._disposed||this._connState!==0&&(this._connectAbort?.abort(),this._connectAbort=null,this._connState=3,this._scheduleReconnect(t+1,s))}_scheduleReconnect(t,s){const e=this.constructor;if(t>e.MAX_ATTEMPTS){this._connState=0,this._setStatus({connected:!1,reconnecting:!1,attempt:t,error:s instanceof Error?s.message:"Max reconnection attempts reached"});return}const n=s instanceof Error?s.message:s?String(s):null;this._setStatus({connected:!1,reconnecting:!0,attempt:t,error:n});const o=this._calculateDelay(t-1);this._reconnectTimer=setTimeout(()=>{this._reconnectTimer=null,this._attemptConnect(t)},o)}}exports.EventBus=b.EventBus;exports.hasSingleton=b.hasSingleton;exports.singleton=b.singleton;exports.teardown=b.teardown;exports.teardownAll=b.teardownAll;exports.Collection=w.Collection;exports.PersistentCollection=w.PersistentCollection;exports.Channel=L;exports.Controller=I;exports.HttpError=z;exports.Model=D;exports.Resource=v;exports.Service=K;exports.ViewModel=y;exports.classifyError=O;exports.isAbortError=m;
|
|
2
2
|
//# sourceMappingURL=mvc-kit.cjs.map
|