lunibee 0.3.1 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dist/builders/attachment.d.ts +1 -0
  2. package/dist/builders/clone.d.ts +10 -0
  3. package/dist/builders/commands.d.ts +1 -1
  4. package/dist/builders/components.d.ts +24 -5
  5. package/dist/builders/index.js +64 -17
  6. package/dist/builders/index.js.map +10 -9
  7. package/dist/collection/index.d.ts +1 -0
  8. package/dist/collection/index.js +297 -19
  9. package/dist/collection/index.js.map +5 -4
  10. package/dist/collection/redis.d.ts +98 -0
  11. package/dist/core/collector.d.ts +8 -0
  12. package/dist/core/events.d.ts +1 -0
  13. package/dist/core/index.d.ts +3 -0
  14. package/dist/core/index.js +6242 -4733
  15. package/dist/core/index.js.map +47 -40
  16. package/dist/core/permissions.d.ts +3 -402
  17. package/dist/core/redis-cache.d.ts +85 -0
  18. package/dist/formatters/index.d.ts +5 -1
  19. package/dist/formatters/index.js +7 -3
  20. package/dist/formatters/index.js.map +3 -3
  21. package/dist/handlers/index.js +11 -2
  22. package/dist/handlers/index.js.map +3 -3
  23. package/dist/index.js +8688 -6136
  24. package/dist/index.js.map +67 -59
  25. package/dist/managers/application.d.ts +10 -6
  26. package/dist/managers/base.d.ts +11 -1
  27. package/dist/managers/guild.d.ts +3 -1
  28. package/dist/managers/index.d.ts +6 -1
  29. package/dist/managers/index.js +383 -109
  30. package/dist/managers/index.js.map +20 -23
  31. package/dist/managers/member.d.ts +3 -1
  32. package/dist/managers/message.d.ts +13 -4
  33. package/dist/managers/thread.d.ts +3 -3
  34. package/dist/rest/decoder.d.ts +2 -0
  35. package/dist/rest/errors.d.ts +5 -2
  36. package/dist/rest/headers.d.ts +31 -0
  37. package/dist/rest/identity.d.ts +31 -0
  38. package/dist/rest/index.d.ts +97 -6
  39. package/dist/rest/index.js +1355 -220
  40. package/dist/rest/index.js.map +16 -13
  41. package/dist/rest/limiter.d.ts +75 -10
  42. package/dist/rest/redis.d.ts +103 -22
  43. package/dist/rest/scheduler.d.ts +13 -0
  44. package/dist/rest/store.d.ts +135 -12
  45. package/dist/rest/telemetry.d.ts +151 -0
  46. package/dist/rest/webhook.d.ts +18 -6
  47. package/dist/sharding/bus.d.ts +4 -2
  48. package/dist/sharding/cluster.d.ts +29 -1
  49. package/dist/sharding/health.d.ts +1 -1
  50. package/dist/sharding/host.d.ts +13 -2
  51. package/dist/sharding/identify.d.ts +2 -0
  52. package/dist/sharding/index.d.ts +8 -0
  53. package/dist/sharding/index.js +579 -65
  54. package/dist/sharding/index.js.map +17 -15
  55. package/dist/sharding/leader.d.ts +34 -0
  56. package/dist/sharding/remote.d.ts +36 -2
  57. package/dist/sharding/supervisor.d.ts +1 -1
  58. package/dist/sharding/thread.d.ts +30 -0
  59. package/dist/sharding/transport.d.ts +6 -5
  60. package/dist/sharding/worker.d.ts +11 -1
  61. package/dist/structures/base.d.ts +16 -5
  62. package/dist/structures/index.d.ts +1 -1
  63. package/dist/structures/index.js +57 -91
  64. package/dist/structures/index.js.map +10 -18
  65. package/dist/structures/options.d.ts +3 -2
  66. package/dist/structures/permissions.d.ts +409 -0
  67. package/dist/structures/resources.d.ts +4 -1
  68. package/dist/types/gateway.d.ts +4 -0
  69. package/dist/types/index.d.ts +14 -4
  70. package/dist/types/index.js.map +3 -3
  71. package/dist/utils/args.d.ts +3 -1
  72. package/dist/utils/index.d.ts +6 -1
  73. package/dist/utils/index.js +17 -10
  74. package/dist/utils/index.js.map +4 -4
  75. package/dist/voice/index.d.ts +7 -1
  76. package/dist/voice/index.js +33 -10
  77. package/dist/voice/index.js.map +3 -3
  78. package/dist/ws/index.d.ts +2 -0
  79. package/dist/ws/index.js +32 -4
  80. package/dist/ws/index.js.map +5 -5
  81. package/package.json +21 -17
@@ -223,3 +223,4 @@ export declare class Collection<K, V> extends Map<K, V> {
223
223
  }
224
224
  export { Cache } from "./cache.js";
225
225
  export type { CacheOptions } from "./cache.js";
226
+ export { RedisCollection, type RedisCollectionOptions, type RedisCommandClient, type RedisSerializer, } from "./redis.js";
@@ -56,6 +56,260 @@ class Cache {
56
56
  return [...this.#entries.entries()];
57
57
  }
58
58
  }
59
+ // packages/collection/src/redis.ts
60
+ var PRELUDE = `
61
+ local exp, lru, clock, ep = KEYS[1], KEYS[2], KEYS[3], ARGV[1]
62
+ local t = redis.call('TIME')
63
+ local now = tonumber(t[1]) * 1000 + math.floor(tonumber(t[2]) / 1000)
64
+ local out = {}
65
+ local function drop(m, reason)
66
+ local v = redis.call('GET', ep .. m)
67
+ redis.call('DEL', ep .. m)
68
+ redis.call('ZREM', exp, m)
69
+ redis.call('ZREM', lru, m)
70
+ if reason then
71
+ table.insert(out, m)
72
+ table.insert(out, v or false)
73
+ table.insert(out, reason)
74
+ end
75
+ end
76
+ local gone = redis.call('ZRANGEBYSCORE', exp, '-inf', now, 'LIMIT', 0, 1000)
77
+ for _, m in ipairs(gone) do drop(m, 'expired') end
78
+ local function touch(m) redis.call('ZADD', lru, redis.call('INCR', clock), m) end
79
+ `;
80
+ var SET_SCRIPT = `${PRELUDE}
81
+ local m, payload, ttl, max, mode = ARGV[2], ARGV[3], tonumber(ARGV[4]), tonumber(ARGV[5]), ARGV[6]
82
+ if mode == 'nx' then
83
+ local cur = redis.call('GET', ep .. m)
84
+ if cur then
85
+ touch(m)
86
+ table.insert(out, 1, cur)
87
+ return out
88
+ end
89
+ end
90
+ local env = ttl .. ':' .. payload
91
+ if ttl > 0 then
92
+ -- The key outlives its logical expiry by a grace second, so the prune
93
+ -- that reports the expiry can still hand the value to onEvict.
94
+ redis.call('SET', ep .. m, env, 'PX', ttl + 1000)
95
+ redis.call('ZADD', exp, now + ttl, m)
96
+ else
97
+ redis.call('SET', ep .. m, env)
98
+ redis.call('ZREM', exp, m)
99
+ end
100
+ touch(m)
101
+ if max > 0 then
102
+ local n = redis.call('ZCARD', lru)
103
+ while n > max do
104
+ local popped = redis.call('ZPOPMIN', lru)
105
+ local victim = popped[1]
106
+ if victim == nil then break end
107
+ if victim ~= m then drop(victim, 'evicted') end
108
+ n = n - 1
109
+ end
110
+ end
111
+ table.insert(out, 1, false)
112
+ return out
113
+ `;
114
+ var GET_SCRIPT = `${PRELUDE}
115
+ local m, slide, mark = ARGV[2], ARGV[3], ARGV[4]
116
+ local env = redis.call('GET', ep .. m)
117
+ if not env then
118
+ redis.call('ZREM', exp, m)
119
+ redis.call('ZREM', lru, m)
120
+ table.insert(out, 1, false)
121
+ return out
122
+ end
123
+ if mark == '1' then touch(m) end
124
+ if slide == '1' then
125
+ local ttl = tonumber(string.match(env, '^(%d+):'))
126
+ if ttl and ttl > 0 then
127
+ redis.call('PEXPIRE', ep .. m, ttl + 1000)
128
+ redis.call('ZADD', exp, now + ttl, m)
129
+ end
130
+ end
131
+ table.insert(out, 1, env)
132
+ return out
133
+ `;
134
+ var DELETE_SCRIPT = `${PRELUDE}
135
+ local m = ARGV[2]
136
+ local existed = redis.call('EXISTS', ep .. m)
137
+ drop(m, nil)
138
+ table.insert(out, 1, existed)
139
+ return out
140
+ `;
141
+ var LIST_SCRIPT = `${PRELUDE}
142
+ local what = ARGV[2]
143
+ if what == 'clear' then
144
+ local n = 0
145
+ repeat
146
+ local batch = redis.call('ZRANGE', lru, 0, 999)
147
+ for _, m in ipairs(batch) do drop(m, nil) end
148
+ n = n + #batch
149
+ until #batch == 0
150
+ redis.call('DEL', exp, lru, clock)
151
+ return {n}
152
+ end
153
+ local result = what == 'size' and redis.call('ZCARD', lru) or redis.call('ZRANGE', lru, 0, -1)
154
+ return {result, unpack(out)}
155
+ `;
156
+ var EXPIRY_GRACE_MS = 1000;
157
+ var JSON_SERIALIZER = {
158
+ serialize: (value) => JSON.stringify(value),
159
+ deserialize: (raw) => JSON.parse(raw)
160
+ };
161
+
162
+ class RedisCollection {
163
+ #redis;
164
+ #keys;
165
+ #ep;
166
+ #ttl;
167
+ #slide;
168
+ #maxSize;
169
+ #serializer;
170
+ #onEvict;
171
+ #stats = {
172
+ hits: 0,
173
+ misses: 0,
174
+ expired: 0,
175
+ evicted: 0
176
+ };
177
+ name;
178
+ constructor(options) {
179
+ if (typeof options.name !== "string" || !/^[\w.:-]{1,100}$/.test(options.name))
180
+ throw new TypeError("name must be 1-100 letters, digits, '_', '.', ':' or '-'.");
181
+ checkTTL(options.ttl);
182
+ if (options.maxSize !== undefined && !(Number.isInteger(options.maxSize) && options.maxSize > 0))
183
+ throw new RangeError("maxSize must be a positive integer.");
184
+ this.#redis = options.client;
185
+ this.name = options.name;
186
+ const base = `${options.prefix ?? "lunibee:collection:"}v1:{${options.name}}:`;
187
+ this.#keys = [`${base}exp`, `${base}lru`, `${base}clock`];
188
+ this.#ep = `${base}e:`;
189
+ this.#ttl = options.ttl ?? 0;
190
+ this.#slide = options.slide ?? true;
191
+ this.#maxSize = options.maxSize ?? 0;
192
+ this.#serializer = options.serializer ?? JSON_SERIALIZER;
193
+ this.#onEvict = options.onEvict;
194
+ }
195
+ get stats() {
196
+ return { ...this.#stats };
197
+ }
198
+ async#run(script, ...argv) {
199
+ const reply = await this.#redis.send("EVAL", [
200
+ script,
201
+ "3",
202
+ ...this.#keys,
203
+ this.#ep,
204
+ ...argv
205
+ ]);
206
+ if (!Array.isArray(reply))
207
+ throw new Error("Unexpected reply from a RedisCollection script.");
208
+ return reply;
209
+ }
210
+ #settle(reply, skip) {
211
+ for (let i = skip;i + 2 < reply.length + 0; i += 3) {
212
+ const key = String(reply[i]);
213
+ const raw = reply[i + 1];
214
+ const reason = reply[i + 2];
215
+ if (reason === "expired")
216
+ this.#stats.expired++;
217
+ else
218
+ this.#stats.evicted++;
219
+ if (!this.#onEvict)
220
+ continue;
221
+ let value;
222
+ try {
223
+ value = typeof raw === "string" ? this.#decode(raw) : undefined;
224
+ } catch {
225
+ value = undefined;
226
+ }
227
+ try {
228
+ this.#onEvict(key, value, reason);
229
+ } catch {}
230
+ }
231
+ return reply[0];
232
+ }
233
+ #decode(envelope) {
234
+ const colon = envelope.indexOf(":");
235
+ return this.#serializer.deserialize(envelope.slice(colon + 1));
236
+ }
237
+ async get(key) {
238
+ const raw = this.#settle(await this.#run(GET_SCRIPT, String(key), this.#slide ? "1" : "0", "1"), 1);
239
+ if (typeof raw !== "string") {
240
+ this.#stats.misses++;
241
+ return;
242
+ }
243
+ this.#stats.hits++;
244
+ return this.#decode(raw);
245
+ }
246
+ async peek(key) {
247
+ const raw = this.#settle(await this.#run(GET_SCRIPT, String(key), "0", "0"), 1);
248
+ return typeof raw === "string" ? this.#decode(raw) : undefined;
249
+ }
250
+ async has(key) {
251
+ return await this.peek(key) !== undefined;
252
+ }
253
+ async set(key, value, ttl) {
254
+ checkTTL(ttl, true);
255
+ this.#settle(await this.#run(SET_SCRIPT, String(key), this.#serializer.serialize(value), String(Math.ceil(ttl ?? this.#ttl)), String(this.#maxSize), "set"), 1);
256
+ return this;
257
+ }
258
+ setWithoutTTL(key, value) {
259
+ return this.set(key, value, 0);
260
+ }
261
+ async ensure(key, factory, ttl) {
262
+ const existing = await this.get(key);
263
+ if (existing !== undefined)
264
+ return existing;
265
+ checkTTL(ttl, true);
266
+ const value = await factory(String(key));
267
+ const raw = this.#settle(await this.#run(SET_SCRIPT, String(key), this.#serializer.serialize(value), String(Math.ceil(ttl ?? this.#ttl)), String(this.#maxSize), "nx"), 1);
268
+ return typeof raw === "string" ? this.#decode(raw) : value;
269
+ }
270
+ async delete(key) {
271
+ const reply = await this.#run(DELETE_SCRIPT, String(key));
272
+ return Number(this.#settle(reply, 1)) === 1;
273
+ }
274
+ async clear() {
275
+ const reply = await this.#run(LIST_SCRIPT, "clear");
276
+ return Number(reply[0]);
277
+ }
278
+ async size() {
279
+ return Number(this.#settle(await this.#run(LIST_SCRIPT, "size"), 1));
280
+ }
281
+ async keys() {
282
+ return this.#settle(await this.#run(LIST_SCRIPT, "keys"), 1).map(String);
283
+ }
284
+ async entries() {
285
+ const keys = await this.keys();
286
+ if (keys.length === 0)
287
+ return [];
288
+ const out = [];
289
+ for (let i = 0;i < keys.length; i += 1000) {
290
+ const batch = keys.slice(i, i + 1000);
291
+ const raws = await this.#redis.send("MGET", batch.map((k) => this.#ep + k));
292
+ raws.forEach((raw, j) => {
293
+ if (typeof raw === "string")
294
+ out.push([batch[j], this.#decode(raw)]);
295
+ });
296
+ }
297
+ return out;
298
+ }
299
+ async values() {
300
+ return (await this.entries()).map(([, value]) => value);
301
+ }
302
+ async ttlRemaining(key) {
303
+ const ms = Number(await this.#redis.send("PTTL", [this.#ep + String(key)]));
304
+ return ms >= 0 ? Math.max(0, ms - EXPIRY_GRACE_MS) : undefined;
305
+ }
306
+ }
307
+ function checkTTL(ttl, allowZero = false) {
308
+ if (ttl === undefined)
309
+ return;
310
+ if (!Number.isFinite(ttl) || ttl < 0 || !allowZero && ttl === 0)
311
+ throw new RangeError(allowZero ? "ttl must be 0 or a positive number." : "ttl must be a positive number.");
312
+ }
59
313
 
60
314
  // packages/collection/src/index.ts
61
315
  function newPolicy(options = {}) {
@@ -114,21 +368,35 @@ class Collection extends Map {
114
368
  this.set(key, value);
115
369
  }
116
370
  set(key, value, ttl) {
117
- if (ttl === undefined && this.#policy === undefined)
118
- return super.set(key, value);
119
- assertTTL(ttl);
120
- let window = ttl ?? this.#policy?.ttl;
121
- const jitter = this.#policy?.jitter ?? 0;
122
- if (window !== undefined && jitter > 0)
123
- window = Math.max(1, window * (1 - jitter * Math.random()));
124
- if (window !== undefined)
125
- this.#policy ??= newPolicy();
126
- if (!this.#policy)
371
+ let policy = this.#policy;
372
+ if (ttl === undefined && policy === undefined)
127
373
  return super.set(key, value);
128
- const before = super.size;
374
+ if (ttl !== undefined)
375
+ assertTTL(ttl);
376
+ let window = ttl ?? policy?.ttl;
377
+ if (window !== undefined && policy !== undefined && policy.jitter > 0)
378
+ window = Math.max(1, window * (1 - policy.jitter * Math.random()));
379
+ if (policy === undefined) {
380
+ if (window === undefined)
381
+ return super.set(key, value);
382
+ policy = this.#policy = newPolicy();
383
+ }
384
+ const entry = policy.entries.get(key);
129
385
  super.set(key, value);
130
- this.#track(key, value, window, super.size !== before);
131
- this.#enforceCap();
386
+ if (entry !== undefined && window !== undefined && entry.window !== 0) {
387
+ const deadline = Date.now() + window;
388
+ if (deadline >= entry.filed) {
389
+ entry.value = value;
390
+ entry.deadline = deadline;
391
+ entry.window = window;
392
+ if (entry.inLru)
393
+ this.#promote(policy, entry);
394
+ return this;
395
+ }
396
+ }
397
+ this.#track(key, value, window, entry);
398
+ if (policy.maxSize !== undefined && policy.lruSize > policy.maxSize)
399
+ this.#enforceCap();
132
400
  return this;
133
401
  }
134
402
  setWithoutTTL(key, value) {
@@ -284,10 +552,10 @@ class Collection extends Map {
284
552
  this.#unlink(policy, entry);
285
553
  policy.entries.delete(key);
286
554
  }
287
- #track(key, value, window, isNew) {
555
+ #track(key, value, window, existing) {
288
556
  const policy = this.#policy;
289
557
  const lru = policy.maxSize !== undefined;
290
- let entry = isNew ? undefined : policy.entries.get(key);
558
+ let entry = existing;
291
559
  if (entry)
292
560
  entry.value = value;
293
561
  if (window === undefined) {
@@ -419,11 +687,20 @@ class Collection extends Map {
419
687
  while (policy.lruSize > max) {
420
688
  const oldest = policy.oldest;
421
689
  const value = policy.onEvict ? super.get(oldest.key) : undefined;
422
- this.#unlink(policy, oldest);
690
+ const next = oldest.newer;
691
+ policy.oldest = next;
692
+ if (next)
693
+ next.older = undefined;
694
+ else
695
+ policy.newest = undefined;
696
+ oldest.newer = undefined;
697
+ oldest.inLru = false;
698
+ policy.lruSize--;
423
699
  policy.entries.delete(oldest.key);
424
700
  super.delete(oldest.key);
425
701
  policy.evicted++;
426
- this.#notify(oldest.key, value, "evicted");
702
+ if (policy.onEvict)
703
+ this.#notify(oldest.key, value, "evicted");
427
704
  }
428
705
  }
429
706
  #nextDeadline() {
@@ -838,7 +1115,8 @@ class Collection extends Map {
838
1115
  }
839
1116
  export {
840
1117
  Cache,
841
- Collection
1118
+ Collection,
1119
+ RedisCollection
842
1120
  };
843
1121
 
844
- //# debugId=44902D8F098C340964756E2164756E21
1122
+ //# debugId=8859F4CE73F8594764756E2164756E21