lunibee 0.2.3 → 0.2.4

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.
Files changed (61) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +225 -225
  3. package/dist/builders/attachment.d.ts +8 -0
  4. package/dist/builders/commands.d.ts +122 -65
  5. package/dist/builders/components.d.ts +10 -31
  6. package/dist/builders/embed.d.ts +66 -33
  7. package/dist/builders/index.js +97 -131
  8. package/dist/builders/index.js.map +8 -8
  9. package/dist/collection/cache.d.ts +13 -6
  10. package/dist/collection/index.d.ts +90 -17
  11. package/dist/collection/index.js +442 -266
  12. package/dist/collection/index.js.map +4 -4
  13. package/dist/core/index.d.ts +8 -0
  14. package/dist/core/index.js +607 -352
  15. package/dist/core/index.js.map +47 -47
  16. package/dist/core/permissions.d.ts +7 -3
  17. package/dist/formatters/index.js +9 -5
  18. package/dist/formatters/index.js.map +3 -3
  19. package/dist/handlers/index.js +5 -10
  20. package/dist/handlers/index.js.map +3 -3
  21. package/dist/index.js +769 -587
  22. package/dist/index.js.map +65 -65
  23. package/dist/managers/base.d.ts +22 -14
  24. package/dist/managers/index.d.ts +2 -1
  25. package/dist/managers/index.js +445 -276
  26. package/dist/managers/index.js.map +26 -26
  27. package/dist/managers/message.d.ts +7 -3
  28. package/dist/rest/errors.d.ts +14 -7
  29. package/dist/rest/index.d.ts +24 -12
  30. package/dist/rest/index.js +54 -17
  31. package/dist/rest/index.js.map +14 -14
  32. package/dist/rest/redis.d.ts +1 -1
  33. package/dist/rest/route.d.ts +8 -4
  34. package/dist/rest/routes.d.ts +102 -48
  35. package/dist/rest/transport.d.ts +10 -5
  36. package/dist/rest/webhook.d.ts +9 -5
  37. package/dist/sharding/bus.d.ts +34 -17
  38. package/dist/sharding/index.d.ts +34 -17
  39. package/dist/sharding/index.js +64 -32
  40. package/dist/sharding/index.js.map +17 -17
  41. package/dist/structures/base.d.ts +19 -10
  42. package/dist/structures/channels.d.ts +28 -14
  43. package/dist/structures/index.js +9 -59
  44. package/dist/structures/index.js.map +19 -18
  45. package/dist/structures/interactions.d.ts +96 -48
  46. package/dist/structures/resources.d.ts +88 -44
  47. package/dist/types/gateway.d.ts +1 -1
  48. package/dist/types/index.js +20 -22
  49. package/dist/types/index.js.map +4 -4
  50. package/dist/utils/index.js.map +2 -2
  51. package/dist/voice/index.d.ts +12 -4
  52. package/dist/voice/index.js +14 -18
  53. package/dist/voice/index.js.map +3 -3
  54. package/dist/ws/decoder.d.ts +6 -2
  55. package/dist/ws/index.d.ts +25 -13
  56. package/dist/ws/index.js +63 -31
  57. package/dist/ws/index.js.map +14 -14
  58. package/dist/ws/protocol.d.ts +10 -2
  59. package/dist/ws/session.d.ts +14 -4
  60. package/dist/ws/state.d.ts +22 -11
  61. package/package.json +15 -14
@@ -1,64 +1,36 @@
1
1
  // @bun
2
2
  // packages/collection/src/cache.ts
3
3
  class Cache {
4
- #entries = new Collection;
5
- #maxSize;
6
- #ttl;
7
- #timer;
4
+ #entries;
8
5
  constructor(options = {}) {
9
- this.#maxSize = options.maxSize ?? Infinity;
10
- this.#ttl = options.ttl ?? 0;
11
- if (!Number.isInteger(this.#maxSize) && this.#maxSize !== Infinity || this.#maxSize < 1)
6
+ const maxSize = options.maxSize ?? Infinity;
7
+ const ttl = options.ttl ?? 0;
8
+ if (!Number.isInteger(maxSize) && maxSize !== Infinity || maxSize < 1)
12
9
  throw new RangeError("Cache maxSize must be a positive integer.");
13
- if (!Number.isFinite(this.#ttl) || this.#ttl < 0)
10
+ if (!Number.isFinite(ttl) || ttl < 0)
14
11
  throw new RangeError("Cache ttl must be a non-negative finite number.");
15
- if (this.#ttl > 0) {
16
- const interval = options.sweepInterval ?? Math.min(this.#ttl, 60000);
12
+ if (ttl > 0) {
13
+ const interval = options.sweepInterval ?? Math.min(ttl, 60000);
17
14
  if (!Number.isFinite(interval) || interval < 1)
18
15
  throw new RangeError("Cache sweepInterval must be positive.");
19
- this.#timer = setInterval(() => this.sweep(), interval);
20
- this.#timer.unref?.();
21
16
  }
17
+ this.#entries = new Collection(null, {
18
+ ttl: ttl > 0 ? ttl : undefined,
19
+ maxSize: maxSize === Infinity ? undefined : maxSize,
20
+ slide: false
21
+ });
22
22
  }
23
23
  get size() {
24
- this.#sweepExpired();
25
24
  return this.#entries.size;
26
25
  }
27
26
  get(key) {
28
- const entry = this.#entries.get(key);
29
- if (!entry)
30
- return;
31
- if (entry.expiresAt > 0 && entry.expiresAt <= Date.now()) {
32
- this.#entries.delete(key);
33
- return;
34
- }
35
- this.#entries.delete(key);
36
- this.#entries.set(key, entry);
37
- return entry.value;
27
+ return this.#entries.get(key);
38
28
  }
39
29
  has(key) {
40
- const entry = this.#entries.get(key);
41
- if (!entry)
42
- return false;
43
- if (entry.expiresAt > 0 && entry.expiresAt <= Date.now()) {
44
- this.#entries.delete(key);
45
- return false;
46
- }
47
- return true;
30
+ return this.#entries.has(key);
48
31
  }
49
32
  set(key, value) {
50
- const expiresAt = this.#ttl > 0 ? Date.now() + this.#ttl : 0;
51
- this.#entries.delete(key);
52
- this.#entries.set(key, { value, expiresAt });
53
- if (this.#maxSize !== Infinity) {
54
- while (this.#entries.size > this.#maxSize) {
55
- const oldest = this.#entries.firstKey();
56
- if (oldest !== undefined)
57
- this.#entries.delete(oldest);
58
- else
59
- break;
60
- }
61
- }
33
+ this.#entries.set(key, value);
62
34
  return this;
63
35
  }
64
36
  delete(key) {
@@ -68,95 +40,52 @@ class Cache {
68
40
  this.#entries.clear();
69
41
  }
70
42
  invalidate(predicate) {
71
- return this.#entries.sweep((entry, key) => predicate(entry.value, key));
43
+ return this.#entries.sweep(predicate);
72
44
  }
73
45
  sweep() {
74
- return this.#entries.sweep((entry) => this.#expired(entry));
75
- }
76
- dispose() {
77
- if (this.#timer)
78
- clearInterval(this.#timer);
79
- this.#timer = undefined;
46
+ return this.#entries.purge();
80
47
  }
48
+ dispose() {}
81
49
  values() {
82
- this.#sweepExpired();
83
- return this.#entries.map((entry) => entry.value);
50
+ return [...this.#entries.values()];
84
51
  }
85
52
  entries() {
86
- this.#sweepExpired();
87
- return this.#entries.map((entry, key) => [key, entry.value]);
88
- }
89
- #expired(entry) {
90
- return entry.expiresAt > 0 && entry.expiresAt <= Date.now();
91
- }
92
- #sweepExpired() {
93
- if (this.#ttl > 0)
94
- this.sweep();
53
+ return [...this.#entries.entries()];
95
54
  }
96
55
  }
97
56
 
98
57
  // packages/collection/src/index.ts
99
- class RecencyList {
100
- #nodes = new Map;
101
- #oldest;
102
- #newest;
103
- get size() {
104
- return this.#nodes.size;
105
- }
106
- oldest() {
107
- return this.#oldest?.key;
108
- }
109
- touch(key) {
110
- const node = this.#nodes.get(key);
111
- if (node)
112
- return this.#moveNewest(node);
113
- const created = { key, older: this.#newest };
114
- if (this.#newest)
115
- this.#newest.newer = created;
116
- else
117
- this.#oldest = created;
118
- this.#newest = created;
119
- this.#nodes.set(key, created);
120
- }
121
- promote(key) {
122
- const node = this.#nodes.get(key);
123
- if (node)
124
- this.#moveNewest(node);
125
- }
126
- delete(key) {
127
- const node = this.#nodes.get(key);
128
- if (!node)
129
- return false;
130
- this.#unlink(node);
131
- this.#nodes.delete(key);
132
- return true;
133
- }
134
- clear() {
135
- this.#nodes.clear();
136
- this.#oldest = this.#newest = undefined;
137
- }
138
- #unlink(node) {
139
- if (node.older)
140
- node.older.newer = node.newer;
141
- else
142
- this.#oldest = node.newer;
143
- if (node.newer)
144
- node.newer.older = node.older;
145
- else
146
- this.#newest = node.older;
147
- node.older = node.newer = undefined;
148
- }
149
- #moveNewest(node) {
150
- if (node === this.#newest)
151
- return;
152
- this.#unlink(node);
153
- node.older = this.#newest;
154
- if (this.#newest)
155
- this.#newest.newer = node;
156
- else
157
- this.#oldest = node;
158
- this.#newest = node;
159
- }
58
+ function newPolicy(options = {}) {
59
+ return {
60
+ ttl: options.ttl,
61
+ maxSize: options.maxSize,
62
+ slide: options.slide ?? true,
63
+ onEvict: options.onEvict,
64
+ expired: 0,
65
+ evicted: 0,
66
+ entries: new Map,
67
+ oldest: undefined,
68
+ newest: undefined,
69
+ lruSize: 0,
70
+ heap: [],
71
+ armedFor: Infinity
72
+ };
73
+ }
74
+ function peekOf(collection, key) {
75
+ return collection instanceof Map ? Map.prototype.get.call(collection, key) : collection.get(key);
76
+ }
77
+ var mapGet = Map.prototype.get;
78
+ var mapHas = Map.prototype.has;
79
+ function sample(items, amount) {
80
+ if (!Number.isInteger(amount) || amount < 0)
81
+ throw new RangeError("amount must be a non-negative integer.");
82
+ const count = Math.min(amount, items.length);
83
+ for (let i = 0;i < count; i++) {
84
+ const j = i + Math.floor(Math.random() * (items.length - i));
85
+ [items[i], items[j]] = [items[j], items[i]];
86
+ }
87
+ items.length = count;
88
+ return items;
160
89
  }
161
90
  function assertTTL(ttl) {
162
91
  if (ttl !== undefined && (!Number.isFinite(ttl) || ttl <= 0))
@@ -164,81 +93,90 @@ function assertTTL(ttl) {
164
93
  }
165
94
 
166
95
  class Collection extends Map {
167
- #ttl;
168
- #maxSize;
169
- #onEvict;
170
- #expiry = new Map;
171
- #lru = new RecencyList;
172
- #stats = {
173
- hits: 0,
174
- misses: 0,
175
- expired: 0,
176
- evicted: 0
177
- };
178
- #heap = [];
179
- #timer;
180
- #armedFor = Infinity;
96
+ #policy;
97
+ #hits = 0;
98
+ #misses = 0;
181
99
  constructor(entries, options = {}) {
182
100
  super();
183
101
  assertTTL(options.ttl);
184
102
  if (options.maxSize !== undefined && (!Number.isInteger(options.maxSize) || options.maxSize <= 0))
185
103
  throw new RangeError("maxSize must be a positive integer.");
186
- this.#ttl = options.ttl;
187
- this.#maxSize = options.maxSize;
188
- this.#onEvict = options.onEvict;
104
+ if (options.ttl !== undefined || options.maxSize !== undefined || options.slide !== undefined || options.onEvict !== undefined)
105
+ this.#policy = newPolicy(options);
189
106
  if (entries)
190
107
  for (const [key, value] of entries)
191
108
  this.set(key, value);
192
109
  }
193
110
  set(key, value, ttl) {
111
+ if (ttl === undefined && this.#policy === undefined)
112
+ return super.set(key, value);
194
113
  assertTTL(ttl);
195
- const window = ttl ?? this.#ttl;
196
- if (this.#maxSize !== undefined) {
197
- this.#lru.touch(key);
198
- }
199
- super.set(key, value);
114
+ const window = ttl ?? this.#policy?.ttl;
200
115
  if (window !== undefined)
201
- this.#schedule(key, window);
202
- else if (this.#expiry.size > 0)
203
- this.#expiry.delete(key);
116
+ this.#policy ??= newPolicy();
117
+ if (!this.#policy)
118
+ return super.set(key, value);
119
+ const before = super.size;
120
+ super.set(key, value);
121
+ this.#track(key, value, window, super.size !== before);
204
122
  this.#enforceCap();
205
123
  return this;
206
124
  }
207
125
  setWithoutTTL(key, value) {
208
- if (this.#expiry.size > 0)
209
- this.#expiry.delete(key);
210
- if (this.#lru.size > 0)
211
- this.#lru.delete(key);
126
+ if (this.#policy)
127
+ this.#forget(key);
212
128
  super.set(key, value);
213
129
  return this;
214
130
  }
215
131
  get(key) {
216
- if (this.#expireIfDue(key)) {
217
- this.#stats.misses++;
132
+ const policy = this.#policy;
133
+ const entry = policy?.entries.get(key);
134
+ if (entry === undefined) {
135
+ const value = mapGet.call(this, key);
136
+ if (value !== undefined || mapHas.call(this, key)) {
137
+ this.#hits++;
138
+ return value;
139
+ }
140
+ this.#misses++;
218
141
  return;
219
142
  }
220
- const value = super.get(key);
221
- if (value === undefined && !super.has(key)) {
222
- this.#stats.misses++;
143
+ const timed = entry.window !== 0;
144
+ const now = timed ? Date.now() : 0;
145
+ if (timed && entry.deadline <= now) {
146
+ this.#expire(entry);
147
+ this.#misses++;
223
148
  return;
224
149
  }
225
- this.#stats.hits++;
226
- const expiry = this.#expiry.get(key);
227
- if (expiry)
228
- expiry.deadline = Date.now() + expiry.window;
229
- this.#lru.promote(key);
230
- return value;
150
+ this.#hits++;
151
+ if (timed && policy.slide)
152
+ entry.deadline = now + entry.window;
153
+ if (entry.inLru)
154
+ this.#promote(policy, entry);
155
+ return entry.value;
156
+ }
157
+ ensure(key, factory, ttl) {
158
+ const existing = this.get(key);
159
+ if (existing !== undefined || super.has(key))
160
+ return existing;
161
+ const created = factory(key, this);
162
+ this.set(key, created, ttl);
163
+ return created;
231
164
  }
232
165
  peek(key) {
233
166
  if (!this.#expireIfDue(key) && super.has(key)) {
234
- this.#stats.hits++;
167
+ this.#hits++;
235
168
  return super.get(key);
236
169
  }
237
- this.#stats.misses++;
170
+ this.#misses++;
238
171
  return;
239
172
  }
240
173
  get stats() {
241
- return { ...this.#stats };
174
+ return {
175
+ hits: this.#hits,
176
+ misses: this.#misses,
177
+ expired: this.#policy?.expired ?? 0,
178
+ evicted: this.#policy?.evicted ?? 0
179
+ };
242
180
  }
243
181
  has(key) {
244
182
  return !this.#expireIfDue(key) && super.has(key);
@@ -246,19 +184,23 @@ class Collection extends Map {
246
184
  delete(key) {
247
185
  if (this.#expireIfDue(key))
248
186
  return false;
249
- this.#expiry.delete(key);
250
- this.#lru.delete(key);
187
+ if (this.#policy)
188
+ this.#forget(key);
251
189
  return super.delete(key);
252
190
  }
253
191
  clear() {
254
192
  super.clear();
255
- this.#expiry.clear();
256
- this.#lru.clear();
257
- this.#heap.length = 0;
258
- if (this.#timer)
259
- clearTimeout(this.#timer);
260
- this.#timer = undefined;
261
- this.#armedFor = Infinity;
193
+ const policy = this.#policy;
194
+ if (!policy)
195
+ return;
196
+ policy.entries.clear();
197
+ policy.oldest = policy.newest = undefined;
198
+ policy.lruSize = 0;
199
+ policy.heap.length = 0;
200
+ if (policy.timer)
201
+ clearTimeout(policy.timer);
202
+ policy.timer = undefined;
203
+ policy.armedFor = Infinity;
262
204
  }
263
205
  get size() {
264
206
  this.purge();
@@ -286,11 +228,11 @@ class Collection extends Map {
286
228
  ttlRemaining(key) {
287
229
  if (this.#expireIfDue(key))
288
230
  return;
289
- const expiry = this.#expiry.get(key);
290
- return expiry && Math.max(0, expiry.deadline - Date.now());
231
+ const entry = this.#policy?.entries.get(key);
232
+ return entry && entry.window !== 0 ? Math.max(0, entry.deadline - Date.now()) : undefined;
291
233
  }
292
234
  purge() {
293
- if (this.#expiry.size === 0)
235
+ if (!this.#policy || this.#policy.heap.length === 0)
294
236
  return 0;
295
237
  const now = Date.now();
296
238
  let removed = 0;
@@ -301,133 +243,255 @@ class Collection extends Map {
301
243
  this.#remove(due.key);
302
244
  removed++;
303
245
  }
304
- this.#stats.expired += removed;
246
+ this.#policy.expired += removed;
305
247
  this.#rearm();
306
248
  for (const [key, value] of dropped)
307
249
  this.#notify(key, value, "expired");
308
250
  return removed;
309
251
  }
310
252
  #expireIfDue(key) {
311
- const expiry = this.#expiry.get(key);
312
- if (!expiry || expiry.deadline > Date.now())
253
+ const entry = this.#policy?.entries.get(key);
254
+ if (!entry || entry.window === 0 || entry.deadline > Date.now())
313
255
  return false;
314
- const value = super.get(key);
315
- this.#remove(key);
316
- this.#stats.expired++;
317
- this.#notify(key, value, "expired");
256
+ this.#expire(entry);
318
257
  return true;
319
258
  }
259
+ #expire(entry) {
260
+ const value = super.get(entry.key);
261
+ this.#remove(entry.key);
262
+ this.#policy.expired++;
263
+ this.#notify(entry.key, value, "expired");
264
+ }
320
265
  #remove(key) {
321
- this.#expiry.delete(key);
322
- this.#lru.delete(key);
266
+ this.#forget(key);
323
267
  super.delete(key);
324
268
  }
269
+ #forget(key) {
270
+ const policy = this.#policy;
271
+ const entry = policy.entries.get(key);
272
+ if (!entry)
273
+ return;
274
+ if (entry.inLru)
275
+ this.#unlink(policy, entry);
276
+ policy.entries.delete(key);
277
+ }
278
+ #track(key, value, window, isNew) {
279
+ const policy = this.#policy;
280
+ const lru = policy.maxSize !== undefined;
281
+ let entry = isNew ? undefined : policy.entries.get(key);
282
+ if (entry)
283
+ entry.value = value;
284
+ if (window === undefined) {
285
+ if (entry && entry.window !== 0) {
286
+ if (lru)
287
+ entry = this.#replace(policy, entry, 0, 0);
288
+ else {
289
+ this.#forget(key);
290
+ return;
291
+ }
292
+ }
293
+ if (!entry && lru) {
294
+ entry = this.#create(key, value, 0, 0);
295
+ policy.entries.set(key, entry);
296
+ }
297
+ if (entry)
298
+ this.#promote(policy, entry);
299
+ return;
300
+ }
301
+ const deadline = Date.now() + window;
302
+ if (entry && entry.window !== 0) {
303
+ entry.deadline = deadline;
304
+ entry.window = window;
305
+ if (deadline < entry.filed)
306
+ entry = this.#replace(policy, entry, window, deadline);
307
+ else {
308
+ if (entry.inLru)
309
+ this.#promote(policy, entry);
310
+ return;
311
+ }
312
+ } else if (entry) {
313
+ entry.window = window;
314
+ entry.deadline = entry.filed = deadline;
315
+ } else {
316
+ entry = this.#create(key, value, window, deadline);
317
+ policy.entries.set(key, entry);
318
+ }
319
+ if (lru)
320
+ this.#promote(policy, entry);
321
+ this.#heapPush(entry);
322
+ if (policy.heap.length > 2 * policy.entries.size + 8)
323
+ this.#compact();
324
+ if (policy.timer === undefined || deadline < policy.armedFor)
325
+ this.#rearm();
326
+ }
327
+ #create(key, value, window, deadline) {
328
+ return {
329
+ key,
330
+ value,
331
+ older: undefined,
332
+ newer: undefined,
333
+ inLru: false,
334
+ window,
335
+ deadline,
336
+ filed: deadline
337
+ };
338
+ }
339
+ #replace(policy, old, window, deadline) {
340
+ const entry = {
341
+ ...old,
342
+ window,
343
+ deadline,
344
+ filed: deadline
345
+ };
346
+ if (old.inLru) {
347
+ if (old.older)
348
+ old.older.newer = entry;
349
+ else
350
+ policy.oldest = entry;
351
+ if (old.newer)
352
+ old.newer.older = entry;
353
+ else
354
+ policy.newest = entry;
355
+ }
356
+ policy.entries.set(old.key, entry);
357
+ return entry;
358
+ }
359
+ #promote(policy, entry) {
360
+ if (entry === policy.newest)
361
+ return;
362
+ if (entry.inLru)
363
+ this.#unlink(policy, entry, true);
364
+ else {
365
+ entry.inLru = true;
366
+ policy.lruSize++;
367
+ }
368
+ entry.older = policy.newest;
369
+ entry.newer = undefined;
370
+ if (policy.newest)
371
+ policy.newest.newer = entry;
372
+ else
373
+ policy.oldest = entry;
374
+ policy.newest = entry;
375
+ }
376
+ #unlink(policy, entry, keepCount = false) {
377
+ if (entry.older)
378
+ entry.older.newer = entry.newer;
379
+ else
380
+ policy.oldest = entry.newer;
381
+ if (entry.newer)
382
+ entry.newer.older = entry.older;
383
+ else
384
+ policy.newest = entry.older;
385
+ entry.older = entry.newer = undefined;
386
+ if (!keepCount) {
387
+ entry.inLru = false;
388
+ policy.lruSize--;
389
+ }
390
+ }
391
+ #derived() {
392
+ const Species = this.constructor[Symbol.species] ?? Collection;
393
+ return new Species;
394
+ }
325
395
  #notify(key, value, reason) {
326
- if (!this.#onEvict)
396
+ const onEvict = this.#policy?.onEvict;
397
+ if (!onEvict)
327
398
  return;
328
399
  try {
329
- this.#onEvict(key, value, reason);
400
+ onEvict(key, value, reason);
330
401
  } catch {}
331
402
  }
332
403
  #enforceCap() {
333
- if (this.#maxSize === undefined)
404
+ const policy = this.#policy;
405
+ const max = policy.maxSize;
406
+ if (max === undefined)
334
407
  return;
335
- while (this.#lru.size > this.#maxSize) {
336
- const oldest = this.#lru.oldest();
337
- const value = super.get(oldest);
338
- this.#remove(oldest);
339
- this.#stats.evicted++;
340
- this.#notify(oldest, value, "evicted");
408
+ if (policy.lruSize > max && policy.heap.length > 0 && policy.heap[0].filed <= Date.now())
409
+ this.purge();
410
+ while (policy.lruSize > max) {
411
+ const oldest = policy.oldest;
412
+ const value = policy.onEvict ? super.get(oldest.key) : undefined;
413
+ this.#unlink(policy, oldest);
414
+ policy.entries.delete(oldest.key);
415
+ super.delete(oldest.key);
416
+ policy.evicted++;
417
+ this.#notify(oldest.key, value, "evicted");
341
418
  }
342
419
  }
343
- #schedule(key, window) {
344
- const deadline = Date.now() + window;
345
- const expiry = this.#expiry.get(key);
346
- if (expiry) {
347
- expiry.deadline = deadline;
348
- expiry.window = window;
349
- if (deadline >= expiry.filed)
350
- return;
351
- expiry.filed = deadline;
352
- } else
353
- this.#expiry.set(key, { deadline, window, filed: deadline });
354
- this.#heapPush({ key, deadline });
355
- if (this.#heap.length > 2 * this.#expiry.size + 8)
356
- this.#compact();
357
- this.#rearm();
358
- }
359
420
  #nextDeadline() {
421
+ const policy = this.#policy;
360
422
  for (;; ) {
361
- const top = this.#heap[0];
423
+ const top = policy.heap[0];
362
424
  if (top === undefined)
363
425
  return Infinity;
364
- const expiry = this.#expiry.get(top.key);
365
- if (!expiry || expiry.filed !== top.deadline) {
426
+ if (policy.entries.get(top.key) !== top) {
366
427
  this.#heapPop();
367
428
  continue;
368
429
  }
369
- if (expiry.deadline === top.deadline)
370
- return top.deadline;
430
+ if (top.deadline === top.filed)
431
+ return top.filed;
371
432
  this.#heapPop();
372
- expiry.filed = expiry.deadline;
373
- this.#heapPush({ key: top.key, deadline: expiry.deadline });
433
+ top.filed = top.deadline;
434
+ this.#heapPush(top);
374
435
  }
375
436
  }
376
437
  #compact() {
377
- const live = this.#heap.filter((record) => this.#expiry.get(record.key)?.filed === record.deadline);
378
- this.#heap.length = 0;
379
- for (const record of live)
380
- this.#heapPush(record);
438
+ const policy = this.#policy;
439
+ const live = policy.heap.filter((entry) => policy.entries.get(entry.key) === entry);
440
+ policy.heap.length = 0;
441
+ for (const entry of live)
442
+ this.#heapPush(entry);
381
443
  }
382
444
  #rearm() {
445
+ const p = this.#policy;
383
446
  const deadline = this.#nextDeadline();
384
- if (this.#timer !== undefined && deadline >= this.#armedFor)
447
+ if (p.timer !== undefined && deadline >= p.armedFor)
385
448
  return;
386
- if (this.#timer)
387
- clearTimeout(this.#timer);
388
- this.#timer = undefined;
389
- this.#armedFor = deadline;
449
+ if (p.timer)
450
+ clearTimeout(p.timer);
451
+ p.timer = undefined;
452
+ p.armedFor = deadline;
390
453
  if (deadline === Infinity)
391
454
  return;
392
- this.#timer = setTimeout(() => {
393
- this.#timer = undefined;
394
- this.#armedFor = Infinity;
455
+ p.timer = setTimeout(() => {
456
+ p.timer = undefined;
457
+ p.armedFor = Infinity;
395
458
  this.purge();
396
459
  }, Math.max(0, deadline - Date.now()));
397
- this.#timer.unref?.();
460
+ p.timer.unref?.();
398
461
  }
399
- #heapPush(record) {
400
- const heap = this.#heap;
401
- heap.push(record);
402
- let i = heap.length - 1;
462
+ #heapPush(entry) {
463
+ const heap = this.#policy.heap;
464
+ let i = heap.length;
465
+ heap.push(entry);
403
466
  while (i > 0) {
404
467
  const parent = i - 1 >> 1;
405
- if (heap[parent].deadline <= heap[i].deadline)
468
+ const above = heap[parent];
469
+ if (above.filed <= entry.filed)
406
470
  break;
407
- [heap[parent], heap[i]] = [heap[i], heap[parent]];
471
+ heap[i] = above;
408
472
  i = parent;
409
473
  }
474
+ heap[i] = entry;
410
475
  }
411
476
  #heapPop() {
412
- const heap = this.#heap;
477
+ const heap = this.#policy.heap;
413
478
  const top = heap[0];
414
479
  const last = heap.pop();
415
480
  if (top === undefined || heap.length === 0)
416
481
  return top;
417
- heap[0] = last;
418
- for (let i = 0;; ) {
419
- const left = 2 * i + 1;
420
- const right = left + 1;
421
- let smallest = i;
422
- if (left < heap.length && heap[left].deadline < heap[smallest].deadline)
423
- smallest = left;
424
- if (right < heap.length && heap[right].deadline < heap[smallest].deadline)
425
- smallest = right;
426
- if (smallest === i)
482
+ let i = 0;
483
+ for (;; ) {
484
+ let child = 2 * i + 1;
485
+ if (child >= heap.length)
427
486
  break;
428
- [heap[smallest], heap[i]] = [heap[i], heap[smallest]];
429
- i = smallest;
487
+ if (child + 1 < heap.length && heap[child + 1].filed < heap[child].filed)
488
+ child++;
489
+ if (heap[child].filed >= last.filed)
490
+ break;
491
+ heap[i] = heap[child];
492
+ i = child;
430
493
  }
494
+ heap[i] = last;
431
495
  return top;
432
496
  }
433
497
  first() {
@@ -459,8 +523,26 @@ class Collection extends Map {
459
523
  }
460
524
  return;
461
525
  }
526
+ findLast(predicate) {
527
+ const entries = [...this];
528
+ for (let i = entries.length - 1;i >= 0; i--) {
529
+ const [key, value] = entries[i];
530
+ if (predicate(value, key, this))
531
+ return value;
532
+ }
533
+ return;
534
+ }
535
+ findLastKey(predicate) {
536
+ const entries = [...this];
537
+ for (let i = entries.length - 1;i >= 0; i--) {
538
+ const [key, value] = entries[i];
539
+ if (predicate(value, key, this))
540
+ return key;
541
+ }
542
+ return;
543
+ }
462
544
  filter(predicate) {
463
- const result = new Collection;
545
+ const result = this.#derived();
464
546
  for (const [key, value] of this) {
465
547
  if (predicate(value, key, this))
466
548
  result.set(key, value);
@@ -504,7 +586,7 @@ class Collection extends Map {
504
586
  return [...this.entries()];
505
587
  }
506
588
  clone() {
507
- const copy = new Collection;
589
+ const copy = this.#derived();
508
590
  for (const [key, value] of this)
509
591
  copy.set(key, value);
510
592
  return copy;
@@ -559,7 +641,7 @@ class Collection extends Map {
559
641
  return result;
560
642
  }
561
643
  intersection(other) {
562
- const result = new Collection;
644
+ const result = this.#derived();
563
645
  for (const [key, value] of this) {
564
646
  if (other.has(key))
565
647
  result.set(key, value);
@@ -567,7 +649,7 @@ class Collection extends Map {
567
649
  return result;
568
650
  }
569
651
  difference(other) {
570
- const result = new Collection;
652
+ const result = this.#derived();
571
653
  for (const [key, value] of this) {
572
654
  if (!other.has(key))
573
655
  result.set(key, value);
@@ -575,8 +657,8 @@ class Collection extends Map {
575
657
  return result;
576
658
  }
577
659
  partition(predicate) {
578
- const pass = new Collection;
579
- const fail = new Collection;
660
+ const pass = this.#derived();
661
+ const fail = this.#derived();
580
662
  for (const [key, value] of this) {
581
663
  if (predicate(value, key, this))
582
664
  pass.set(key, value);
@@ -585,6 +667,81 @@ class Collection extends Map {
585
667
  }
586
668
  return [pass, fail];
587
669
  }
670
+ symmetricDifference(other) {
671
+ const result = this.#derived();
672
+ for (const [key, value] of this)
673
+ if (!other.has(key))
674
+ result.set(key, value);
675
+ for (const [key, value] of other)
676
+ if (!this.has(key))
677
+ result.set(key, value);
678
+ return result;
679
+ }
680
+ concat(...collections) {
681
+ const result = this.clone();
682
+ for (const collection of collections)
683
+ for (const [key, value] of collection)
684
+ result.set(key, value);
685
+ return result;
686
+ }
687
+ merge(other, whenInSelf, whenInOther, whenInBoth) {
688
+ const result = this.#derived();
689
+ const decide = (key, kept) => {
690
+ if (kept.keep)
691
+ result.set(key, kept.value);
692
+ };
693
+ for (const [key, value] of this) {
694
+ decide(key, other.has(key) ? whenInBoth(value, peekOf(other, key), key) : whenInSelf(value, key));
695
+ }
696
+ for (const [key, value] of other)
697
+ if (!this.has(key))
698
+ decide(key, whenInOther(value, key));
699
+ return result;
700
+ }
701
+ equals(other) {
702
+ if (!other)
703
+ return false;
704
+ if (other === this)
705
+ return true;
706
+ if (this.size !== other.size)
707
+ return false;
708
+ for (const [key, value] of this) {
709
+ if (!other.has(key))
710
+ return false;
711
+ if (value !== peekOf(other, key))
712
+ return false;
713
+ }
714
+ return true;
715
+ }
716
+ mapValues(transform) {
717
+ const result = this.#derived();
718
+ for (const [key, value] of this)
719
+ result.set(key, transform(value, key, this));
720
+ return result;
721
+ }
722
+ toReversed() {
723
+ const result = this.#derived();
724
+ const entries = [...this];
725
+ for (let i = entries.length - 1;i >= 0; i--)
726
+ result.set(entries[i][0], entries[i][1]);
727
+ return result;
728
+ }
729
+ toSorted(comparator) {
730
+ return this.sorted(comparator);
731
+ }
732
+ static groupBy(items, keySelector) {
733
+ const groups = new Collection;
734
+ let index = 0;
735
+ for (const item of items)
736
+ groups.ensure(keySelector(item, index++), () => []).push(item);
737
+ return groups;
738
+ }
739
+ static combineEntries(entries, combine) {
740
+ const result = new Collection;
741
+ for (const [key, value] of entries)
742
+ result.set(key, result.has(key) ? combine(result.get(key), value, key) : value);
743
+ return result;
744
+ }
588
745
  tap(fn) {
589
746
  fn(this);
590
747
  return this;
@@ -603,6 +760,13 @@ class Collection extends Map {
603
760
  acc = fn(acc, value, key, this);
604
761
  return acc;
605
762
  }
763
+ reduceRight(fn, initialValue) {
764
+ const entries = [...this];
765
+ let acc = initialValue;
766
+ for (let i = entries.length - 1;i >= 0; i--)
767
+ acc = fn(acc, entries[i][1], entries[i][0], this);
768
+ return acc;
769
+ }
606
770
  sorted(comparator) {
607
771
  const decorated = [...this.entries()].map((entry, index) => ({
608
772
  entry,
@@ -613,22 +777,34 @@ class Collection extends Map {
613
777
  const comparison = comparator(x.entry[1], y.entry[1], x.entry[0], y.entry[0]);
614
778
  return comparison !== 0 ? comparison : x.index - y.index;
615
779
  });
616
- const result = new Collection;
780
+ const result = this.#derived();
617
781
  for (const { entry } of decorated)
618
782
  result.set(entry[0], entry[1]);
619
783
  return result;
620
784
  }
621
- random() {
622
- const arr = [...this.values()];
623
- if (!arr.length)
785
+ random(amount) {
786
+ if (amount !== undefined)
787
+ return sample([...this.values()], amount);
788
+ const size = this.size;
789
+ if (size === 0)
624
790
  return;
625
- return arr[Math.floor(Math.random() * arr.length)];
791
+ let index = Math.floor(Math.random() * size);
792
+ for (const value of this.values())
793
+ if (index-- === 0)
794
+ return value;
795
+ return;
626
796
  }
627
- randomKey() {
628
- const arr = [...this.keys()];
629
- if (!arr.length)
797
+ randomKey(amount) {
798
+ if (amount !== undefined)
799
+ return sample([...this.keys()], amount);
800
+ const size = this.size;
801
+ if (size === 0)
630
802
  return;
631
- return arr[Math.floor(Math.random() * arr.length)];
803
+ let index = Math.floor(Math.random() * size);
804
+ for (const key of this.keys())
805
+ if (index-- === 0)
806
+ return key;
807
+ return;
632
808
  }
633
809
  at(index) {
634
810
  const arr = [...this.values()];
@@ -649,4 +825,4 @@ export {
649
825
  Collection
650
826
  };
651
827
 
652
- //# debugId=4109A00736CB03B064756E2164756E21
828
+ //# debugId=72EF4AA34379CD3464756E2164756E21