mvc-kit 2.7.1 → 2.9.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 +47 -1
- package/agent-config/claude-code/skills/guide/SKILL.md +1 -0
- package/agent-config/claude-code/skills/guide/anti-patterns.md +3 -3
- package/agent-config/claude-code/skills/guide/api-reference.md +146 -2
- package/agent-config/claude-code/skills/guide/patterns.md +120 -0
- package/agent-config/claude-code/skills/scaffold/templates/model.md +38 -1
- package/agent-config/copilot/copilot-instructions.md +54 -1
- package/agent-config/cursor/cursorrules +54 -1
- package/dist/Collection.cjs +69 -17
- package/dist/Collection.cjs.map +1 -1
- package/dist/Collection.d.ts.map +1 -1
- package/dist/Collection.js +69 -17
- package/dist/Collection.js.map +1 -1
- package/dist/Feed.cjs +86 -0
- package/dist/Feed.cjs.map +1 -0
- package/dist/Feed.d.ts +46 -0
- package/dist/Feed.d.ts.map +1 -0
- package/dist/Feed.js +86 -0
- package/dist/Feed.js.map +1 -0
- package/dist/Model.cjs +22 -4
- package/dist/Model.cjs.map +1 -1
- package/dist/Model.d.ts +2 -0
- package/dist/Model.d.ts.map +1 -1
- package/dist/Model.js +22 -4
- package/dist/Model.js.map +1 -1
- package/dist/Pagination.cjs +84 -0
- package/dist/Pagination.cjs.map +1 -0
- package/dist/Pagination.d.ts +39 -0
- package/dist/Pagination.d.ts.map +1 -0
- package/dist/Pagination.js +84 -0
- package/dist/Pagination.js.map +1 -0
- package/dist/PersistentCollection.cjs +16 -15
- package/dist/PersistentCollection.cjs.map +1 -1
- package/dist/PersistentCollection.d.ts +7 -1
- package/dist/PersistentCollection.d.ts.map +1 -1
- package/dist/PersistentCollection.js +16 -15
- package/dist/PersistentCollection.js.map +1 -1
- package/dist/Resource.cjs +23 -156
- package/dist/Resource.cjs.map +1 -1
- package/dist/Resource.d.ts +3 -2
- package/dist/Resource.d.ts.map +1 -1
- package/dist/Resource.js +23 -156
- package/dist/Resource.js.map +1 -1
- package/dist/Selection.cjs +99 -0
- package/dist/Selection.cjs.map +1 -0
- package/dist/Selection.d.ts +36 -0
- package/dist/Selection.d.ts.map +1 -0
- package/dist/Selection.js +99 -0
- package/dist/Selection.js.map +1 -0
- package/dist/Sorting.cjs +114 -0
- package/dist/Sorting.cjs.map +1 -0
- package/dist/Sorting.d.ts +43 -0
- package/dist/Sorting.d.ts.map +1 -0
- package/dist/Sorting.js +114 -0
- package/dist/Sorting.js.map +1 -0
- package/dist/ViewModel.cjs +177 -227
- package/dist/ViewModel.cjs.map +1 -1
- package/dist/ViewModel.d.ts +9 -12
- package/dist/ViewModel.d.ts.map +1 -1
- package/dist/ViewModel.js +177 -227
- package/dist/ViewModel.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/mvc-kit.cjs +8 -0
- package/dist/mvc-kit.cjs.map +1 -1
- package/dist/mvc-kit.js +8 -0
- package/dist/mvc-kit.js.map +1 -1
- package/dist/react/components/CardList.cjs +42 -0
- package/dist/react/components/CardList.cjs.map +1 -0
- package/dist/react/components/CardList.d.ts +22 -0
- package/dist/react/components/CardList.d.ts.map +1 -0
- package/dist/react/components/CardList.js +42 -0
- package/dist/react/components/CardList.js.map +1 -0
- package/dist/react/components/DataTable.cjs +179 -0
- package/dist/react/components/DataTable.cjs.map +1 -0
- package/dist/react/components/DataTable.d.ts +30 -0
- package/dist/react/components/DataTable.d.ts.map +1 -0
- package/dist/react/components/DataTable.js +179 -0
- package/dist/react/components/DataTable.js.map +1 -0
- package/dist/react/components/InfiniteScroll.cjs +44 -0
- package/dist/react/components/InfiniteScroll.cjs.map +1 -0
- package/dist/react/components/InfiniteScroll.d.ts +21 -0
- package/dist/react/components/InfiniteScroll.d.ts.map +1 -0
- package/dist/react/components/InfiniteScroll.js +44 -0
- package/dist/react/components/InfiniteScroll.js.map +1 -0
- package/dist/react/components/types.cjs +15 -0
- package/dist/react/components/types.cjs.map +1 -0
- package/dist/react/components/types.d.ts +71 -0
- package/dist/react/components/types.d.ts.map +1 -0
- package/dist/react/components/types.js +15 -0
- package/dist/react/components/types.js.map +1 -0
- package/dist/react/index.d.ts +8 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/use-instance.cjs +31 -21
- package/dist/react/use-instance.cjs.map +1 -1
- package/dist/react/use-instance.d.ts +1 -1
- package/dist/react/use-instance.d.ts.map +1 -1
- package/dist/react/use-instance.js +32 -22
- package/dist/react/use-instance.js.map +1 -1
- package/dist/react/use-model.cjs +29 -2
- package/dist/react/use-model.cjs.map +1 -1
- package/dist/react/use-model.d.ts +9 -0
- package/dist/react/use-model.d.ts.map +1 -1
- package/dist/react/use-model.js +30 -3
- package/dist/react/use-model.js.map +1 -1
- package/dist/react-native/NativeCollection.cjs +3 -0
- package/dist/react-native/NativeCollection.cjs.map +1 -1
- package/dist/react-native/NativeCollection.d.ts +3 -0
- package/dist/react-native/NativeCollection.d.ts.map +1 -1
- package/dist/react-native/NativeCollection.js +3 -0
- package/dist/react-native/NativeCollection.js.map +1 -1
- package/dist/react.cjs +7 -0
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +8 -1
- package/dist/react.js.map +1 -1
- package/dist/walkPrototypeChain.cjs.map +1 -1
- package/dist/walkPrototypeChain.d.ts +2 -2
- package/dist/walkPrototypeChain.js.map +1 -1
- package/dist/web/idb.cjs.map +1 -1
- package/dist/web/idb.d.ts +18 -0
- package/dist/web/idb.d.ts.map +1 -1
- package/dist/web/idb.js.map +1 -1
- package/dist/wrapAsyncMethods.cjs +159 -0
- package/dist/wrapAsyncMethods.cjs.map +1 -0
- package/dist/wrapAsyncMethods.d.ts +37 -0
- package/dist/wrapAsyncMethods.d.ts.map +1 -0
- package/dist/wrapAsyncMethods.js +159 -0
- package/dist/wrapAsyncMethods.js.map +1 -0
- package/package.json +1 -1
package/dist/Collection.cjs
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const __DEV__ = typeof __MVC_KIT_DEV__ !== "undefined" && __MVC_KIT_DEV__;
|
|
4
|
+
function freeze(obj) {
|
|
5
|
+
return __DEV__ ? Object.freeze(obj) : obj;
|
|
6
|
+
}
|
|
4
7
|
class Collection {
|
|
5
8
|
/** Maximum number of items before FIFO eviction. 0 = unlimited. */
|
|
6
9
|
static MAX_SIZE = 0;
|
|
@@ -31,7 +34,7 @@ class Collection {
|
|
|
31
34
|
this._timestamps?.delete(item.id);
|
|
32
35
|
}
|
|
33
36
|
}
|
|
34
|
-
this._items =
|
|
37
|
+
this._items = freeze(result);
|
|
35
38
|
this.rebuildIndex();
|
|
36
39
|
this._scheduleEvictionTimer();
|
|
37
40
|
}
|
|
@@ -78,6 +81,21 @@ class Collection {
|
|
|
78
81
|
if (items.length === 0) {
|
|
79
82
|
return;
|
|
80
83
|
}
|
|
84
|
+
if (items.length === 1) {
|
|
85
|
+
const item = items[0];
|
|
86
|
+
if (this._index.has(item.id)) return;
|
|
87
|
+
const prev2 = this._items;
|
|
88
|
+
let result2 = [...prev2, item];
|
|
89
|
+
this._index.set(item.id, item);
|
|
90
|
+
if (this._timestamps) this._timestamps.set(item.id, Date.now());
|
|
91
|
+
if (this._maxSize > 0 && result2.length > this._maxSize) {
|
|
92
|
+
result2 = this._evictForCapacity(result2);
|
|
93
|
+
}
|
|
94
|
+
this._items = freeze(result2);
|
|
95
|
+
this.notify(prev2);
|
|
96
|
+
this._scheduleEvictionTimer();
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
81
99
|
const seen = /* @__PURE__ */ new Set();
|
|
82
100
|
const newItems = [];
|
|
83
101
|
for (const item of items) {
|
|
@@ -101,7 +119,7 @@ class Collection {
|
|
|
101
119
|
if (this._maxSize > 0 && result.length > this._maxSize) {
|
|
102
120
|
result = this._evictForCapacity(result);
|
|
103
121
|
}
|
|
104
|
-
this._items =
|
|
122
|
+
this._items = freeze(result);
|
|
105
123
|
this.notify(prev);
|
|
106
124
|
this._scheduleEvictionTimer();
|
|
107
125
|
}
|
|
@@ -116,6 +134,33 @@ class Collection {
|
|
|
116
134
|
throw new Error("Cannot upsert on disposed Collection");
|
|
117
135
|
}
|
|
118
136
|
if (items.length === 0) return;
|
|
137
|
+
if (items.length === 1) {
|
|
138
|
+
const item = items[0];
|
|
139
|
+
const existing = this._index.get(item.id);
|
|
140
|
+
if (existing) {
|
|
141
|
+
if (existing === item) return;
|
|
142
|
+
const prev2 = this._items;
|
|
143
|
+
const idx = this._items.indexOf(existing);
|
|
144
|
+
const newItems = [...prev2];
|
|
145
|
+
newItems[idx] = item;
|
|
146
|
+
this._index.set(item.id, item);
|
|
147
|
+
if (this._timestamps) this._timestamps.set(item.id, Date.now());
|
|
148
|
+
this._items = freeze(newItems);
|
|
149
|
+
this.notify(prev2);
|
|
150
|
+
} else {
|
|
151
|
+
const prev2 = this._items;
|
|
152
|
+
let result2 = [...prev2, item];
|
|
153
|
+
this._index.set(item.id, item);
|
|
154
|
+
if (this._timestamps) this._timestamps.set(item.id, Date.now());
|
|
155
|
+
if (this._maxSize > 0 && result2.length > this._maxSize) {
|
|
156
|
+
result2 = this._evictForCapacity(result2);
|
|
157
|
+
}
|
|
158
|
+
this._items = freeze(result2);
|
|
159
|
+
this.notify(prev2);
|
|
160
|
+
this._scheduleEvictionTimer();
|
|
161
|
+
}
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
119
164
|
const incoming = /* @__PURE__ */ new Map();
|
|
120
165
|
for (const item of items) {
|
|
121
166
|
incoming.set(item.id, item);
|
|
@@ -154,7 +199,7 @@ class Collection {
|
|
|
154
199
|
if (this._maxSize > 0 && result.length > this._maxSize) {
|
|
155
200
|
result = this._evictForCapacity(result);
|
|
156
201
|
}
|
|
157
|
-
this._items =
|
|
202
|
+
this._items = freeze(result);
|
|
158
203
|
this.notify(prev);
|
|
159
204
|
this._scheduleEvictionTimer();
|
|
160
205
|
}
|
|
@@ -168,13 +213,24 @@ class Collection {
|
|
|
168
213
|
if (ids.length === 0) {
|
|
169
214
|
return;
|
|
170
215
|
}
|
|
216
|
+
if (ids.length === 1) {
|
|
217
|
+
const id = ids[0];
|
|
218
|
+
if (!this._index.has(id)) return;
|
|
219
|
+
const prev2 = this._items;
|
|
220
|
+
this._items = freeze(prev2.filter((item) => item.id !== id));
|
|
221
|
+
this._index.delete(id);
|
|
222
|
+
this._timestamps?.delete(id);
|
|
223
|
+
this.notify(prev2);
|
|
224
|
+
this._scheduleEvictionTimer();
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
171
227
|
const idSet = new Set(ids);
|
|
172
228
|
const filtered = this._items.filter((item) => !idSet.has(item.id));
|
|
173
229
|
if (filtered.length === this._items.length) {
|
|
174
230
|
return;
|
|
175
231
|
}
|
|
176
232
|
const prev = this._items;
|
|
177
|
-
this._items =
|
|
233
|
+
this._items = freeze(filtered);
|
|
178
234
|
for (const id of ids) {
|
|
179
235
|
this._index.delete(id);
|
|
180
236
|
this._timestamps?.delete(id);
|
|
@@ -189,21 +245,17 @@ class Collection {
|
|
|
189
245
|
if (this._disposed) {
|
|
190
246
|
throw new Error("Cannot update disposed Collection");
|
|
191
247
|
}
|
|
192
|
-
const
|
|
193
|
-
if (
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
const existing = this._items[idx];
|
|
197
|
-
const updated = { ...existing, ...changes, id };
|
|
248
|
+
const existing = this._index.get(id);
|
|
249
|
+
if (!existing) return;
|
|
198
250
|
const keys = Object.keys(changes);
|
|
199
251
|
const hasChanges = keys.some((key) => changes[key] !== existing[key]);
|
|
200
|
-
if (!hasChanges)
|
|
201
|
-
|
|
202
|
-
}
|
|
252
|
+
if (!hasChanges) return;
|
|
253
|
+
const updated = { ...existing, ...changes, id };
|
|
203
254
|
const prev = this._items;
|
|
255
|
+
const idx = this._items.indexOf(existing);
|
|
204
256
|
const newItems = [...prev];
|
|
205
257
|
newItems[idx] = updated;
|
|
206
|
-
this._items =
|
|
258
|
+
this._items = freeze(newItems);
|
|
207
259
|
this._index.set(id, updated);
|
|
208
260
|
this.notify(prev);
|
|
209
261
|
}
|
|
@@ -226,7 +278,7 @@ class Collection {
|
|
|
226
278
|
if (this._maxSize > 0 && result.length > this._maxSize) {
|
|
227
279
|
result = this._evictForCapacity(result);
|
|
228
280
|
}
|
|
229
|
-
this._items =
|
|
281
|
+
this._items = freeze(result);
|
|
230
282
|
this.rebuildIndex();
|
|
231
283
|
this.notify(prev);
|
|
232
284
|
this._scheduleEvictionTimer();
|
|
@@ -242,7 +294,7 @@ class Collection {
|
|
|
242
294
|
return;
|
|
243
295
|
}
|
|
244
296
|
const prev = this._items;
|
|
245
|
-
this._items =
|
|
297
|
+
this._items = freeze([]);
|
|
246
298
|
this._index.clear();
|
|
247
299
|
this._timestamps?.clear();
|
|
248
300
|
this._clearEvictionTimer();
|
|
@@ -419,7 +471,7 @@ class Collection {
|
|
|
419
471
|
}
|
|
420
472
|
const evictIds = new Set(toEvict.map((item) => item.id));
|
|
421
473
|
const prev = this._items;
|
|
422
|
-
this._items =
|
|
474
|
+
this._items = freeze(
|
|
423
475
|
prev.filter((item) => !evictIds.has(item.id))
|
|
424
476
|
);
|
|
425
477
|
for (const item of toEvict) {
|
package/dist/Collection.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Collection.cjs","sources":["../src/Collection.ts"],"sourcesContent":["import type { Listener, Subscribable } from './types';\n\nconst __DEV__ = typeof __MVC_KIT_DEV__ !== 'undefined' && __MVC_KIT_DEV__;\n\ntype CollectionState<T> = 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 /** Maximum number of items before FIFO eviction. 0 = unlimited. */\n static MAX_SIZE = 0;\n /** Time-to-live in milliseconds. 0 = no expiry. */\n static TTL = 0;\n\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 private _timestamps: Map<T['id'], number> | null = null;\n private _evictionTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(initialItems: T[] = []) {\n let result = [...initialItems];\n\n if (this._ttl > 0) {\n this._timestamps = new Map();\n const now = Date.now();\n for (const item of result) {\n this._timestamps.set(item.id, now);\n }\n }\n\n if (this._maxSize > 0 && result.length > this._maxSize) {\n // FIFO: trim from the front (oldest items)\n const excess = result.length - this._maxSize;\n const evicted = result.slice(0, excess);\n result = result.slice(excess);\n for (const item of evicted) {\n this._timestamps?.delete(item.id);\n }\n }\n\n this._items = Object.freeze(result);\n this.rebuildIndex();\n this._scheduleEvictionTimer();\n }\n\n /**\n * Alias for Subscribable compatibility.\n */\n get state(): T[] {\n return this._items as T[];\n }\n\n /** The raw array of items. */\n get items(): T[] {\n return this._items as T[];\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 // ── Config Accessors ──\n\n private get _maxSize(): number {\n return (this.constructor as typeof Collection).MAX_SIZE;\n }\n\n private get _ttl(): number {\n return (this.constructor as typeof Collection).TTL;\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 let result = [...prev, ...newItems];\n\n for (const item of newItems) {\n this._index.set(item.id, item);\n }\n\n // Record timestamps for TTL\n if (this._timestamps) {\n const now = Date.now();\n for (const item of newItems) {\n this._timestamps.set(item.id, now);\n }\n }\n\n // Enforce capacity before freeze/notify\n if (this._maxSize > 0 && result.length > this._maxSize) {\n result = this._evictForCapacity(result);\n }\n\n this._items = Object.freeze(result);\n this.notify(prev);\n this._scheduleEvictionTimer();\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 // Record/refresh timestamps for TTL (upsert refreshes existing)\n if (this._timestamps) {\n const now = Date.now();\n for (const [id] of incoming) {\n this._timestamps.set(id, now);\n }\n }\n\n for (const [id, item] of incoming) {\n this._index.set(id, item);\n }\n\n // Enforce capacity before freeze/notify\n let result = newArray;\n if (this._maxSize > 0 && result.length > this._maxSize) {\n result = this._evictForCapacity(result);\n }\n\n this._items = Object.freeze(result);\n this.notify(prev);\n this._scheduleEvictionTimer();\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 this._timestamps?.delete(id);\n }\n\n this.notify(prev);\n this._scheduleEvictionTimer();\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\n // Record timestamps for TTL\n if (this._timestamps) {\n this._timestamps.clear();\n const now = Date.now();\n for (const item of items) {\n this._timestamps.set(item.id, now);\n }\n }\n\n let result = [...items];\n\n // Enforce capacity before freeze/notify\n if (this._maxSize > 0 && result.length > this._maxSize) {\n result = this._evictForCapacity(result);\n }\n\n this._items = Object.freeze(result);\n this.rebuildIndex();\n\n this.notify(prev);\n this._scheduleEvictionTimer();\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 this._timestamps?.clear();\n this._clearEvictionTimer();\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 const timestampSnapshot = this._timestamps ? new Map(this._timestamps) : null;\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 if (timestampSnapshot) {\n this._timestamps = timestampSnapshot;\n }\n this.rebuildIndex();\n this.notify(prev);\n this._scheduleEvictionTimer();\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): T[] {\n return this._items.filter(predicate) as T[];\n }\n\n /**\n * Return sorted copy.\n */\n sorted(compareFn: (a: T, b: T) => number): T[] {\n return [...this._items].sort(compareFn);\n }\n\n /**\n * Map items to new array.\n */\n map<U>(fn: (item: T) => U): 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._clearEvictionTimer();\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 this._timestamps?.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 /**\n * Called before items are auto-evicted by capacity or TTL.\n * Override to filter which items get evicted, or veto entirely.\n *\n * @param items - Candidates for eviction\n * @param reason - Why eviction is happening\n * @returns void to proceed with all, false to veto, or T[] subset to evict only those\n */\n protected onEvict?(items: T[], reason: 'capacity' | 'ttl'): T[] | false | void;\n\n private notify(prev: readonly T[]): void {\n for (const listener of this._listeners) {\n listener(this._items as T[], prev as T[]);\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 // ── Eviction Internals ──\n\n private _evictForCapacity(items: T[]): T[] {\n const excess = items.length - this._maxSize;\n if (excess <= 0) return items;\n\n const candidates = items.slice(0, excess);\n const toEvict = this._applyOnEvict(candidates, 'capacity');\n\n if (toEvict === false) return items; // veto\n\n if (toEvict.length === 0) return items; // nothing to evict\n\n const evictIds = new Set(toEvict.map(item => item.id));\n const result = items.filter(item => !evictIds.has(item.id));\n\n // Clean up index and timestamps for evicted items\n for (const item of toEvict) {\n this._index.delete(item.id);\n this._timestamps?.delete(item.id);\n }\n\n return result;\n }\n\n private _applyOnEvict(candidates: T[], reason: 'capacity' | 'ttl'): T[] | false {\n if (!this.onEvict) return candidates;\n\n const result = this.onEvict(candidates, reason);\n if (result === false) {\n // DEV warning when veto causes collection to exceed 2x MAX_SIZE\n if (__DEV__ && reason === 'capacity' && this._maxSize > 0) {\n const currentSize = this._items.length + candidates.length;\n if (currentSize > this._maxSize * 2) {\n console.warn(\n `[mvc-kit] Collection exceeded 2x MAX_SIZE (${currentSize}/${this._maxSize}). ` +\n `onEvict is vetoing eviction — this may cause unbounded growth.`\n );\n }\n }\n return false;\n }\n if (Array.isArray(result)) {\n // Only include items that are actually in the current items\n const candidateIds = new Set(candidates.map(c => c.id));\n return result.filter(item => candidateIds.has(item.id));\n }\n return candidates; // void = proceed with all\n }\n\n private _sweepExpired(): void {\n if (this._disposed || !this._timestamps || this._ttl <= 0) return;\n\n const now = Date.now();\n const ttl = this._ttl;\n const expired: T[] = [];\n\n for (const item of this._items) {\n const ts = this._timestamps.get(item.id);\n if (ts !== undefined && (now - ts) >= ttl) {\n expired.push(item);\n }\n }\n\n if (expired.length === 0) {\n this._scheduleEvictionTimer();\n return;\n }\n\n const toEvict = this._applyOnEvict(expired, 'ttl');\n\n if (toEvict === false) {\n this._scheduleEvictionTimer();\n return;\n }\n\n if (toEvict.length === 0) {\n this._scheduleEvictionTimer();\n return;\n }\n\n const evictIds = new Set(toEvict.map(item => item.id));\n const prev = this._items;\n this._items = Object.freeze(\n (prev as T[]).filter((item: T) => !evictIds.has(item.id))\n );\n\n for (const item of toEvict) {\n this._index.delete(item.id);\n this._timestamps.delete(item.id);\n }\n\n this.notify(prev);\n this._scheduleEvictionTimer();\n }\n\n private _scheduleEvictionTimer(): void {\n this._clearEvictionTimer();\n\n if (this._disposed || !this._timestamps || this._ttl <= 0 || this._timestamps.size === 0) return;\n\n const now = Date.now();\n const ttl = this._ttl;\n let earliest = Infinity;\n\n for (const ts of this._timestamps.values()) {\n if (ts < earliest) earliest = ts;\n }\n\n const delay = Math.max(0, (earliest + ttl) - now);\n this._evictionTimer = setTimeout(() => this._sweepExpired(), delay);\n }\n\n private _clearEvictionTimer(): void {\n if (this._evictionTimer !== null) {\n clearTimeout(this._evictionTimer);\n this._evictionTimer = null;\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Collection.cjs","sources":["../src/Collection.ts"],"sourcesContent":["import type { Listener, Subscribable } from './types';\n\nconst __DEV__ = typeof __MVC_KIT_DEV__ !== 'undefined' && __MVC_KIT_DEV__;\n\nfunction freeze<T>(obj: T): T {\n return __DEV__ ? Object.freeze(obj) as T : obj;\n}\n\ntype CollectionState<T> = 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 /** Maximum number of items before FIFO eviction. 0 = unlimited. */\n static MAX_SIZE = 0;\n /** Time-to-live in milliseconds. 0 = no expiry. */\n static TTL = 0;\n\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 private _timestamps: Map<T['id'], number> | null = null;\n private _evictionTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(initialItems: T[] = []) {\n let result = [...initialItems];\n\n if (this._ttl > 0) {\n this._timestamps = new Map();\n const now = Date.now();\n for (const item of result) {\n this._timestamps.set(item.id, now);\n }\n }\n\n if (this._maxSize > 0 && result.length > this._maxSize) {\n // FIFO: trim from the front (oldest items)\n const excess = result.length - this._maxSize;\n const evicted = result.slice(0, excess);\n result = result.slice(excess);\n for (const item of evicted) {\n this._timestamps?.delete(item.id);\n }\n }\n\n this._items = freeze(result);\n this.rebuildIndex();\n this._scheduleEvictionTimer();\n }\n\n /**\n * Alias for Subscribable compatibility.\n */\n get state(): T[] {\n return this._items as T[];\n }\n\n /** The raw array of items. */\n get items(): T[] {\n return this._items as T[];\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 // ── Config Accessors ──\n\n private get _maxSize(): number {\n return (this.constructor as typeof Collection).MAX_SIZE;\n }\n\n private get _ttl(): number {\n return (this.constructor as typeof Collection).TTL;\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 // Fast path: single item (most common case)\n if (items.length === 1) {\n const item = items[0];\n if (this._index.has(item.id)) return;\n const prev = this._items;\n let result = [...prev, item];\n this._index.set(item.id, item);\n if (this._timestamps) this._timestamps.set(item.id, Date.now());\n if (this._maxSize > 0 && result.length > this._maxSize) {\n result = this._evictForCapacity(result);\n }\n this._items = freeze(result);\n this.notify(prev);\n this._scheduleEvictionTimer();\n return;\n }\n\n // Multi-item path\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 let result = [...prev, ...newItems];\n\n for (const item of newItems) {\n this._index.set(item.id, item);\n }\n\n // Record timestamps for TTL\n if (this._timestamps) {\n const now = Date.now();\n for (const item of newItems) {\n this._timestamps.set(item.id, now);\n }\n }\n\n // Enforce capacity before freeze/notify\n if (this._maxSize > 0 && result.length > this._maxSize) {\n result = this._evictForCapacity(result);\n }\n\n this._items = freeze(result);\n this.notify(prev);\n this._scheduleEvictionTimer();\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 // Fast path: single item (most common case — channel messages, real-time updates)\n if (items.length === 1) {\n const item = items[0];\n const existing = this._index.get(item.id);\n\n if (existing) {\n // Replace in-place — skip if same reference\n if (existing === item) return;\n const prev = this._items;\n const idx = this._items.indexOf(existing);\n const newItems = [...prev];\n newItems[idx] = item;\n this._index.set(item.id, item);\n if (this._timestamps) this._timestamps.set(item.id, Date.now());\n this._items = freeze(newItems);\n this.notify(prev);\n } else {\n // New item — append (with capacity enforcement)\n const prev = this._items;\n let result = [...prev, item];\n this._index.set(item.id, item);\n if (this._timestamps) this._timestamps.set(item.id, Date.now());\n if (this._maxSize > 0 && result.length > this._maxSize) {\n result = this._evictForCapacity(result);\n }\n this._items = freeze(result);\n this.notify(prev);\n this._scheduleEvictionTimer();\n }\n return;\n }\n\n // Multi-item path: 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 // Record/refresh timestamps for TTL (upsert refreshes existing)\n if (this._timestamps) {\n const now = Date.now();\n for (const [id] of incoming) {\n this._timestamps.set(id, now);\n }\n }\n\n for (const [id, item] of incoming) {\n this._index.set(id, item);\n }\n\n // Enforce capacity before freeze/notify\n let result = newArray;\n if (this._maxSize > 0 && result.length > this._maxSize) {\n result = this._evictForCapacity(result);\n }\n\n this._items = freeze(result);\n this.notify(prev);\n this._scheduleEvictionTimer();\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 // Fast path: single id (most common case)\n if (ids.length === 1) {\n const id = ids[0];\n if (!this._index.has(id)) return;\n const prev = this._items;\n this._items = freeze(prev.filter(item => item.id !== id));\n this._index.delete(id);\n this._timestamps?.delete(id);\n this.notify(prev);\n this._scheduleEvictionTimer();\n return;\n }\n\n // Multi-id path\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 = freeze(filtered);\n\n for (const id of ids) {\n this._index.delete(id);\n this._timestamps?.delete(id);\n }\n\n this.notify(prev);\n this._scheduleEvictionTimer();\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 // O(1) existence check via index Map\n const existing = this._index.get(id);\n if (!existing) return;\n\n // Check if anything actually changed (before any array work)\n const keys = Object.keys(changes) as (keyof T)[];\n const hasChanges = keys.some(key => changes[key] !== existing[key]);\n if (!hasChanges) return;\n\n const updated = { ...existing, ...changes, id };\n const prev = this._items;\n const idx = this._items.indexOf(existing);\n const newItems = [...prev];\n newItems[idx] = updated;\n this._items = 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\n // Record timestamps for TTL\n if (this._timestamps) {\n this._timestamps.clear();\n const now = Date.now();\n for (const item of items) {\n this._timestamps.set(item.id, now);\n }\n }\n\n let result = [...items];\n\n // Enforce capacity before freeze/notify\n if (this._maxSize > 0 && result.length > this._maxSize) {\n result = this._evictForCapacity(result);\n }\n\n this._items = freeze(result);\n this.rebuildIndex();\n\n this.notify(prev);\n this._scheduleEvictionTimer();\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 = freeze([] as T[]);\n this._index.clear();\n this._timestamps?.clear();\n this._clearEvictionTimer();\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 const timestampSnapshot = this._timestamps ? new Map(this._timestamps) : null;\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 if (timestampSnapshot) {\n this._timestamps = timestampSnapshot;\n }\n this.rebuildIndex();\n this.notify(prev);\n this._scheduleEvictionTimer();\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): T[] {\n return this._items.filter(predicate) as T[];\n }\n\n /**\n * Return sorted copy.\n */\n sorted(compareFn: (a: T, b: T) => number): T[] {\n return [...this._items].sort(compareFn);\n }\n\n /**\n * Map items to new array.\n */\n map<U>(fn: (item: T) => U): 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._clearEvictionTimer();\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 this._timestamps?.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 /**\n * Called before items are auto-evicted by capacity or TTL.\n * Override to filter which items get evicted, or veto entirely.\n *\n * @param items - Candidates for eviction\n * @param reason - Why eviction is happening\n * @returns void to proceed with all, false to veto, or T[] subset to evict only those\n */\n protected onEvict?(items: T[], reason: 'capacity' | 'ttl'): T[] | false | void;\n\n private notify(prev: readonly T[]): void {\n for (const listener of this._listeners) {\n listener(this._items as T[], prev as T[]);\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 // ── Eviction Internals ──\n\n private _evictForCapacity(items: T[]): T[] {\n const excess = items.length - this._maxSize;\n if (excess <= 0) return items;\n\n const candidates = items.slice(0, excess);\n const toEvict = this._applyOnEvict(candidates, 'capacity');\n\n if (toEvict === false) return items; // veto\n\n if (toEvict.length === 0) return items; // nothing to evict\n\n const evictIds = new Set(toEvict.map(item => item.id));\n const result = items.filter(item => !evictIds.has(item.id));\n\n // Clean up index and timestamps for evicted items\n for (const item of toEvict) {\n this._index.delete(item.id);\n this._timestamps?.delete(item.id);\n }\n\n return result;\n }\n\n private _applyOnEvict(candidates: T[], reason: 'capacity' | 'ttl'): T[] | false {\n if (!this.onEvict) return candidates;\n\n const result = this.onEvict(candidates, reason);\n if (result === false) {\n // DEV warning when veto causes collection to exceed 2x MAX_SIZE\n if (__DEV__ && reason === 'capacity' && this._maxSize > 0) {\n const currentSize = this._items.length + candidates.length;\n if (currentSize > this._maxSize * 2) {\n console.warn(\n `[mvc-kit] Collection exceeded 2x MAX_SIZE (${currentSize}/${this._maxSize}). ` +\n `onEvict is vetoing eviction — this may cause unbounded growth.`\n );\n }\n }\n return false;\n }\n if (Array.isArray(result)) {\n // Only include items that are actually in the current items\n const candidateIds = new Set(candidates.map(c => c.id));\n return result.filter(item => candidateIds.has(item.id));\n }\n return candidates; // void = proceed with all\n }\n\n private _sweepExpired(): void {\n if (this._disposed || !this._timestamps || this._ttl <= 0) return;\n\n const now = Date.now();\n const ttl = this._ttl;\n const expired: T[] = [];\n\n for (const item of this._items) {\n const ts = this._timestamps.get(item.id);\n if (ts !== undefined && (now - ts) >= ttl) {\n expired.push(item);\n }\n }\n\n if (expired.length === 0) {\n this._scheduleEvictionTimer();\n return;\n }\n\n const toEvict = this._applyOnEvict(expired, 'ttl');\n\n if (toEvict === false) {\n this._scheduleEvictionTimer();\n return;\n }\n\n if (toEvict.length === 0) {\n this._scheduleEvictionTimer();\n return;\n }\n\n const evictIds = new Set(toEvict.map(item => item.id));\n const prev = this._items;\n this._items = freeze(\n (prev as T[]).filter((item: T) => !evictIds.has(item.id))\n );\n\n for (const item of toEvict) {\n this._index.delete(item.id);\n this._timestamps.delete(item.id);\n }\n\n this.notify(prev);\n this._scheduleEvictionTimer();\n }\n\n private _scheduleEvictionTimer(): void {\n this._clearEvictionTimer();\n\n if (this._disposed || !this._timestamps || this._ttl <= 0 || this._timestamps.size === 0) return;\n\n const now = Date.now();\n const ttl = this._ttl;\n let earliest = Infinity;\n\n for (const ts of this._timestamps.values()) {\n if (ts < earliest) earliest = ts;\n }\n\n const delay = Math.max(0, (earliest + ttl) - now);\n this._evictionTimer = setTimeout(() => this._sweepExpired(), delay);\n }\n\n private _clearEvictionTimer(): void {\n if (this._evictionTimer !== null) {\n clearTimeout(this._evictionTimer);\n this._evictionTimer = null;\n }\n }\n}\n"],"names":["prev","result"],"mappings":"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"}
|
package/dist/Collection.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Collection.d.ts","sourceRoot":"","sources":["../src/Collection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"Collection.d.ts","sourceRoot":"","sources":["../src/Collection.ts"],"names":[],"mappings":"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"}
|
package/dist/Collection.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
const __DEV__ = typeof __MVC_KIT_DEV__ !== "undefined" && __MVC_KIT_DEV__;
|
|
2
|
+
function freeze(obj) {
|
|
3
|
+
return __DEV__ ? Object.freeze(obj) : obj;
|
|
4
|
+
}
|
|
2
5
|
class Collection {
|
|
3
6
|
/** Maximum number of items before FIFO eviction. 0 = unlimited. */
|
|
4
7
|
static MAX_SIZE = 0;
|
|
@@ -29,7 +32,7 @@ class Collection {
|
|
|
29
32
|
this._timestamps?.delete(item.id);
|
|
30
33
|
}
|
|
31
34
|
}
|
|
32
|
-
this._items =
|
|
35
|
+
this._items = freeze(result);
|
|
33
36
|
this.rebuildIndex();
|
|
34
37
|
this._scheduleEvictionTimer();
|
|
35
38
|
}
|
|
@@ -76,6 +79,21 @@ class Collection {
|
|
|
76
79
|
if (items.length === 0) {
|
|
77
80
|
return;
|
|
78
81
|
}
|
|
82
|
+
if (items.length === 1) {
|
|
83
|
+
const item = items[0];
|
|
84
|
+
if (this._index.has(item.id)) return;
|
|
85
|
+
const prev2 = this._items;
|
|
86
|
+
let result2 = [...prev2, item];
|
|
87
|
+
this._index.set(item.id, item);
|
|
88
|
+
if (this._timestamps) this._timestamps.set(item.id, Date.now());
|
|
89
|
+
if (this._maxSize > 0 && result2.length > this._maxSize) {
|
|
90
|
+
result2 = this._evictForCapacity(result2);
|
|
91
|
+
}
|
|
92
|
+
this._items = freeze(result2);
|
|
93
|
+
this.notify(prev2);
|
|
94
|
+
this._scheduleEvictionTimer();
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
79
97
|
const seen = /* @__PURE__ */ new Set();
|
|
80
98
|
const newItems = [];
|
|
81
99
|
for (const item of items) {
|
|
@@ -99,7 +117,7 @@ class Collection {
|
|
|
99
117
|
if (this._maxSize > 0 && result.length > this._maxSize) {
|
|
100
118
|
result = this._evictForCapacity(result);
|
|
101
119
|
}
|
|
102
|
-
this._items =
|
|
120
|
+
this._items = freeze(result);
|
|
103
121
|
this.notify(prev);
|
|
104
122
|
this._scheduleEvictionTimer();
|
|
105
123
|
}
|
|
@@ -114,6 +132,33 @@ class Collection {
|
|
|
114
132
|
throw new Error("Cannot upsert on disposed Collection");
|
|
115
133
|
}
|
|
116
134
|
if (items.length === 0) return;
|
|
135
|
+
if (items.length === 1) {
|
|
136
|
+
const item = items[0];
|
|
137
|
+
const existing = this._index.get(item.id);
|
|
138
|
+
if (existing) {
|
|
139
|
+
if (existing === item) return;
|
|
140
|
+
const prev2 = this._items;
|
|
141
|
+
const idx = this._items.indexOf(existing);
|
|
142
|
+
const newItems = [...prev2];
|
|
143
|
+
newItems[idx] = item;
|
|
144
|
+
this._index.set(item.id, item);
|
|
145
|
+
if (this._timestamps) this._timestamps.set(item.id, Date.now());
|
|
146
|
+
this._items = freeze(newItems);
|
|
147
|
+
this.notify(prev2);
|
|
148
|
+
} else {
|
|
149
|
+
const prev2 = this._items;
|
|
150
|
+
let result2 = [...prev2, item];
|
|
151
|
+
this._index.set(item.id, item);
|
|
152
|
+
if (this._timestamps) this._timestamps.set(item.id, Date.now());
|
|
153
|
+
if (this._maxSize > 0 && result2.length > this._maxSize) {
|
|
154
|
+
result2 = this._evictForCapacity(result2);
|
|
155
|
+
}
|
|
156
|
+
this._items = freeze(result2);
|
|
157
|
+
this.notify(prev2);
|
|
158
|
+
this._scheduleEvictionTimer();
|
|
159
|
+
}
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
117
162
|
const incoming = /* @__PURE__ */ new Map();
|
|
118
163
|
for (const item of items) {
|
|
119
164
|
incoming.set(item.id, item);
|
|
@@ -152,7 +197,7 @@ class Collection {
|
|
|
152
197
|
if (this._maxSize > 0 && result.length > this._maxSize) {
|
|
153
198
|
result = this._evictForCapacity(result);
|
|
154
199
|
}
|
|
155
|
-
this._items =
|
|
200
|
+
this._items = freeze(result);
|
|
156
201
|
this.notify(prev);
|
|
157
202
|
this._scheduleEvictionTimer();
|
|
158
203
|
}
|
|
@@ -166,13 +211,24 @@ class Collection {
|
|
|
166
211
|
if (ids.length === 0) {
|
|
167
212
|
return;
|
|
168
213
|
}
|
|
214
|
+
if (ids.length === 1) {
|
|
215
|
+
const id = ids[0];
|
|
216
|
+
if (!this._index.has(id)) return;
|
|
217
|
+
const prev2 = this._items;
|
|
218
|
+
this._items = freeze(prev2.filter((item) => item.id !== id));
|
|
219
|
+
this._index.delete(id);
|
|
220
|
+
this._timestamps?.delete(id);
|
|
221
|
+
this.notify(prev2);
|
|
222
|
+
this._scheduleEvictionTimer();
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
169
225
|
const idSet = new Set(ids);
|
|
170
226
|
const filtered = this._items.filter((item) => !idSet.has(item.id));
|
|
171
227
|
if (filtered.length === this._items.length) {
|
|
172
228
|
return;
|
|
173
229
|
}
|
|
174
230
|
const prev = this._items;
|
|
175
|
-
this._items =
|
|
231
|
+
this._items = freeze(filtered);
|
|
176
232
|
for (const id of ids) {
|
|
177
233
|
this._index.delete(id);
|
|
178
234
|
this._timestamps?.delete(id);
|
|
@@ -187,21 +243,17 @@ class Collection {
|
|
|
187
243
|
if (this._disposed) {
|
|
188
244
|
throw new Error("Cannot update disposed Collection");
|
|
189
245
|
}
|
|
190
|
-
const
|
|
191
|
-
if (
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
const existing = this._items[idx];
|
|
195
|
-
const updated = { ...existing, ...changes, id };
|
|
246
|
+
const existing = this._index.get(id);
|
|
247
|
+
if (!existing) return;
|
|
196
248
|
const keys = Object.keys(changes);
|
|
197
249
|
const hasChanges = keys.some((key) => changes[key] !== existing[key]);
|
|
198
|
-
if (!hasChanges)
|
|
199
|
-
|
|
200
|
-
}
|
|
250
|
+
if (!hasChanges) return;
|
|
251
|
+
const updated = { ...existing, ...changes, id };
|
|
201
252
|
const prev = this._items;
|
|
253
|
+
const idx = this._items.indexOf(existing);
|
|
202
254
|
const newItems = [...prev];
|
|
203
255
|
newItems[idx] = updated;
|
|
204
|
-
this._items =
|
|
256
|
+
this._items = freeze(newItems);
|
|
205
257
|
this._index.set(id, updated);
|
|
206
258
|
this.notify(prev);
|
|
207
259
|
}
|
|
@@ -224,7 +276,7 @@ class Collection {
|
|
|
224
276
|
if (this._maxSize > 0 && result.length > this._maxSize) {
|
|
225
277
|
result = this._evictForCapacity(result);
|
|
226
278
|
}
|
|
227
|
-
this._items =
|
|
279
|
+
this._items = freeze(result);
|
|
228
280
|
this.rebuildIndex();
|
|
229
281
|
this.notify(prev);
|
|
230
282
|
this._scheduleEvictionTimer();
|
|
@@ -240,7 +292,7 @@ class Collection {
|
|
|
240
292
|
return;
|
|
241
293
|
}
|
|
242
294
|
const prev = this._items;
|
|
243
|
-
this._items =
|
|
295
|
+
this._items = freeze([]);
|
|
244
296
|
this._index.clear();
|
|
245
297
|
this._timestamps?.clear();
|
|
246
298
|
this._clearEvictionTimer();
|
|
@@ -417,7 +469,7 @@ class Collection {
|
|
|
417
469
|
}
|
|
418
470
|
const evictIds = new Set(toEvict.map((item) => item.id));
|
|
419
471
|
const prev = this._items;
|
|
420
|
-
this._items =
|
|
472
|
+
this._items = freeze(
|
|
421
473
|
prev.filter((item) => !evictIds.has(item.id))
|
|
422
474
|
);
|
|
423
475
|
for (const item of toEvict) {
|
package/dist/Collection.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Collection.js","sources":["../src/Collection.ts"],"sourcesContent":["import type { Listener, Subscribable } from './types';\n\nconst __DEV__ = typeof __MVC_KIT_DEV__ !== 'undefined' && __MVC_KIT_DEV__;\n\ntype CollectionState<T> = 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 /** Maximum number of items before FIFO eviction. 0 = unlimited. */\n static MAX_SIZE = 0;\n /** Time-to-live in milliseconds. 0 = no expiry. */\n static TTL = 0;\n\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 private _timestamps: Map<T['id'], number> | null = null;\n private _evictionTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(initialItems: T[] = []) {\n let result = [...initialItems];\n\n if (this._ttl > 0) {\n this._timestamps = new Map();\n const now = Date.now();\n for (const item of result) {\n this._timestamps.set(item.id, now);\n }\n }\n\n if (this._maxSize > 0 && result.length > this._maxSize) {\n // FIFO: trim from the front (oldest items)\n const excess = result.length - this._maxSize;\n const evicted = result.slice(0, excess);\n result = result.slice(excess);\n for (const item of evicted) {\n this._timestamps?.delete(item.id);\n }\n }\n\n this._items = Object.freeze(result);\n this.rebuildIndex();\n this._scheduleEvictionTimer();\n }\n\n /**\n * Alias for Subscribable compatibility.\n */\n get state(): T[] {\n return this._items as T[];\n }\n\n /** The raw array of items. */\n get items(): T[] {\n return this._items as T[];\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 // ── Config Accessors ──\n\n private get _maxSize(): number {\n return (this.constructor as typeof Collection).MAX_SIZE;\n }\n\n private get _ttl(): number {\n return (this.constructor as typeof Collection).TTL;\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 let result = [...prev, ...newItems];\n\n for (const item of newItems) {\n this._index.set(item.id, item);\n }\n\n // Record timestamps for TTL\n if (this._timestamps) {\n const now = Date.now();\n for (const item of newItems) {\n this._timestamps.set(item.id, now);\n }\n }\n\n // Enforce capacity before freeze/notify\n if (this._maxSize > 0 && result.length > this._maxSize) {\n result = this._evictForCapacity(result);\n }\n\n this._items = Object.freeze(result);\n this.notify(prev);\n this._scheduleEvictionTimer();\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 // Record/refresh timestamps for TTL (upsert refreshes existing)\n if (this._timestamps) {\n const now = Date.now();\n for (const [id] of incoming) {\n this._timestamps.set(id, now);\n }\n }\n\n for (const [id, item] of incoming) {\n this._index.set(id, item);\n }\n\n // Enforce capacity before freeze/notify\n let result = newArray;\n if (this._maxSize > 0 && result.length > this._maxSize) {\n result = this._evictForCapacity(result);\n }\n\n this._items = Object.freeze(result);\n this.notify(prev);\n this._scheduleEvictionTimer();\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 this._timestamps?.delete(id);\n }\n\n this.notify(prev);\n this._scheduleEvictionTimer();\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\n // Record timestamps for TTL\n if (this._timestamps) {\n this._timestamps.clear();\n const now = Date.now();\n for (const item of items) {\n this._timestamps.set(item.id, now);\n }\n }\n\n let result = [...items];\n\n // Enforce capacity before freeze/notify\n if (this._maxSize > 0 && result.length > this._maxSize) {\n result = this._evictForCapacity(result);\n }\n\n this._items = Object.freeze(result);\n this.rebuildIndex();\n\n this.notify(prev);\n this._scheduleEvictionTimer();\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 this._timestamps?.clear();\n this._clearEvictionTimer();\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 const timestampSnapshot = this._timestamps ? new Map(this._timestamps) : null;\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 if (timestampSnapshot) {\n this._timestamps = timestampSnapshot;\n }\n this.rebuildIndex();\n this.notify(prev);\n this._scheduleEvictionTimer();\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): T[] {\n return this._items.filter(predicate) as T[];\n }\n\n /**\n * Return sorted copy.\n */\n sorted(compareFn: (a: T, b: T) => number): T[] {\n return [...this._items].sort(compareFn);\n }\n\n /**\n * Map items to new array.\n */\n map<U>(fn: (item: T) => U): 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._clearEvictionTimer();\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 this._timestamps?.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 /**\n * Called before items are auto-evicted by capacity or TTL.\n * Override to filter which items get evicted, or veto entirely.\n *\n * @param items - Candidates for eviction\n * @param reason - Why eviction is happening\n * @returns void to proceed with all, false to veto, or T[] subset to evict only those\n */\n protected onEvict?(items: T[], reason: 'capacity' | 'ttl'): T[] | false | void;\n\n private notify(prev: readonly T[]): void {\n for (const listener of this._listeners) {\n listener(this._items as T[], prev as T[]);\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 // ── Eviction Internals ──\n\n private _evictForCapacity(items: T[]): T[] {\n const excess = items.length - this._maxSize;\n if (excess <= 0) return items;\n\n const candidates = items.slice(0, excess);\n const toEvict = this._applyOnEvict(candidates, 'capacity');\n\n if (toEvict === false) return items; // veto\n\n if (toEvict.length === 0) return items; // nothing to evict\n\n const evictIds = new Set(toEvict.map(item => item.id));\n const result = items.filter(item => !evictIds.has(item.id));\n\n // Clean up index and timestamps for evicted items\n for (const item of toEvict) {\n this._index.delete(item.id);\n this._timestamps?.delete(item.id);\n }\n\n return result;\n }\n\n private _applyOnEvict(candidates: T[], reason: 'capacity' | 'ttl'): T[] | false {\n if (!this.onEvict) return candidates;\n\n const result = this.onEvict(candidates, reason);\n if (result === false) {\n // DEV warning when veto causes collection to exceed 2x MAX_SIZE\n if (__DEV__ && reason === 'capacity' && this._maxSize > 0) {\n const currentSize = this._items.length + candidates.length;\n if (currentSize > this._maxSize * 2) {\n console.warn(\n `[mvc-kit] Collection exceeded 2x MAX_SIZE (${currentSize}/${this._maxSize}). ` +\n `onEvict is vetoing eviction — this may cause unbounded growth.`\n );\n }\n }\n return false;\n }\n if (Array.isArray(result)) {\n // Only include items that are actually in the current items\n const candidateIds = new Set(candidates.map(c => c.id));\n return result.filter(item => candidateIds.has(item.id));\n }\n return candidates; // void = proceed with all\n }\n\n private _sweepExpired(): void {\n if (this._disposed || !this._timestamps || this._ttl <= 0) return;\n\n const now = Date.now();\n const ttl = this._ttl;\n const expired: T[] = [];\n\n for (const item of this._items) {\n const ts = this._timestamps.get(item.id);\n if (ts !== undefined && (now - ts) >= ttl) {\n expired.push(item);\n }\n }\n\n if (expired.length === 0) {\n this._scheduleEvictionTimer();\n return;\n }\n\n const toEvict = this._applyOnEvict(expired, 'ttl');\n\n if (toEvict === false) {\n this._scheduleEvictionTimer();\n return;\n }\n\n if (toEvict.length === 0) {\n this._scheduleEvictionTimer();\n return;\n }\n\n const evictIds = new Set(toEvict.map(item => item.id));\n const prev = this._items;\n this._items = Object.freeze(\n (prev as T[]).filter((item: T) => !evictIds.has(item.id))\n );\n\n for (const item of toEvict) {\n this._index.delete(item.id);\n this._timestamps.delete(item.id);\n }\n\n this.notify(prev);\n this._scheduleEvictionTimer();\n }\n\n private _scheduleEvictionTimer(): void {\n this._clearEvictionTimer();\n\n if (this._disposed || !this._timestamps || this._ttl <= 0 || this._timestamps.size === 0) return;\n\n const now = Date.now();\n const ttl = this._ttl;\n let earliest = Infinity;\n\n for (const ts of this._timestamps.values()) {\n if (ts < earliest) earliest = ts;\n }\n\n const delay = Math.max(0, (earliest + ttl) - now);\n this._evictionTimer = setTimeout(() => this._sweepExpired(), delay);\n }\n\n private _clearEvictionTimer(): void {\n if (this._evictionTimer !== null) {\n clearTimeout(this._evictionTimer);\n this._evictionTimer = null;\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Collection.js","sources":["../src/Collection.ts"],"sourcesContent":["import type { Listener, Subscribable } from './types';\n\nconst __DEV__ = typeof __MVC_KIT_DEV__ !== 'undefined' && __MVC_KIT_DEV__;\n\nfunction freeze<T>(obj: T): T {\n return __DEV__ ? Object.freeze(obj) as T : obj;\n}\n\ntype CollectionState<T> = 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 /** Maximum number of items before FIFO eviction. 0 = unlimited. */\n static MAX_SIZE = 0;\n /** Time-to-live in milliseconds. 0 = no expiry. */\n static TTL = 0;\n\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 private _timestamps: Map<T['id'], number> | null = null;\n private _evictionTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(initialItems: T[] = []) {\n let result = [...initialItems];\n\n if (this._ttl > 0) {\n this._timestamps = new Map();\n const now = Date.now();\n for (const item of result) {\n this._timestamps.set(item.id, now);\n }\n }\n\n if (this._maxSize > 0 && result.length > this._maxSize) {\n // FIFO: trim from the front (oldest items)\n const excess = result.length - this._maxSize;\n const evicted = result.slice(0, excess);\n result = result.slice(excess);\n for (const item of evicted) {\n this._timestamps?.delete(item.id);\n }\n }\n\n this._items = freeze(result);\n this.rebuildIndex();\n this._scheduleEvictionTimer();\n }\n\n /**\n * Alias for Subscribable compatibility.\n */\n get state(): T[] {\n return this._items as T[];\n }\n\n /** The raw array of items. */\n get items(): T[] {\n return this._items as T[];\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 // ── Config Accessors ──\n\n private get _maxSize(): number {\n return (this.constructor as typeof Collection).MAX_SIZE;\n }\n\n private get _ttl(): number {\n return (this.constructor as typeof Collection).TTL;\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 // Fast path: single item (most common case)\n if (items.length === 1) {\n const item = items[0];\n if (this._index.has(item.id)) return;\n const prev = this._items;\n let result = [...prev, item];\n this._index.set(item.id, item);\n if (this._timestamps) this._timestamps.set(item.id, Date.now());\n if (this._maxSize > 0 && result.length > this._maxSize) {\n result = this._evictForCapacity(result);\n }\n this._items = freeze(result);\n this.notify(prev);\n this._scheduleEvictionTimer();\n return;\n }\n\n // Multi-item path\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 let result = [...prev, ...newItems];\n\n for (const item of newItems) {\n this._index.set(item.id, item);\n }\n\n // Record timestamps for TTL\n if (this._timestamps) {\n const now = Date.now();\n for (const item of newItems) {\n this._timestamps.set(item.id, now);\n }\n }\n\n // Enforce capacity before freeze/notify\n if (this._maxSize > 0 && result.length > this._maxSize) {\n result = this._evictForCapacity(result);\n }\n\n this._items = freeze(result);\n this.notify(prev);\n this._scheduleEvictionTimer();\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 // Fast path: single item (most common case — channel messages, real-time updates)\n if (items.length === 1) {\n const item = items[0];\n const existing = this._index.get(item.id);\n\n if (existing) {\n // Replace in-place — skip if same reference\n if (existing === item) return;\n const prev = this._items;\n const idx = this._items.indexOf(existing);\n const newItems = [...prev];\n newItems[idx] = item;\n this._index.set(item.id, item);\n if (this._timestamps) this._timestamps.set(item.id, Date.now());\n this._items = freeze(newItems);\n this.notify(prev);\n } else {\n // New item — append (with capacity enforcement)\n const prev = this._items;\n let result = [...prev, item];\n this._index.set(item.id, item);\n if (this._timestamps) this._timestamps.set(item.id, Date.now());\n if (this._maxSize > 0 && result.length > this._maxSize) {\n result = this._evictForCapacity(result);\n }\n this._items = freeze(result);\n this.notify(prev);\n this._scheduleEvictionTimer();\n }\n return;\n }\n\n // Multi-item path: 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 // Record/refresh timestamps for TTL (upsert refreshes existing)\n if (this._timestamps) {\n const now = Date.now();\n for (const [id] of incoming) {\n this._timestamps.set(id, now);\n }\n }\n\n for (const [id, item] of incoming) {\n this._index.set(id, item);\n }\n\n // Enforce capacity before freeze/notify\n let result = newArray;\n if (this._maxSize > 0 && result.length > this._maxSize) {\n result = this._evictForCapacity(result);\n }\n\n this._items = freeze(result);\n this.notify(prev);\n this._scheduleEvictionTimer();\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 // Fast path: single id (most common case)\n if (ids.length === 1) {\n const id = ids[0];\n if (!this._index.has(id)) return;\n const prev = this._items;\n this._items = freeze(prev.filter(item => item.id !== id));\n this._index.delete(id);\n this._timestamps?.delete(id);\n this.notify(prev);\n this._scheduleEvictionTimer();\n return;\n }\n\n // Multi-id path\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 = freeze(filtered);\n\n for (const id of ids) {\n this._index.delete(id);\n this._timestamps?.delete(id);\n }\n\n this.notify(prev);\n this._scheduleEvictionTimer();\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 // O(1) existence check via index Map\n const existing = this._index.get(id);\n if (!existing) return;\n\n // Check if anything actually changed (before any array work)\n const keys = Object.keys(changes) as (keyof T)[];\n const hasChanges = keys.some(key => changes[key] !== existing[key]);\n if (!hasChanges) return;\n\n const updated = { ...existing, ...changes, id };\n const prev = this._items;\n const idx = this._items.indexOf(existing);\n const newItems = [...prev];\n newItems[idx] = updated;\n this._items = 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\n // Record timestamps for TTL\n if (this._timestamps) {\n this._timestamps.clear();\n const now = Date.now();\n for (const item of items) {\n this._timestamps.set(item.id, now);\n }\n }\n\n let result = [...items];\n\n // Enforce capacity before freeze/notify\n if (this._maxSize > 0 && result.length > this._maxSize) {\n result = this._evictForCapacity(result);\n }\n\n this._items = freeze(result);\n this.rebuildIndex();\n\n this.notify(prev);\n this._scheduleEvictionTimer();\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 = freeze([] as T[]);\n this._index.clear();\n this._timestamps?.clear();\n this._clearEvictionTimer();\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 const timestampSnapshot = this._timestamps ? new Map(this._timestamps) : null;\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 if (timestampSnapshot) {\n this._timestamps = timestampSnapshot;\n }\n this.rebuildIndex();\n this.notify(prev);\n this._scheduleEvictionTimer();\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): T[] {\n return this._items.filter(predicate) as T[];\n }\n\n /**\n * Return sorted copy.\n */\n sorted(compareFn: (a: T, b: T) => number): T[] {\n return [...this._items].sort(compareFn);\n }\n\n /**\n * Map items to new array.\n */\n map<U>(fn: (item: T) => U): 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._clearEvictionTimer();\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 this._timestamps?.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 /**\n * Called before items are auto-evicted by capacity or TTL.\n * Override to filter which items get evicted, or veto entirely.\n *\n * @param items - Candidates for eviction\n * @param reason - Why eviction is happening\n * @returns void to proceed with all, false to veto, or T[] subset to evict only those\n */\n protected onEvict?(items: T[], reason: 'capacity' | 'ttl'): T[] | false | void;\n\n private notify(prev: readonly T[]): void {\n for (const listener of this._listeners) {\n listener(this._items as T[], prev as T[]);\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 // ── Eviction Internals ──\n\n private _evictForCapacity(items: T[]): T[] {\n const excess = items.length - this._maxSize;\n if (excess <= 0) return items;\n\n const candidates = items.slice(0, excess);\n const toEvict = this._applyOnEvict(candidates, 'capacity');\n\n if (toEvict === false) return items; // veto\n\n if (toEvict.length === 0) return items; // nothing to evict\n\n const evictIds = new Set(toEvict.map(item => item.id));\n const result = items.filter(item => !evictIds.has(item.id));\n\n // Clean up index and timestamps for evicted items\n for (const item of toEvict) {\n this._index.delete(item.id);\n this._timestamps?.delete(item.id);\n }\n\n return result;\n }\n\n private _applyOnEvict(candidates: T[], reason: 'capacity' | 'ttl'): T[] | false {\n if (!this.onEvict) return candidates;\n\n const result = this.onEvict(candidates, reason);\n if (result === false) {\n // DEV warning when veto causes collection to exceed 2x MAX_SIZE\n if (__DEV__ && reason === 'capacity' && this._maxSize > 0) {\n const currentSize = this._items.length + candidates.length;\n if (currentSize > this._maxSize * 2) {\n console.warn(\n `[mvc-kit] Collection exceeded 2x MAX_SIZE (${currentSize}/${this._maxSize}). ` +\n `onEvict is vetoing eviction — this may cause unbounded growth.`\n );\n }\n }\n return false;\n }\n if (Array.isArray(result)) {\n // Only include items that are actually in the current items\n const candidateIds = new Set(candidates.map(c => c.id));\n return result.filter(item => candidateIds.has(item.id));\n }\n return candidates; // void = proceed with all\n }\n\n private _sweepExpired(): void {\n if (this._disposed || !this._timestamps || this._ttl <= 0) return;\n\n const now = Date.now();\n const ttl = this._ttl;\n const expired: T[] = [];\n\n for (const item of this._items) {\n const ts = this._timestamps.get(item.id);\n if (ts !== undefined && (now - ts) >= ttl) {\n expired.push(item);\n }\n }\n\n if (expired.length === 0) {\n this._scheduleEvictionTimer();\n return;\n }\n\n const toEvict = this._applyOnEvict(expired, 'ttl');\n\n if (toEvict === false) {\n this._scheduleEvictionTimer();\n return;\n }\n\n if (toEvict.length === 0) {\n this._scheduleEvictionTimer();\n return;\n }\n\n const evictIds = new Set(toEvict.map(item => item.id));\n const prev = this._items;\n this._items = freeze(\n (prev as T[]).filter((item: T) => !evictIds.has(item.id))\n );\n\n for (const item of toEvict) {\n this._index.delete(item.id);\n this._timestamps.delete(item.id);\n }\n\n this.notify(prev);\n this._scheduleEvictionTimer();\n }\n\n private _scheduleEvictionTimer(): void {\n this._clearEvictionTimer();\n\n if (this._disposed || !this._timestamps || this._ttl <= 0 || this._timestamps.size === 0) return;\n\n const now = Date.now();\n const ttl = this._ttl;\n let earliest = Infinity;\n\n for (const ts of this._timestamps.values()) {\n if (ts < earliest) earliest = ts;\n }\n\n const delay = Math.max(0, (earliest + ttl) - now);\n this._evictionTimer = setTimeout(() => this._sweepExpired(), delay);\n }\n\n private _clearEvictionTimer(): void {\n if (this._evictionTimer !== null) {\n clearTimeout(this._evictionTimer);\n this._evictionTimer = null;\n }\n }\n}\n"],"names":["prev","result"],"mappings":"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"}
|