lunibee 0.3.1 → 0.3.2
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/dist/builders/attachment.d.ts +1 -0
- package/dist/builders/clone.d.ts +10 -0
- package/dist/builders/commands.d.ts +1 -1
- package/dist/builders/components.d.ts +24 -5
- package/dist/builders/index.js +64 -17
- package/dist/builders/index.js.map +10 -9
- package/dist/collection/index.d.ts +1 -0
- package/dist/collection/index.js +297 -19
- package/dist/collection/index.js.map +5 -4
- package/dist/collection/redis.d.ts +98 -0
- package/dist/core/collector.d.ts +8 -0
- package/dist/core/events.d.ts +1 -0
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.js +6213 -4716
- package/dist/core/index.js.map +46 -39
- package/dist/core/permissions.d.ts +3 -402
- package/dist/core/redis-cache.d.ts +85 -0
- package/dist/formatters/index.d.ts +5 -1
- package/dist/formatters/index.js +7 -3
- package/dist/formatters/index.js.map +3 -3
- package/dist/handlers/index.js +11 -2
- package/dist/handlers/index.js.map +3 -3
- package/dist/index.js +8272 -6085
- package/dist/index.js.map +64 -58
- package/dist/managers/application.d.ts +10 -6
- package/dist/managers/base.d.ts +4 -1
- package/dist/managers/guild.d.ts +3 -1
- package/dist/managers/index.d.ts +6 -1
- package/dist/managers/index.js +365 -103
- package/dist/managers/index.js.map +19 -22
- package/dist/managers/member.d.ts +3 -1
- package/dist/managers/message.d.ts +13 -4
- package/dist/managers/thread.d.ts +3 -3
- package/dist/rest/decoder.d.ts +2 -0
- package/dist/rest/errors.d.ts +5 -2
- package/dist/rest/headers.d.ts +31 -0
- package/dist/rest/identity.d.ts +31 -0
- package/dist/rest/index.d.ts +97 -6
- package/dist/rest/index.js +1350 -220
- package/dist/rest/index.js.map +16 -13
- package/dist/rest/limiter.d.ts +75 -10
- package/dist/rest/redis.d.ts +103 -22
- package/dist/rest/scheduler.d.ts +13 -0
- package/dist/rest/store.d.ts +135 -12
- package/dist/rest/telemetry.d.ts +151 -0
- package/dist/rest/webhook.d.ts +18 -6
- package/dist/sharding/bus.d.ts +4 -2
- package/dist/sharding/cluster.d.ts +1 -1
- package/dist/sharding/health.d.ts +1 -1
- package/dist/sharding/host.d.ts +6 -0
- package/dist/sharding/identify.d.ts +2 -0
- package/dist/sharding/index.d.ts +6 -0
- package/dist/sharding/index.js +205 -39
- package/dist/sharding/index.js.map +14 -14
- package/dist/sharding/remote.d.ts +18 -2
- package/dist/sharding/supervisor.d.ts +1 -1
- package/dist/sharding/transport.d.ts +6 -5
- package/dist/sharding/worker.d.ts +11 -1
- package/dist/structures/base.d.ts +16 -5
- package/dist/structures/index.d.ts +1 -1
- package/dist/structures/index.js +57 -91
- package/dist/structures/index.js.map +10 -18
- package/dist/structures/options.d.ts +3 -2
- package/dist/structures/permissions.d.ts +409 -0
- package/dist/structures/resources.d.ts +4 -1
- package/dist/types/gateway.d.ts +4 -0
- package/dist/types/index.d.ts +14 -4
- package/dist/types/index.js.map +3 -3
- package/dist/utils/args.d.ts +3 -1
- package/dist/utils/index.d.ts +6 -1
- package/dist/utils/index.js +17 -10
- package/dist/utils/index.js.map +4 -4
- package/dist/voice/index.d.ts +7 -1
- package/dist/voice/index.js +33 -10
- package/dist/voice/index.js.map +3 -3
- package/dist/ws/index.d.ts +2 -0
- package/dist/ws/index.js +32 -4
- package/dist/ws/index.js.map +5 -5
- package/package.json +19 -16
|
@@ -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";
|
package/dist/collection/index.js
CHANGED
|
@@ -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
|
-
|
|
118
|
-
|
|
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
|
-
|
|
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
|
-
|
|
131
|
-
|
|
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,
|
|
555
|
+
#track(key, value, window, existing) {
|
|
288
556
|
const policy = this.#policy;
|
|
289
557
|
const lru = policy.maxSize !== undefined;
|
|
290
|
-
let entry =
|
|
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
|
-
|
|
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
|
-
|
|
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=
|
|
1122
|
+
//# debugId=8859F4CE73F8594764756E2164756E21
|