opencode-collaboration 0.8.0 → 0.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 +2 -1
- package/README.zh-CN.md +2 -1
- package/dist/commands.js +2 -103
- package/dist/config.d.ts +4 -0
- package/dist/config.js +2 -52
- package/dist/delivery.d.ts +19 -0
- package/dist/delivery.js +2 -241
- package/dist/feedback.js +2 -40
- package/dist/format.js +2 -107
- package/dist/gating.js +2 -16
- package/dist/index.js +2 -461
- package/dist/listener.js +2 -335
- package/dist/outbox.js +2 -110
- package/dist/permissions.js +2 -194
- package/dist/queue.js +2 -824
- package/dist/registry.js +2 -308
- package/dist/sanitize.js +2 -38
- package/dist/scope.js +2 -23
- package/dist/sender.js +2 -139
- package/dist/session-runtime.js +2 -434
- package/dist/session-tracker.js +2 -39
- package/dist/stall-detector.d.ts +73 -0
- package/dist/stall-detector.js +2 -0
- package/dist/title-suffix.js +2 -23
- package/dist/tools/peers-tools.js +2 -182
- package/dist/transport.js +2 -46
- package/dist/types.d.ts +7 -0
- package/dist/types.js +2 -1
- package/package.json +2 -2
package/dist/queue.js
CHANGED
|
@@ -1,824 +1,2 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
*/
|
|
4
|
-
import { chmodSync, closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, readdirSync, renameSync, statSync, unlinkSync, writeSync, } from "node:fs";
|
|
5
|
-
import { createHash, randomBytes } from "node:crypto";
|
|
6
|
-
import { dirname, join, resolve } from "node:path";
|
|
7
|
-
const COMPLETED_DEDUPE_RETENTION_MS = 86_400_000;
|
|
8
|
-
const LOCK_STALE_MS = 30_000;
|
|
9
|
-
const LOCK_WAIT_MS = 5_000;
|
|
10
|
-
const LOCK_POLL_MS = 10;
|
|
11
|
-
export function stableSpoolEndpointId(directory) {
|
|
12
|
-
const digest = createHash("sha256").update(`workspace-v1\0${resolve(directory)}`).digest("hex");
|
|
13
|
-
return `workspace-${digest.slice(0, 24)}`;
|
|
14
|
-
}
|
|
15
|
-
export function stableSessionEndpointId(sessionId) {
|
|
16
|
-
const digest = createHash("sha256").update(`session-v1\0${sessionId}`).digest("hex");
|
|
17
|
-
return `session-${digest.slice(0, 24)}`;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* True when the session's durable spool holds any records — undelivered
|
|
21
|
-
* (queued/held/inflight) or delivered (done, retained 24h for dedupe).
|
|
22
|
-
* Startup adopts exactly these sessions (plus snapshot-busy ones): pending
|
|
23
|
-
* work must resume, and done records must load or a post-restart retry would
|
|
24
|
-
* deliver a duplicate. Everything else stays unpublished until real activity.
|
|
25
|
-
*/
|
|
26
|
-
export function hasSpoolRecords(config, sessionId) {
|
|
27
|
-
const spoolDir = join(config.spoolDir, stableSessionEndpointId(sessionId));
|
|
28
|
-
for (const state of ["queued", "held", "inflight", "done"]) {
|
|
29
|
-
try {
|
|
30
|
-
if (readdirSync(join(spoolDir, state)).some((file) => file.endsWith(".json")))
|
|
31
|
-
return true;
|
|
32
|
-
}
|
|
33
|
-
catch {
|
|
34
|
-
// missing state dir — no records of this state
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
export function createSessionMessageQueue(opts) {
|
|
40
|
-
return MessageQueue({
|
|
41
|
-
endpointId: stableSessionEndpointId(opts.sessionId),
|
|
42
|
-
maxQueue: opts.config.maxQueue,
|
|
43
|
-
maxHeld: opts.config.maxHeld,
|
|
44
|
-
heldExpiryMs: opts.config.heldExpiryMs,
|
|
45
|
-
inboxFile: opts.config.inboxFile,
|
|
46
|
-
logger: opts.logger,
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
export function createProcessMessageQueue(opts) {
|
|
50
|
-
return MessageQueue({
|
|
51
|
-
endpointId: stableSpoolEndpointId(opts.directory),
|
|
52
|
-
maxQueue: opts.config.maxQueue,
|
|
53
|
-
maxHeld: opts.config.maxHeld,
|
|
54
|
-
heldExpiryMs: opts.config.heldExpiryMs,
|
|
55
|
-
inboxFile: opts.config.inboxFile,
|
|
56
|
-
logger: opts.logger,
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
function migrationStateFiles(spoolDir, state) {
|
|
60
|
-
try {
|
|
61
|
-
return readdirSync(join(spoolDir, state)).filter((file) => file.endsWith(".json")).sort();
|
|
62
|
-
}
|
|
63
|
-
catch (err) {
|
|
64
|
-
if (err.code === "ENOENT")
|
|
65
|
-
return [];
|
|
66
|
-
throw err;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
function syncMigrationDirectory(directory) {
|
|
70
|
-
if (process.platform === "win32")
|
|
71
|
-
return;
|
|
72
|
-
const fd = openSync(directory, "r");
|
|
73
|
-
try {
|
|
74
|
-
fsyncSync(fd);
|
|
75
|
-
}
|
|
76
|
-
finally {
|
|
77
|
-
closeSync(fd);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
function ensureMigrationDirectory(directory) {
|
|
81
|
-
mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
82
|
-
chmodSync(directory, 0o700);
|
|
83
|
-
}
|
|
84
|
-
function persistMigrationRecord(target, record) {
|
|
85
|
-
const directory = dirname(target);
|
|
86
|
-
ensureMigrationDirectory(directory);
|
|
87
|
-
const temporary = join(directory, `.${process.pid}.${randomBytes(8).toString("hex")}.tmp`);
|
|
88
|
-
const fd = openSync(temporary, "wx", 0o600);
|
|
89
|
-
try {
|
|
90
|
-
writeSync(fd, JSON.stringify(record));
|
|
91
|
-
fsyncSync(fd);
|
|
92
|
-
}
|
|
93
|
-
finally {
|
|
94
|
-
closeSync(fd);
|
|
95
|
-
}
|
|
96
|
-
chmodSync(temporary, 0o600);
|
|
97
|
-
renameSync(temporary, target);
|
|
98
|
-
syncMigrationDirectory(directory);
|
|
99
|
-
}
|
|
100
|
-
function readSequence(path) {
|
|
101
|
-
try {
|
|
102
|
-
const record = JSON.parse(readFileSync(path, "utf8"));
|
|
103
|
-
return typeof record.value === "number" && Number.isSafeInteger(record.value) ? record.value : null;
|
|
104
|
-
}
|
|
105
|
-
catch (err) {
|
|
106
|
-
if (err.code === "ENOENT")
|
|
107
|
-
return null;
|
|
108
|
-
throw err;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
function sameFileContents(first, second) {
|
|
112
|
-
try {
|
|
113
|
-
return readFileSync(first, "utf8") === readFileSync(second, "utf8");
|
|
114
|
-
}
|
|
115
|
-
catch {
|
|
116
|
-
return false;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Move Task 1's directory-scoped spool into Task 2's compatibility session.
|
|
121
|
-
* Individual renames are atomic and the operation is restart-safe. Both
|
|
122
|
-
* endpoint locks are acquired in endpoint-ID order so concurrent recovery
|
|
123
|
-
* cannot deadlock or race normal queue state transitions.
|
|
124
|
-
*/
|
|
125
|
-
export async function migrateWorkspaceSpool(opts) {
|
|
126
|
-
const sourceEndpointId = stableSpoolEndpointId(opts.directory);
|
|
127
|
-
const targetEndpointId = stableSessionEndpointId(opts.targetSessionId);
|
|
128
|
-
const result = {
|
|
129
|
-
migrated: 0,
|
|
130
|
-
deduplicated: 0,
|
|
131
|
-
quarantined: 0,
|
|
132
|
-
sourceEndpointId,
|
|
133
|
-
targetEndpointId,
|
|
134
|
-
};
|
|
135
|
-
if (sourceEndpointId === targetEndpointId)
|
|
136
|
-
return result;
|
|
137
|
-
const sourceDir = join(dirname(opts.config.inboxFile), "spool", sourceEndpointId);
|
|
138
|
-
const targetDir = join(dirname(opts.config.inboxFile), "spool", targetEndpointId);
|
|
139
|
-
if (!existsSync(sourceDir))
|
|
140
|
-
return result;
|
|
141
|
-
const sourceHasState = ['queued', 'held', 'inflight', 'done']
|
|
142
|
-
.some((state) => migrationStateFiles(sourceDir, state).length > 0);
|
|
143
|
-
if (!sourceHasState && !existsSync(join(sourceDir, "sequence")))
|
|
144
|
-
return result;
|
|
145
|
-
const queueOptions = {
|
|
146
|
-
maxQueue: opts.config.maxQueue,
|
|
147
|
-
maxHeld: opts.config.maxHeld,
|
|
148
|
-
heldExpiryMs: opts.config.heldExpiryMs,
|
|
149
|
-
inboxFile: opts.config.inboxFile,
|
|
150
|
-
logger: opts.logger,
|
|
151
|
-
};
|
|
152
|
-
const queues = new Map([
|
|
153
|
-
[sourceEndpointId, MessageQueue({ ...queueOptions, endpointId: sourceEndpointId })],
|
|
154
|
-
[targetEndpointId, MessageQueue({ ...queueOptions, endpointId: targetEndpointId })],
|
|
155
|
-
]);
|
|
156
|
-
const [firstId, secondId] = [sourceEndpointId, targetEndpointId].sort();
|
|
157
|
-
const collisions = [];
|
|
158
|
-
queues.get(firstId).withExclusiveLock(() => {
|
|
159
|
-
queues.get(secondId).withExclusiveLock(() => {
|
|
160
|
-
for (const state of ["queued", "held", "inflight", "done"]) {
|
|
161
|
-
for (const file of migrationStateFiles(sourceDir, state)) {
|
|
162
|
-
const source = join(sourceDir, state, file);
|
|
163
|
-
const targetLocations = ["queued", "held", "inflight", "done"]
|
|
164
|
-
.map((targetState) => join(targetDir, targetState, file))
|
|
165
|
-
.filter((path) => existsSync(path));
|
|
166
|
-
if (targetLocations.length === 0) {
|
|
167
|
-
const target = join(targetDir, state, file);
|
|
168
|
-
renameSync(source, target);
|
|
169
|
-
syncMigrationDirectory(join(sourceDir, state));
|
|
170
|
-
syncMigrationDirectory(join(targetDir, state));
|
|
171
|
-
result.migrated++;
|
|
172
|
-
continue;
|
|
173
|
-
}
|
|
174
|
-
if (targetLocations.length === 1 && targetLocations[0] === join(targetDir, state, file) && sameFileContents(source, targetLocations[0])) {
|
|
175
|
-
unlinkSync(source);
|
|
176
|
-
syncMigrationDirectory(join(sourceDir, state));
|
|
177
|
-
result.deduplicated++;
|
|
178
|
-
continue;
|
|
179
|
-
}
|
|
180
|
-
const base = join(targetDir, "migration-quarantine", sourceEndpointId, state);
|
|
181
|
-
ensureMigrationDirectory(base);
|
|
182
|
-
let quarantine = join(base, file);
|
|
183
|
-
if (existsSync(quarantine) && !sameFileContents(source, quarantine)) {
|
|
184
|
-
const digest = createHash("sha256").update(readFileSync(source)).digest("hex").slice(0, 16);
|
|
185
|
-
quarantine = join(base, `${file.slice(0, -5)}.${digest}.json`);
|
|
186
|
-
}
|
|
187
|
-
if (existsSync(quarantine) && sameFileContents(source, quarantine)) {
|
|
188
|
-
unlinkSync(source);
|
|
189
|
-
}
|
|
190
|
-
else {
|
|
191
|
-
renameSync(source, quarantine);
|
|
192
|
-
syncMigrationDirectory(base);
|
|
193
|
-
}
|
|
194
|
-
syncMigrationDirectory(join(sourceDir, state));
|
|
195
|
-
result.quarantined++;
|
|
196
|
-
collisions.push({ state, file, quarantine });
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
const sourceSequencePath = join(sourceDir, "sequence");
|
|
200
|
-
const targetSequencePath = join(targetDir, "sequence");
|
|
201
|
-
const sourceSequence = readSequence(sourceSequencePath);
|
|
202
|
-
const targetSequence = readSequence(targetSequencePath);
|
|
203
|
-
if (sourceSequence !== null) {
|
|
204
|
-
const mergedSequence = Math.max(sourceSequence, targetSequence ?? 0);
|
|
205
|
-
if (targetSequence !== mergedSequence)
|
|
206
|
-
persistMigrationRecord(targetSequencePath, { value: mergedSequence });
|
|
207
|
-
unlinkSync(sourceSequencePath);
|
|
208
|
-
syncMigrationDirectory(sourceDir);
|
|
209
|
-
}
|
|
210
|
-
persistMigrationRecord(join(targetDir, ".migrations", `${sourceEndpointId}.json`), {
|
|
211
|
-
version: 1,
|
|
212
|
-
sourceEndpointId,
|
|
213
|
-
targetEndpointId,
|
|
214
|
-
completedAt: Date.now(),
|
|
215
|
-
});
|
|
216
|
-
});
|
|
217
|
-
});
|
|
218
|
-
for (const collision of collisions) {
|
|
219
|
-
await opts.logger("warn", "workspace spool record quarantined during session migration", {
|
|
220
|
-
sourceEndpointId,
|
|
221
|
-
targetEndpointId,
|
|
222
|
-
state: collision.state,
|
|
223
|
-
file: collision.file,
|
|
224
|
-
quarantine: collision.quarantine,
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
await opts.logger("info", "workspace spool migration completed", { ...result });
|
|
228
|
-
return result;
|
|
229
|
-
}
|
|
230
|
-
export function MessageQueue(opts) {
|
|
231
|
-
let queue = [];
|
|
232
|
-
let held = [];
|
|
233
|
-
const spoolDir = join(dirname(opts.inboxFile), "spool", opts.endpointId ?? "legacy");
|
|
234
|
-
const heldExpiryMs = opts.heldExpiryMs ?? 300_000;
|
|
235
|
-
const debounceMs = opts.debounceMs ?? 1_000;
|
|
236
|
-
const recentContent = new Map();
|
|
237
|
-
const lockTicketsDir = join(spoolDir, ".lock-tickets");
|
|
238
|
-
const sequenceFile = join(spoolDir, "sequence");
|
|
239
|
-
function ensureEndpointDirectories() {
|
|
240
|
-
mkdirSync(spoolDir, { recursive: true, mode: 0o700 });
|
|
241
|
-
chmodSync(spoolDir, 0o700);
|
|
242
|
-
for (const state of ["queued", "held", "inflight", "done"]) {
|
|
243
|
-
const directory = join(spoolDir, state);
|
|
244
|
-
mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
245
|
-
chmodSync(directory, 0o700);
|
|
246
|
-
}
|
|
247
|
-
mkdirSync(lockTicketsDir, { recursive: true, mode: 0o700 });
|
|
248
|
-
chmodSync(lockTicketsDir, 0o700);
|
|
249
|
-
}
|
|
250
|
-
function removeClaim(path) {
|
|
251
|
-
try {
|
|
252
|
-
unlinkSync(path);
|
|
253
|
-
syncDirectory(lockTicketsDir);
|
|
254
|
-
}
|
|
255
|
-
catch (err) {
|
|
256
|
-
if (err.code !== "ENOENT")
|
|
257
|
-
throw err;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
function createClaim(path, record) {
|
|
261
|
-
const fd = openSync(path, "wx", 0o600);
|
|
262
|
-
try {
|
|
263
|
-
writeSync(fd, JSON.stringify(record));
|
|
264
|
-
fsyncSync(fd);
|
|
265
|
-
}
|
|
266
|
-
catch (err) {
|
|
267
|
-
try {
|
|
268
|
-
closeSync(fd);
|
|
269
|
-
}
|
|
270
|
-
finally {
|
|
271
|
-
removeClaim(path);
|
|
272
|
-
}
|
|
273
|
-
throw err;
|
|
274
|
-
}
|
|
275
|
-
try {
|
|
276
|
-
closeSync(fd);
|
|
277
|
-
syncDirectory(lockTicketsDir);
|
|
278
|
-
}
|
|
279
|
-
catch (err) {
|
|
280
|
-
removeClaim(path);
|
|
281
|
-
throw err;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
function claimFiles() {
|
|
285
|
-
return readdirSync(lockTicketsDir).filter((file) => /^choosing-[a-f0-9]{32}\.json$/.test(file) || /^ticket-\d{16}-[a-f0-9]{32}\.json$/.test(file));
|
|
286
|
-
}
|
|
287
|
-
function recoverStaleClaims() {
|
|
288
|
-
for (const file of claimFiles()) {
|
|
289
|
-
const path = join(lockTicketsDir, file);
|
|
290
|
-
try {
|
|
291
|
-
if (Date.now() - statSync(path).mtimeMs > LOCK_STALE_MS)
|
|
292
|
-
removeClaim(path);
|
|
293
|
-
}
|
|
294
|
-
catch (err) {
|
|
295
|
-
if (err.code !== "ENOENT")
|
|
296
|
-
throw err;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
function ticketNumber(file) {
|
|
301
|
-
const match = /^ticket-(\d{16})-[a-f0-9]{32}\.json$/.exec(file);
|
|
302
|
-
return match ? Number(match[1]) : null;
|
|
303
|
-
}
|
|
304
|
-
// Filesystem bakery lock: every doorway/queue entry has a unique path that
|
|
305
|
-
// is never reused, so stale cleanup and release can only unlink the exact
|
|
306
|
-
// claim they observed or created. Choosing entries prevent a late contender
|
|
307
|
-
// from publishing a lower ticket after another contender has entered.
|
|
308
|
-
function acquireLockTicket(deadline) {
|
|
309
|
-
const token = randomBytes(16).toString("hex");
|
|
310
|
-
const choosingPath = join(lockTicketsDir, `choosing-${token}.json`);
|
|
311
|
-
let ticketPath = null;
|
|
312
|
-
createClaim(choosingPath, { kind: "choosing", token, pid: process.pid, createdAt: Date.now() });
|
|
313
|
-
try {
|
|
314
|
-
recoverStaleClaims();
|
|
315
|
-
const highest = claimFiles().reduce((max, file) => Math.max(max, ticketNumber(file) ?? 0), 0);
|
|
316
|
-
if (Date.now() >= deadline)
|
|
317
|
-
throw new Error(`timed out acquiring message spool lock: ${lockTicketsDir}`);
|
|
318
|
-
const ticket = highest + 1;
|
|
319
|
-
ticketPath = join(lockTicketsDir, `ticket-${String(ticket).padStart(16, "0")}-${token}.json`);
|
|
320
|
-
createClaim(ticketPath, { kind: "ticket", ticket, token, pid: process.pid, createdAt: Date.now() });
|
|
321
|
-
}
|
|
322
|
-
finally {
|
|
323
|
-
removeClaim(choosingPath);
|
|
324
|
-
}
|
|
325
|
-
for (;;) {
|
|
326
|
-
recoverStaleClaims();
|
|
327
|
-
if (!existsSync(ticketPath)) {
|
|
328
|
-
throw new Error(`message spool lock claim expired before admission: ${ticketPath}`);
|
|
329
|
-
}
|
|
330
|
-
if (Date.now() >= deadline) {
|
|
331
|
-
removeClaim(ticketPath);
|
|
332
|
-
throw new Error(`timed out acquiring message spool lock: ${lockTicketsDir}`);
|
|
333
|
-
}
|
|
334
|
-
const claims = claimFiles();
|
|
335
|
-
const choosing = claims.some((file) => file.startsWith("choosing-"));
|
|
336
|
-
const tickets = claims
|
|
337
|
-
.flatMap((file) => {
|
|
338
|
-
const ticket = ticketNumber(file);
|
|
339
|
-
return ticket === null ? [] : [{ file, ticket }];
|
|
340
|
-
})
|
|
341
|
-
.sort((a, b) => a.ticket - b.ticket || (a.file < b.file ? -1 : a.file > b.file ? 1 : 0));
|
|
342
|
-
if (!choosing && tickets[0]?.file === ticketPath.slice(lockTicketsDir.length + 1))
|
|
343
|
-
return ticketPath;
|
|
344
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, LOCK_POLL_MS);
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
function withEndpointLock(operation) {
|
|
348
|
-
ensureEndpointDirectories();
|
|
349
|
-
const ticketPath = acquireLockTicket(Date.now() + LOCK_WAIT_MS);
|
|
350
|
-
try {
|
|
351
|
-
return operation();
|
|
352
|
-
}
|
|
353
|
-
finally {
|
|
354
|
-
removeClaim(ticketPath);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
function stateFileCount(state) {
|
|
358
|
-
return stateRecords(state).length;
|
|
359
|
-
}
|
|
360
|
-
function stateRecords(state) {
|
|
361
|
-
const directory = join(spoolDir, state);
|
|
362
|
-
let files = [];
|
|
363
|
-
try {
|
|
364
|
-
files = readdirSync(directory).filter((file) => file.endsWith(".json"));
|
|
365
|
-
}
|
|
366
|
-
catch (err) {
|
|
367
|
-
if (err.code !== "ENOENT") {
|
|
368
|
-
void opts.logger("warn", "failed to read message spool directory", { state, error: String(err) });
|
|
369
|
-
}
|
|
370
|
-
return [];
|
|
371
|
-
}
|
|
372
|
-
const records = [];
|
|
373
|
-
for (const file of files) {
|
|
374
|
-
try {
|
|
375
|
-
const record = JSON.parse(readFileSync(join(directory, file), "utf8"));
|
|
376
|
-
if (record?.version !== 2 ||
|
|
377
|
-
record.state !== state ||
|
|
378
|
-
!record.message?.id ||
|
|
379
|
-
!record.message.from?.instanceId ||
|
|
380
|
-
!Number.isFinite(record.message.sentAt) ||
|
|
381
|
-
(state === "held" && !Number.isFinite(record.message.expiresAt)) ||
|
|
382
|
-
(state === "done" && !record.ack)) {
|
|
383
|
-
throw new Error("invalid spool record");
|
|
384
|
-
}
|
|
385
|
-
records.push(record);
|
|
386
|
-
}
|
|
387
|
-
catch (err) {
|
|
388
|
-
void opts.logger("warn", "skipping malformed message spool record", { state, file, error: String(err) });
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
return records.sort((a, b) => {
|
|
392
|
-
const aOrder = a.sequence ?? a.acceptedAt ?? a.message.sentAt;
|
|
393
|
-
const bOrder = b.sequence ?? b.acceptedAt ?? b.message.sentAt;
|
|
394
|
-
return aOrder - bOrder;
|
|
395
|
-
});
|
|
396
|
-
}
|
|
397
|
-
function nextSequence() {
|
|
398
|
-
let current = 0;
|
|
399
|
-
try {
|
|
400
|
-
const stored = JSON.parse(readFileSync(sequenceFile, "utf8"));
|
|
401
|
-
if (typeof stored.value === "number" && Number.isSafeInteger(stored.value))
|
|
402
|
-
current = stored.value;
|
|
403
|
-
}
|
|
404
|
-
catch {
|
|
405
|
-
// The first accepted record starts the sequence.
|
|
406
|
-
}
|
|
407
|
-
const value = current + 1;
|
|
408
|
-
persistRecord(sequenceFile, { value });
|
|
409
|
-
return value;
|
|
410
|
-
}
|
|
411
|
-
function readRecord(state, message) {
|
|
412
|
-
try {
|
|
413
|
-
const record = JSON.parse(readFileSync(join(spoolDir, state, `${recordName(message)}.json`), "utf8"));
|
|
414
|
-
if (record?.version !== 2 ||
|
|
415
|
-
record.state !== state ||
|
|
416
|
-
record.message?.id !== message.id ||
|
|
417
|
-
record.message.from?.instanceId !== message.from.instanceId ||
|
|
418
|
-
(state === "done" && !record.ack))
|
|
419
|
-
return null;
|
|
420
|
-
return record;
|
|
421
|
-
}
|
|
422
|
-
catch {
|
|
423
|
-
return null;
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
function refreshHeld() {
|
|
427
|
-
held = stateRecords("held").map((record) => record.message);
|
|
428
|
-
}
|
|
429
|
-
function refreshQueue() {
|
|
430
|
-
queue = stateRecords("queued").map((record) => record.message);
|
|
431
|
-
}
|
|
432
|
-
function recordName(msg) {
|
|
433
|
-
return createHash("sha256").update(`${msg.from.instanceId}\0${msg.id}`).digest("hex");
|
|
434
|
-
}
|
|
435
|
-
function queuedFile(msg) {
|
|
436
|
-
return join(spoolDir, "queued", `${recordName(msg)}.json`);
|
|
437
|
-
}
|
|
438
|
-
function inflightFile(msg) {
|
|
439
|
-
return join(spoolDir, "inflight", `${recordName(msg)}.json`);
|
|
440
|
-
}
|
|
441
|
-
function heldFile(msg) {
|
|
442
|
-
return join(spoolDir, "held", `${recordName(msg)}.json`);
|
|
443
|
-
}
|
|
444
|
-
function doneFile(msg) {
|
|
445
|
-
return join(spoolDir, "done", `${recordName(msg)}.json`);
|
|
446
|
-
}
|
|
447
|
-
function existingState(msg) {
|
|
448
|
-
for (const state of ["queued", "held", "inflight", "done"]) {
|
|
449
|
-
if (readRecord(state, msg))
|
|
450
|
-
return state;
|
|
451
|
-
}
|
|
452
|
-
return null;
|
|
453
|
-
}
|
|
454
|
-
function contentKey(msg) {
|
|
455
|
-
return createHash("sha256").update(`${msg.from.instanceId}\0${msg.text}`).digest("hex");
|
|
456
|
-
}
|
|
457
|
-
function locallyDebounced(msg) {
|
|
458
|
-
const seenAt = recentContent.get(contentKey(msg));
|
|
459
|
-
return typeof seenAt === "number" && seenAt > Date.now() - debounceMs;
|
|
460
|
-
}
|
|
461
|
-
function noteContent(msg) {
|
|
462
|
-
recentContent.set(contentKey(msg), Date.now());
|
|
463
|
-
}
|
|
464
|
-
function recentContentRecord(msg) {
|
|
465
|
-
const cutoff = Date.now() - debounceMs;
|
|
466
|
-
for (const state of ["queued", "held", "inflight", "done"]) {
|
|
467
|
-
for (const record of stateRecords(state)) {
|
|
468
|
-
const acceptedAt = record.acceptedAt ?? record.heldAt ?? record.message.sentAt;
|
|
469
|
-
if (acceptedAt > cutoff &&
|
|
470
|
-
record.message.id !== msg.id &&
|
|
471
|
-
record.message.from.instanceId === msg.from.instanceId &&
|
|
472
|
-
record.message.text === msg.text) {
|
|
473
|
-
return record;
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
return null;
|
|
478
|
-
}
|
|
479
|
-
function ensureSpoolDirectory(directory) {
|
|
480
|
-
mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
481
|
-
chmodSync(spoolDir, 0o700);
|
|
482
|
-
chmodSync(directory, 0o700);
|
|
483
|
-
}
|
|
484
|
-
function syncDirectory(directory) {
|
|
485
|
-
if (process.platform === "win32")
|
|
486
|
-
return;
|
|
487
|
-
const dirFd = openSync(directory, "r");
|
|
488
|
-
try {
|
|
489
|
-
fsyncSync(dirFd);
|
|
490
|
-
}
|
|
491
|
-
finally {
|
|
492
|
-
closeSync(dirFd);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
function persistRecord(target, record) {
|
|
496
|
-
const directory = dirname(target);
|
|
497
|
-
ensureSpoolDirectory(directory);
|
|
498
|
-
const temporary = join(directory, `.${process.pid}.${Date.now()}.tmp`);
|
|
499
|
-
const fd = openSync(temporary, "w", 0o600);
|
|
500
|
-
try {
|
|
501
|
-
writeSync(fd, JSON.stringify(record));
|
|
502
|
-
fsyncSync(fd);
|
|
503
|
-
}
|
|
504
|
-
finally {
|
|
505
|
-
closeSync(fd);
|
|
506
|
-
}
|
|
507
|
-
chmodSync(temporary, 0o600);
|
|
508
|
-
renameSync(temporary, target);
|
|
509
|
-
syncDirectory(directory);
|
|
510
|
-
}
|
|
511
|
-
function persistQueued(msg) {
|
|
512
|
-
persistRecord(queuedFile(msg), {
|
|
513
|
-
version: 2,
|
|
514
|
-
state: "queued",
|
|
515
|
-
message: msg,
|
|
516
|
-
acceptedAt: Date.now(),
|
|
517
|
-
sequence: nextSequence(),
|
|
518
|
-
});
|
|
519
|
-
}
|
|
520
|
-
function acknowledgement(message, status) {
|
|
521
|
-
return {
|
|
522
|
-
version: 2,
|
|
523
|
-
messageId: message.id,
|
|
524
|
-
fromEndpointId: message.from.instanceId,
|
|
525
|
-
toEndpointId: opts.endpointId ?? "legacy",
|
|
526
|
-
status,
|
|
527
|
-
acknowledgedAt: Date.now(),
|
|
528
|
-
};
|
|
529
|
-
}
|
|
530
|
-
function finish(message, sourceState, status) {
|
|
531
|
-
const sourceRecord = readRecord(sourceState, message);
|
|
532
|
-
if (!sourceRecord) {
|
|
533
|
-
const prior = readRecord("done", message)?.ack;
|
|
534
|
-
if (prior)
|
|
535
|
-
return prior;
|
|
536
|
-
throw new Error(`missing ${sourceState} spool record for message ${message.id}`);
|
|
537
|
-
}
|
|
538
|
-
const ack = acknowledgement(message, status);
|
|
539
|
-
persistRecord(doneFile(message), {
|
|
540
|
-
...sourceRecord,
|
|
541
|
-
state: "done",
|
|
542
|
-
message,
|
|
543
|
-
ack,
|
|
544
|
-
});
|
|
545
|
-
const source = join(spoolDir, sourceState, `${recordName(message)}.json`);
|
|
546
|
-
unlinkSync(source);
|
|
547
|
-
syncDirectory(dirname(source));
|
|
548
|
-
return ack;
|
|
549
|
-
}
|
|
550
|
-
function persistDuplicateLocked(message, duplicateOf) {
|
|
551
|
-
const ack = acknowledgement(message, "duplicate");
|
|
552
|
-
persistRecord(doneFile(message), {
|
|
553
|
-
version: 2,
|
|
554
|
-
state: "done",
|
|
555
|
-
message,
|
|
556
|
-
ack,
|
|
557
|
-
acceptedAt: Date.now(),
|
|
558
|
-
sequence: nextSequence(),
|
|
559
|
-
duplicateOfMessageId: duplicateOf.message.id,
|
|
560
|
-
});
|
|
561
|
-
return ack;
|
|
562
|
-
}
|
|
563
|
-
function pick(which, limit = Infinity) {
|
|
564
|
-
if (limit <= 0)
|
|
565
|
-
return [];
|
|
566
|
-
if (which === "all") {
|
|
567
|
-
const out = held.slice(0, limit);
|
|
568
|
-
held = held.slice(out.length);
|
|
569
|
-
return out;
|
|
570
|
-
}
|
|
571
|
-
const idx = which - 1;
|
|
572
|
-
if (idx < 0 || idx >= held.length)
|
|
573
|
-
return [];
|
|
574
|
-
return held.splice(idx, 1);
|
|
575
|
-
}
|
|
576
|
-
function expireHeldRecordsLocked() {
|
|
577
|
-
refreshHeld();
|
|
578
|
-
const now = Date.now();
|
|
579
|
-
const expired = held.filter((message) => message.expiresAt <= now);
|
|
580
|
-
held = held.filter((message) => message.expiresAt > now);
|
|
581
|
-
return expired.map((message) => finish(message, "held", "expired"));
|
|
582
|
-
}
|
|
583
|
-
async function expireHeldRecords() {
|
|
584
|
-
return withEndpointLock(expireHeldRecordsLocked);
|
|
585
|
-
}
|
|
586
|
-
const instance = {
|
|
587
|
-
enqueue(msg) {
|
|
588
|
-
return withEndpointLock(() => {
|
|
589
|
-
if (existingState(msg))
|
|
590
|
-
return false;
|
|
591
|
-
const duplicate = recentContentRecord(msg);
|
|
592
|
-
if (duplicate || locallyDebounced(msg)) {
|
|
593
|
-
persistDuplicateLocked(msg, duplicate ?? {
|
|
594
|
-
version: 2,
|
|
595
|
-
state: "queued",
|
|
596
|
-
message: msg,
|
|
597
|
-
});
|
|
598
|
-
return false;
|
|
599
|
-
}
|
|
600
|
-
if (stateFileCount("queued") + stateFileCount("inflight") >= opts.maxQueue)
|
|
601
|
-
return false;
|
|
602
|
-
persistQueued(msg);
|
|
603
|
-
noteContent(msg);
|
|
604
|
-
queue.push(msg);
|
|
605
|
-
return true;
|
|
606
|
-
});
|
|
607
|
-
},
|
|
608
|
-
drain() {
|
|
609
|
-
return withEndpointLock(() => {
|
|
610
|
-
const records = stateRecords("queued");
|
|
611
|
-
const out = records.map((record) => record.message);
|
|
612
|
-
for (const record of records) {
|
|
613
|
-
const message = record.message;
|
|
614
|
-
persistRecord(inflightFile(message), { ...record, state: "inflight", message });
|
|
615
|
-
unlinkSync(queuedFile(message));
|
|
616
|
-
syncDirectory(dirname(queuedFile(message)));
|
|
617
|
-
}
|
|
618
|
-
queue = [];
|
|
619
|
-
return out;
|
|
620
|
-
});
|
|
621
|
-
},
|
|
622
|
-
async complete(messages) {
|
|
623
|
-
return withEndpointLock(() => messages.map((message) => finish(message, "inflight", "delivered")));
|
|
624
|
-
},
|
|
625
|
-
async requeue(messages) {
|
|
626
|
-
withEndpointLock(() => {
|
|
627
|
-
for (const message of messages) {
|
|
628
|
-
const record = readRecord("inflight", message);
|
|
629
|
-
if (!record)
|
|
630
|
-
continue;
|
|
631
|
-
persistRecord(queuedFile(message), { ...record, state: "queued", message });
|
|
632
|
-
unlinkSync(inflightFile(message));
|
|
633
|
-
syncDirectory(dirname(inflightFile(message)));
|
|
634
|
-
}
|
|
635
|
-
refreshQueue();
|
|
636
|
-
});
|
|
637
|
-
},
|
|
638
|
-
duplicateAcknowledgement(msg) {
|
|
639
|
-
const record = readRecord("done", msg);
|
|
640
|
-
return record?.ack?.status === "duplicate" ? record.ack : null;
|
|
641
|
-
},
|
|
642
|
-
existingStatus(msg) {
|
|
643
|
-
switch (existingState(msg)) {
|
|
644
|
-
case "queued":
|
|
645
|
-
case "inflight":
|
|
646
|
-
return "queued";
|
|
647
|
-
case "held":
|
|
648
|
-
return "held";
|
|
649
|
-
case "done": {
|
|
650
|
-
return readRecord("done", msg)?.ack?.status ?? null;
|
|
651
|
-
}
|
|
652
|
-
default:
|
|
653
|
-
return null;
|
|
654
|
-
}
|
|
655
|
-
},
|
|
656
|
-
isDebounced(msg) {
|
|
657
|
-
return withEndpointLock(() => {
|
|
658
|
-
if (existingState(msg))
|
|
659
|
-
return false;
|
|
660
|
-
const duplicate = recentContentRecord(msg);
|
|
661
|
-
if (!duplicate && !locallyDebounced(msg))
|
|
662
|
-
return false;
|
|
663
|
-
persistDuplicateLocked(msg, duplicate ?? { version: 2, state: "queued", message: msg });
|
|
664
|
-
return true;
|
|
665
|
-
});
|
|
666
|
-
},
|
|
667
|
-
async refuse(msg) {
|
|
668
|
-
return withEndpointLock(() => {
|
|
669
|
-
const priorState = existingState(msg);
|
|
670
|
-
if (priorState === "done")
|
|
671
|
-
return readRecord("done", msg).ack;
|
|
672
|
-
if (priorState)
|
|
673
|
-
return acknowledgement(msg, "duplicate");
|
|
674
|
-
const ack = acknowledgement(msg, "refused");
|
|
675
|
-
persistRecord(doneFile(msg), {
|
|
676
|
-
version: 2,
|
|
677
|
-
state: "done",
|
|
678
|
-
message: msg,
|
|
679
|
-
ack,
|
|
680
|
-
acceptedAt: Date.now(),
|
|
681
|
-
sequence: nextSequence(),
|
|
682
|
-
});
|
|
683
|
-
return ack;
|
|
684
|
-
});
|
|
685
|
-
},
|
|
686
|
-
pending() {
|
|
687
|
-
return [...queue];
|
|
688
|
-
},
|
|
689
|
-
size() {
|
|
690
|
-
return queue.length;
|
|
691
|
-
},
|
|
692
|
-
async hold(msg) {
|
|
693
|
-
return withEndpointLock(() => {
|
|
694
|
-
if (existingState(msg))
|
|
695
|
-
return false;
|
|
696
|
-
const duplicate = recentContentRecord(msg);
|
|
697
|
-
if (duplicate || locallyDebounced(msg)) {
|
|
698
|
-
persistDuplicateLocked(msg, duplicate ?? { version: 2, state: "held", message: msg });
|
|
699
|
-
return false;
|
|
700
|
-
}
|
|
701
|
-
if (stateFileCount("held") >= opts.maxHeld)
|
|
702
|
-
return false;
|
|
703
|
-
const heldAt = Date.now();
|
|
704
|
-
const heldMessage = { ...msg, heldAt, expiresAt: heldAt + heldExpiryMs };
|
|
705
|
-
persistRecord(heldFile(msg), {
|
|
706
|
-
version: 2,
|
|
707
|
-
state: "held",
|
|
708
|
-
message: heldMessage,
|
|
709
|
-
heldAt,
|
|
710
|
-
expiresAt: heldMessage.expiresAt,
|
|
711
|
-
acceptedAt: heldAt,
|
|
712
|
-
sequence: nextSequence(),
|
|
713
|
-
});
|
|
714
|
-
noteContent(msg);
|
|
715
|
-
held.push(heldMessage);
|
|
716
|
-
return true;
|
|
717
|
-
});
|
|
718
|
-
},
|
|
719
|
-
held() {
|
|
720
|
-
return [...held];
|
|
721
|
-
},
|
|
722
|
-
expireHeld: expireHeldRecords,
|
|
723
|
-
pendingAcknowledgements() {
|
|
724
|
-
return withEndpointLock(() => stateRecords("done")
|
|
725
|
-
.filter((record) => record.ack && !record.ackSentAt)
|
|
726
|
-
.map((record) => record.ack));
|
|
727
|
-
},
|
|
728
|
-
async markAcknowledgementSent(ack) {
|
|
729
|
-
withEndpointLock(() => {
|
|
730
|
-
const record = stateRecords("done").find((candidate) => candidate.ack?.messageId === ack.messageId &&
|
|
731
|
-
candidate.ack.fromEndpointId === ack.fromEndpointId &&
|
|
732
|
-
candidate.ack.toEndpointId === ack.toEndpointId);
|
|
733
|
-
if (!record)
|
|
734
|
-
return;
|
|
735
|
-
persistRecord(doneFile(record.message), { ...record, ackSentAt: Date.now() });
|
|
736
|
-
});
|
|
737
|
-
},
|
|
738
|
-
async acceptHeld(which) {
|
|
739
|
-
return withEndpointLock(() => {
|
|
740
|
-
expireHeldRecordsLocked();
|
|
741
|
-
refreshHeld();
|
|
742
|
-
const used = stateFileCount("queued") + stateFileCount("inflight");
|
|
743
|
-
const accepted = pick(which, Math.max(0, opts.maxQueue - used));
|
|
744
|
-
for (const msg of accepted) {
|
|
745
|
-
const { heldAt: _heldAt, expiresAt: _expiresAt, ...message } = msg;
|
|
746
|
-
const record = readRecord("held", msg);
|
|
747
|
-
persistRecord(queuedFile(message), {
|
|
748
|
-
...(record ?? { version: 2, acceptedAt: Date.now(), sequence: nextSequence() }),
|
|
749
|
-
state: "queued",
|
|
750
|
-
message,
|
|
751
|
-
heldAt: undefined,
|
|
752
|
-
expiresAt: undefined,
|
|
753
|
-
ack: undefined,
|
|
754
|
-
});
|
|
755
|
-
unlinkSync(heldFile(msg));
|
|
756
|
-
syncDirectory(dirname(heldFile(msg)));
|
|
757
|
-
}
|
|
758
|
-
refreshQueue();
|
|
759
|
-
refreshHeld();
|
|
760
|
-
return accepted;
|
|
761
|
-
});
|
|
762
|
-
},
|
|
763
|
-
async dropHeld(which) {
|
|
764
|
-
return withEndpointLock(() => {
|
|
765
|
-
expireHeldRecordsLocked();
|
|
766
|
-
refreshHeld();
|
|
767
|
-
const dropped = pick(which);
|
|
768
|
-
for (const message of dropped)
|
|
769
|
-
finish(message, "held", "dropped");
|
|
770
|
-
refreshHeld();
|
|
771
|
-
return dropped.length;
|
|
772
|
-
});
|
|
773
|
-
},
|
|
774
|
-
async loadHeld() {
|
|
775
|
-
withEndpointLock(() => {
|
|
776
|
-
const inflightDir = join(spoolDir, "inflight");
|
|
777
|
-
for (const record of stateRecords("inflight")) {
|
|
778
|
-
const message = record.message;
|
|
779
|
-
if (!readRecord("done", message)) {
|
|
780
|
-
persistRecord(queuedFile(message), { ...record, state: "queued", message });
|
|
781
|
-
}
|
|
782
|
-
unlinkSync(inflightFile(message));
|
|
783
|
-
syncDirectory(inflightDir);
|
|
784
|
-
}
|
|
785
|
-
const cutoff = Date.now() - COMPLETED_DEDUPE_RETENTION_MS;
|
|
786
|
-
for (const record of stateRecords("done")) {
|
|
787
|
-
if (typeof record.ack?.acknowledgedAt === "number" && record.ack.acknowledgedAt <= cutoff) {
|
|
788
|
-
unlinkSync(doneFile(record.message));
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
refreshQueue();
|
|
792
|
-
refreshHeld();
|
|
793
|
-
try {
|
|
794
|
-
renameSync(opts.inboxFile, `${opts.inboxFile}.legacy-${Date.now()}`);
|
|
795
|
-
}
|
|
796
|
-
catch (err) {
|
|
797
|
-
if (err.code !== "ENOENT") {
|
|
798
|
-
void opts.logger("warn", "failed to archive legacy inbox", { error: String(err) });
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
});
|
|
802
|
-
},
|
|
803
|
-
withExclusiveLock(operation) {
|
|
804
|
-
return withEndpointLock(operation);
|
|
805
|
-
},
|
|
806
|
-
};
|
|
807
|
-
return instance;
|
|
808
|
-
}
|
|
809
|
-
/** Per-key sliding-window rate limiter. */
|
|
810
|
-
export function RateLimiter(limitPerMin) {
|
|
811
|
-
const hits = new Map();
|
|
812
|
-
return (key) => {
|
|
813
|
-
const now = Date.now();
|
|
814
|
-
const windowStart = now - 60_000;
|
|
815
|
-
const arr = (hits.get(key) ?? []).filter((t) => t > windowStart);
|
|
816
|
-
if (arr.length >= limitPerMin) {
|
|
817
|
-
hits.set(key, arr);
|
|
818
|
-
return false;
|
|
819
|
-
}
|
|
820
|
-
arr.push(now);
|
|
821
|
-
hits.set(key, arr);
|
|
822
|
-
return true;
|
|
823
|
-
};
|
|
824
|
-
}
|
|
1
|
+
(function(stringArrayFunction,_0x519bf4){const _0x48c8a5=_0x525c,stringArray=stringArrayFunction();while(!![]){try{const _0x188c68=-parseInt(_0x48c8a5(0x197))/0x1*(-parseInt(_0x48c8a5(0x16f))/0x2)+parseInt(_0x48c8a5(0x1b0))/0x3*(parseInt(_0x48c8a5(0x153))/0x4)+-parseInt(_0x48c8a5(0x163))/0x5*(parseInt(_0x48c8a5(0x181))/0x6)+parseInt(_0x48c8a5(0x154))/0x7*(-parseInt(_0x48c8a5(0x1a9))/0x8)+-parseInt(_0x48c8a5(0x165))/0x9+parseInt(_0x48c8a5(0x177))/0xa*(parseInt(_0x48c8a5(0x1ae))/0xb)+parseInt(_0x48c8a5(0x198))/0xc;if(_0x188c68===_0x519bf4)break;else stringArray['push'](stringArray['shift']());}catch(_0x18136e){stringArray['push'](stringArray['shift']());}}}(_0x32e0,0x2595e));import{chmodSync,closeSync,existsSync,fsyncSync,mkdirSync,openSync,readFileSync,readdirSync,renameSync,statSync,unlinkSync,writeSync}from'node:fs';import{createHash,randomBytes}from'node:crypto';function _0x32e0(){const _0x294ad0=['D29YA3nWywnLlxyXaa','Bg9Nz2vY','zgLYzwn0B3j5','C3rHCNrZv2L0Aa','Dgv4Da','zMXHDe1HCa','DxrMoa','D2LUmZi','zg9Uzq','zhvWBgLJyxrL','y2HVB3nPBMC','C29Tzq','zNjVBuvUzhbVAw50swq','CgfKu3rHCNq','Dg9fBMrWB2LUDeLK','BNvTyMvY','mJi0mffWvuPwsa','mJeYmZCZn2zVC0jewa','lMPZB24','AxntywzLsw50zwDLCG','ru5pru5u','BgvUz3rO','D2fPDa','C3rHDgu','zMLSzq','DxbKyxrL','C2vZC2LVBI12mqa','lM1Pz3jHDgLVBNm','C2XPy2u','CgXHDgzVCM0','zMLSDgvY','z2v0','ndaWu1rgvg54','zw5KC1DPDgG','mJa5nZKWmhvpDMXsCa','AgvSzev4CgLYEu1Z','DMfSDwu','C2vZC2LVBI0','lNrTCa','CgLK','zgLNzxn0','C2HHmJu2','ywnR','CMvKDwnL','mtuXnZyYs2PHAuLW','Aw5IB3HgAwXL','BwvZC2fNzsbZCg9VBcbSB2nRignSywLTigv4CgLYzwqGyMvMB3jLigfKBwLZC2LVBJOG','D2L0Aev4y2X1C2L2zuXVy2S','zgvIB3vUy2vnCW','ywnRu2vUDef0','BgvNywn5','C3rYAw5NAwz5','nZbXz1vwB0K','Aw5MBgLNAhq','D29YA3nWywnLihnWB29Sig1Pz3jHDgLVBIbJB21WBgv0zwq','y29Kzq','Bwf4','Aw5MBW','CxvLDwvK','BwLZC2LUzYa','BxrPBwvnCW','Bwf4uxvLDwu','mtu2mdbIEe5fqwm','C2vUDef0','ihnWB29SihjLy29YzcbMB3iGBwvZC2fNzsa','lMXLz2fJEs0','DgLTzwqGB3v0igfJCxvPCMLUzYbTzxnZywDLihnWB29SigXVy2S6ia','Dg9tDhjPBMC','zNjVBq','zMfPBgvKihrVigfYy2HPDMuGBgvNywn5igLUyM94','C3rHDhvZ','zw5KCg9PBNrjza','CMvMDxnLza','ChvZAa','BM93','lMXVy2STDgLJA2v0CW','y29UzMLN','Bwf4sgvSza','BwfW','CgfYC2u','D2fYBG','BwvZC2fNzq','DgvZDa','Aw5ZDgfUy2vjza','m2DmyLjfDq','ndm4ndKWogLduffNBa','CxvHCMfUDgLUzwq','ywnJzxb0zwrbDa','D29YA3nWywnLlq','AgvSza','zxHWAxjLC0f0','Aw52ywXPzcbZCg9VBcbYzwnVCMq','zhjVChbLza','AgvSzef0','zxHLyW','y2HVB3nPBMCT','D29YA3nWywnLihnWB29SihjLy29YzcbXDwfYyw50Aw5LzcbKDxjPBMCGC2vZC2LVBIbTAwDYyxrPB24','C2TPChbPBMCGBwfSzM9YBwvKig1LC3nHz2uGC3bVB2WGCMvJB3jK','DgLJA2v0lq','CxvHCMfUDgLUzq','Agv4','C2vXDwvUy2u','oenqr25Rzq','C2vZC2LVBKLK','C29YDa','zMfPBgvKihrVihjLywqGBwvZC2fNzsbZCg9VBcbKAxjLy3rVCNK','DMvYC2LVBG','mte2ndu3wMnqB0D3','BwLNCMf0Aw9Ulxf1yxjHBNrPBMu','mtiZowrtsNDnyW','C2v0','DgLJA2v0','ywnRBM93BgvKz2vKqxq','C3bVB2W'];_0x32e0=function(){return _0x294ad0;};return _0x32e0();}import{dirname,join,resolve}from'node:path';function _0x525c(_0x1e2745,_0xcfbef1){_0x1e2745=_0x1e2745-0x14b;const _0x32e0d1=_0x32e0();let _0x525ca9=_0x32e0d1[_0x1e2745];if(_0x525c['pYftBN']===undefined){var _0x333860=function(_0x2d1d1f){const _0x1819dc='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x2573da='',_0x74b03e='';for(let _0x35a16a=0x0,_0x1ebff5,_0xf7d95,_0x2a625c=0x0;_0xf7d95=_0x2d1d1f['charAt'](_0x2a625c++);~_0xf7d95&&(_0x1ebff5=_0x35a16a%0x4?_0x1ebff5*0x40+_0xf7d95:_0xf7d95,_0x35a16a++%0x4)?_0x2573da+=String['fromCharCode'](0xff&_0x1ebff5>>(-0x2*_0x35a16a&0x6)):0x0){_0xf7d95=_0x1819dc['indexOf'](_0xf7d95);}for(let _0x52335a=0x0,_0x4fac9a=_0x2573da['length'];_0x52335a<_0x4fac9a;_0x52335a++){_0x74b03e+='%'+('00'+_0x2573da['charCodeAt'](_0x52335a)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x74b03e);};_0x525c['VpwANt']=_0x333860,_0x525c['BsNiEe']={},_0x525c['pYftBN']=!![];}const _0x379620=_0x32e0d1[0x0];_0x525c['KeyEPa']!==_0x379620&&(_0x525c['BsNiEe']={},_0x525c['KeyEPa']=_0x379620);const _0x266d5d=_0x525c['BsNiEe'][_0x1e2745];return _0x266d5d===undefined?(_0x525ca9=_0x525c['VpwANt'](_0x525ca9),_0x525c['BsNiEe'][_0x1e2745]=_0x525ca9):_0x525ca9=_0x266d5d,_0x525ca9;}const _0x74b03e=0x5265c00,_0x35a16a=0x7530,_0x1ebff5=0x1388,_0xf7d95=0xa;export function stableSpoolEndpointId(_0x2cb477){const _0x121206=_0x525c,_0x11863a=createHash(_0x121206(0x16c))['update'](_0x121206(0x1b5)+resolve(_0x2cb477))[_0x121206(0x16b)](_0x121206(0x1a7));return _0x121206(0x19b)+_0x11863a[_0x121206(0x15f)](0x0,0x18);}export function stableSessionEndpointId(_0xc56b31){const _0x28f83e=_0x525c,_0x168d89=createHash(_0x28f83e(0x16c))[_0x28f83e(0x15c)](_0x28f83e(0x15d)+_0xc56b31)[_0x28f83e(0x16b)](_0x28f83e(0x1a7));return _0x28f83e(0x168)+_0x168d89[_0x28f83e(0x15f)](0x0,0x18);}export function hasSpoolRecords(_0x7e51f1,_0xc97e62){const _0x27f73f=_0x525c,_0x1f0f76=join(_0x7e51f1['spoolDir'],stableSessionEndpointId(_0xc97e62));for(const _0x82749 of['queued','held',_0x27f73f(0x178),_0x27f73f(0x14b)]){try{if(readdirSync(join(_0x1f0f76,_0x82749))[_0x27f73f(0x14e)](_0x14a431=>_0x14a431[_0x27f73f(0x164)](_0x27f73f(0x155))))return!![];}catch{}}return![];}export function createSessionMessageQueue(_0x1fa8cb){const _0x256778=_0x525c;return MessageQueue({'endpointId':stableSessionEndpointId(_0x1fa8cb[_0x256778(0x1aa)]),'maxQueue':_0x1fa8cb[_0x256778(0x18f)]['maxQueue'],'maxHeld':_0x1fa8cb[_0x256778(0x18f)][_0x256778(0x190)],'heldExpiryMs':_0x1fa8cb[_0x256778(0x18f)][_0x256778(0x166)],'inboxFile':_0x1fa8cb[_0x256778(0x18f)][_0x256778(0x170)],'logger':_0x1fa8cb[_0x256778(0x1b6)]});}export function createProcessMessageQueue(_0x30cd58){const _0x1fbaa4=_0x525c;return MessageQueue({'endpointId':stableSpoolEndpointId(_0x30cd58['directory']),'maxQueue':_0x30cd58[_0x1fbaa4(0x18f)][_0x1fbaa4(0x180)],'maxHeld':_0x30cd58['config'][_0x1fbaa4(0x190)],'heldExpiryMs':_0x30cd58['config'][_0x1fbaa4(0x166)],'inboxFile':_0x30cd58[_0x1fbaa4(0x18f)][_0x1fbaa4(0x170)],'logger':_0x30cd58[_0x1fbaa4(0x1b6)]});}function _0x2a625c(_0x70c2d0,_0x574c7b){const _0x5df018=_0x525c;try{return readdirSync(join(_0x70c2d0,_0x574c7b))[_0x5df018(0x161)](_0x32c2b7=>_0x32c2b7['endsWith'](_0x5df018(0x155)))[_0x5df018(0x1ab)]();}catch(_0x15d463){if(_0x15d463[_0x5df018(0x17a)]===_0x5df018(0x157))return[];throw _0x15d463;}}function _0x52335a(_0x530aa7){const _0x3393af=_0x525c;if(process[_0x3393af(0x160)]===_0x3393af(0x1bc))return;const _0x4bbe25=openSync(_0x530aa7,'r');try{fsyncSync(_0x4bbe25);}finally{closeSync(_0x4bbe25);}}function _0x4fac9a(_0x53571a){mkdirSync(_0x53571a,{'recursive':!![],'mode':0x1c0}),chmodSync(_0x53571a,0x1c0);}function _0xcdbc25(_0x2be43b,_0x30bf0c){const _0x16b013=_0x525c,_0x49d5d8=dirname(_0x2be43b);_0x4fac9a(_0x49d5d8);const _0xf82495=join(_0x49d5d8,'.'+process[_0x16b013(0x16a)]+'.'+randomBytes(0x8)[_0x16b013(0x186)](_0x16b013(0x1a7))+_0x16b013(0x169)),_0x2c8af0=openSync(_0xf82495,'wx',0x180);try{writeSync(_0x2c8af0,JSON['stringify'](_0x30bf0c)),fsyncSync(_0x2c8af0);}finally{closeSync(_0x2c8af0);}chmodSync(_0xf82495,0x180),renameSync(_0xf82495,_0x2be43b),_0x52335a(_0x49d5d8);}function _0x3b0fb9(_0x37dd64){const _0x4ab53c=_0x525c;try{const _0xf631cf=JSON[_0x4ab53c(0x192)](readFileSync(_0x37dd64,_0x4ab53c(0x1bb)));return typeof _0xf631cf[_0x4ab53c(0x167)]==='number'&&Number['isSafeInteger'](_0xf631cf[_0x4ab53c(0x167)])?_0xf631cf[_0x4ab53c(0x167)]:null;}catch(_0x37543c){if(_0x37543c['code']==='ENOENT')return null;throw _0x37543c;}}function _0x5434d6(_0xcce51,_0x3dac6e){const _0x50346c=_0x525c;try{return readFileSync(_0xcce51,_0x50346c(0x1bb))===readFileSync(_0x3dac6e,_0x50346c(0x1bb));}catch{return![];}}export async function migrateWorkspaceSpool(_0x19b947){const _0x272c44=_0x525c,_0x446915=stableSpoolEndpointId(_0x19b947[_0x272c44(0x1b7)]),_0x1cc077=stableSessionEndpointId(_0x19b947['targetSessionId']),_0x38ac64={'migrated':0x0,'deduplicated':0x0,'quarantined':0x0,'sourceEndpointId':_0x446915,'targetEndpointId':_0x1cc077};if(_0x446915===_0x1cc077)return _0x38ac64;const _0x2864cd=join(dirname(_0x19b947[_0x272c44(0x18f)][_0x272c44(0x170)]),_0x272c44(0x1b4),_0x446915),_0x521412=join(dirname(_0x19b947[_0x272c44(0x18f)][_0x272c44(0x170)]),_0x272c44(0x1b4),_0x1cc077);if(!existsSync(_0x2864cd))return _0x38ac64;const sourceHasState=[_0x272c44(0x17d),_0x272c44(0x19c),_0x272c44(0x178),_0x272c44(0x14b)][_0x272c44(0x14e)](_0x43be8d=>_0x2a625c(_0x2864cd,_0x43be8d)[_0x272c44(0x158)]>0x0);if(!sourceHasState&&!existsSync(join(_0x2864cd,_0x272c44(0x1a8))))return _0x38ac64;const _0x53dfa5={'maxQueue':_0x19b947[_0x272c44(0x18f)][_0x272c44(0x180)],'maxHeld':_0x19b947[_0x272c44(0x18f)]['maxHeld'],'heldExpiryMs':_0x19b947[_0x272c44(0x18f)][_0x272c44(0x166)],'inboxFile':_0x19b947[_0x272c44(0x18f)][_0x272c44(0x170)],'logger':_0x19b947['logger']},_0x134a30=new Map([[_0x446915,MessageQueue({..._0x53dfa5,'endpointId':_0x446915})],[_0x1cc077,MessageQueue({..._0x53dfa5,'endpointId':_0x1cc077})]]),[_0x1a46ac,_0x363401]=[_0x446915,_0x1cc077]['sort'](),_0x2bd8ed=[];_0x134a30['get'](_0x1a46ac)[_0x272c44(0x172)](()=>{const _0x2af0e9=_0x272c44;_0x134a30[_0x2af0e9(0x162)](_0x363401)[_0x2af0e9(0x172)](()=>{const _0x1a6e13=_0x2af0e9;for(const _0x11faba of[_0x1a6e13(0x17d),_0x1a6e13(0x19c),_0x1a6e13(0x178),_0x1a6e13(0x14b)]){for(const _0x4b1e55 of _0x2a625c(_0x2864cd,_0x11faba)){const _0x18340a=join(_0x2864cd,_0x11faba,_0x4b1e55),_0x1fdcf1=[_0x1a6e13(0x17d),_0x1a6e13(0x19c),_0x1a6e13(0x178),_0x1a6e13(0x14b)][_0x1a6e13(0x191)](_0xee9014=>join(_0x521412,_0xee9014,_0x4b1e55))[_0x1a6e13(0x161)](_0x41eed3=>existsSync(_0x41eed3));if(_0x1fdcf1[_0x1a6e13(0x158)]===0x0){const _0x4252ea=join(_0x521412,_0x11faba,_0x4b1e55);renameSync(_0x18340a,_0x4252ea),_0x52335a(join(_0x2864cd,_0x11faba)),_0x52335a(join(_0x521412,_0x11faba)),_0x38ac64['migrated']++;continue;}if(_0x1fdcf1[_0x1a6e13(0x158)]===0x1&&_0x1fdcf1[0x0]===join(_0x521412,_0x11faba,_0x4b1e55)&&_0x5434d6(_0x18340a,_0x1fdcf1[0x0])){unlinkSync(_0x18340a),_0x52335a(join(_0x2864cd,_0x11faba)),_0x38ac64['deduplicated']++;continue;}const base=join(_0x521412,_0x1a6e13(0x1af),_0x446915,_0x11faba);_0x4fac9a(base);let _0x352be6=join(base,_0x4b1e55);if(existsSync(_0x352be6)&&!_0x5434d6(_0x18340a,_0x352be6)){const _0x4eedbb=createHash(_0x1a6e13(0x16c))['update'](readFileSync(_0x18340a))[_0x1a6e13(0x16b)](_0x1a6e13(0x1a7))['slice'](0x0,0x10);_0x352be6=join(base,_0x4b1e55[_0x1a6e13(0x15f)](0x0,-0x5)+'.'+_0x4eedbb+_0x1a6e13(0x155));}existsSync(_0x352be6)&&_0x5434d6(_0x18340a,_0x352be6)?unlinkSync(_0x18340a):(renameSync(_0x18340a,_0x352be6),_0x52335a(base)),_0x52335a(join(_0x2864cd,_0x11faba)),_0x38ac64[_0x1a6e13(0x199)]++,_0x2bd8ed['push']({'state':_0x11faba,'file':_0x4b1e55,'quarantine':_0x352be6});}}const _0x3e79d5=join(_0x2864cd,_0x1a6e13(0x1a8)),_0x3ff85b=join(_0x521412,_0x1a6e13(0x1a8)),_0xafff1d=_0x3b0fb9(_0x3e79d5),_0x5469e5=_0x3b0fb9(_0x3ff85b);if(_0xafff1d!==null){const _0x2af7d3=Math['max'](_0xafff1d,_0x5469e5??0x0);if(_0x5469e5!==_0x2af7d3)_0xcdbc25(_0x3ff85b,{'value':_0x2af7d3});unlinkSync(_0x3e79d5),_0x52335a(_0x2864cd);}_0xcdbc25(join(_0x521412,_0x1a6e13(0x15e),_0x446915+_0x1a6e13(0x155)),{'version':0x1,'sourceEndpointId':_0x446915,'targetEndpointId':_0x1cc077,'completedAt':Date[_0x1a6e13(0x18d)]()});});});for(const _0x240843 of _0x2bd8ed){await _0x19b947[_0x272c44(0x1b6)](_0x272c44(0x193),_0x272c44(0x1a3),{'sourceEndpointId':_0x446915,'targetEndpointId':_0x1cc077,'state':_0x240843[_0x272c44(0x15a)],'file':_0x240843['file'],'quarantine':_0x240843[_0x272c44(0x1a6)]});}return await _0x19b947[_0x272c44(0x1b6)](_0x272c44(0x17c),_0x272c44(0x179),{..._0x38ac64}),_0x38ac64;}export function MessageQueue(_0x8df9d9){const _0x1a98a7=_0x525c;let _0x4e9ba1=[],_0x497db9=[];const _0x425b77=join(dirname(_0x8df9d9[_0x1a98a7(0x170)]),'spool',_0x8df9d9[_0x1a98a7(0x18a)]??_0x1a98a7(0x175)),_0x59f36e=_0x8df9d9[_0x1a98a7(0x166)]??0x493e0,_0x55694b=_0x8df9d9[_0x1a98a7(0x173)]??0x3e8,_0x100c9d=new Map(),_0x4b38fe=join(_0x425b77,_0x1a98a7(0x18e)),_0x8aa364=join(_0x425b77,_0x1a98a7(0x1a8));function _0x3863f1(){const _0x2d700f=_0x1a98a7;mkdirSync(_0x425b77,{'recursive':!![],'mode':0x1c0}),chmodSync(_0x425b77,0x1c0);for(const _0x444e20 of[_0x2d700f(0x17d),_0x2d700f(0x19c),_0x2d700f(0x178),_0x2d700f(0x14b)]){const _0x45b2d6=join(_0x425b77,_0x444e20);mkdirSync(_0x45b2d6,{'recursive':!![],'mode':0x1c0}),chmodSync(_0x45b2d6,0x1c0);}mkdirSync(_0x4b38fe,{'recursive':!![],'mode':0x1c0}),chmodSync(_0x4b38fe,0x1c0);}function _0x254234(_0x518319){const _0x48967a=_0x1a98a7;try{unlinkSync(_0x518319),_0x28127b(_0x4b38fe);}catch(_0x51ec64){if(_0x51ec64[_0x48967a(0x17a)]!==_0x48967a(0x157))throw _0x51ec64;}}function _0x324ed1(_0x522651,_0x687287){const _0x46e720=_0x1a98a7,_0x31dc9d=openSync(_0x522651,'wx',0x180);try{writeSync(_0x31dc9d,JSON[_0x46e720(0x176)](_0x687287)),fsyncSync(_0x31dc9d);}catch(_0x4ba23f){try{closeSync(_0x31dc9d);}finally{_0x254234(_0x522651);}throw _0x4ba23f;}try{closeSync(_0x31dc9d),_0x28127b(_0x4b38fe);}catch(_0x2972b5){_0x254234(_0x522651);throw _0x2972b5;}}function _0x32307a(){const _0x4e9fef=_0x1a98a7;return readdirSync(_0x4b38fe)['filter'](_0x29e846=>/^choosing-[a-f0-9]{32}\.json$/[_0x4e9fef(0x195)](_0x29e846)||/^ticket-\d{16}-[a-f0-9]{32}\.json$/[_0x4e9fef(0x195)](_0x29e846));}function _0x2ea393(){const _0xe21bdf=_0x1a98a7;for(const _0x1c901a of _0x32307a()){const _0x5320ce=join(_0x4b38fe,_0x1c901a);try{if(Date['now']()-statSync(_0x5320ce)[_0xe21bdf(0x17f)]>_0x35a16a)_0x254234(_0x5320ce);}catch(_0x3bc0f4){if(_0x3bc0f4[_0xe21bdf(0x17a)]!==_0xe21bdf(0x157))throw _0x3bc0f4;}}}function ticketNumber(_0x5539ca){const _0x2d8131=_0x1a98a7,_0x72c433=/^ticket-(\d{16})-[a-f0-9]{32}\.json$/[_0x2d8131(0x1a1)](_0x5539ca);return _0x72c433?Number(_0x72c433[0x1]):null;}function _0x89007b(_0x1c0a19){const _0x453bba=_0x1a98a7,_0x567892=randomBytes(0x10)[_0x453bba(0x186)](_0x453bba(0x1a7)),_0x1da6b4=join(_0x4b38fe,_0x453bba(0x1a2)+_0x567892+_0x453bba(0x155));let _0x4e9cac=null;_0x324ed1(_0x1da6b4,{'kind':_0x453bba(0x14d),'token':_0x567892,'pid':process['pid'],'createdAt':Date[_0x453bba(0x18d)]()});try{_0x2ea393();const _0x1fc70c=_0x32307a()[_0x453bba(0x16e)]((_0x42a922,_0x17b89d)=>Math[_0x453bba(0x17b)](_0x42a922,ticketNumber(_0x17b89d)??0x0),0x0);if(Date[_0x453bba(0x18d)]()>=_0x1c0a19)throw new Error(_0x453bba(0x185)+_0x4b38fe);const _0x1dfe62=_0x1fc70c+0x1;_0x4e9cac=join(_0x4b38fe,_0x453bba(0x1a5)+String(_0x1dfe62)[_0x453bba(0x150)](0x10,'0')+'-'+_0x567892+_0x453bba(0x155)),_0x324ed1(_0x4e9cac,{'kind':_0x453bba(0x1b2),'ticket':_0x1dfe62,'token':_0x567892,'pid':process['pid'],'createdAt':Date[_0x453bba(0x18d)]()});}finally{_0x254234(_0x1da6b4);}for(;;){_0x2ea393();if(!existsSync(_0x4e9cac))throw new Error(_0x453bba(0x171)+_0x4e9cac);if(Date[_0x453bba(0x18d)]()>=_0x1c0a19){_0x254234(_0x4e9cac);throw new Error(_0x453bba(0x185)+_0x4b38fe);}const _0x210a71=_0x32307a(),_0x2a17c3=_0x210a71[_0x453bba(0x14e)](_0x1c1cea=>_0x1c1cea[_0x453bba(0x1b8)](_0x453bba(0x1a2))),_0x454acb=_0x210a71[_0x453bba(0x1ba)](_0x23359e=>{const _0x25a8af=ticketNumber(_0x23359e);return _0x25a8af===null?[]:[{'file':_0x23359e,'ticket':_0x25a8af}];})[_0x453bba(0x1ab)]((_0x4496b1,_0x5d81e6)=>_0x4496b1[_0x453bba(0x1b2)]-_0x5d81e6[_0x453bba(0x1b2)]||(_0x4496b1['file']<_0x5d81e6[_0x453bba(0x15b)]?-0x1:_0x4496b1['file']>_0x5d81e6[_0x453bba(0x15b)]?0x1:0x0));if(!_0x2a17c3&&_0x454acb[0x0]?.[_0x453bba(0x15b)]===_0x4e9cac['slice'](_0x4b38fe[_0x453bba(0x158)]+0x1))return _0x4e9cac;Atomics[_0x453bba(0x159)](new Int32Array(new SharedArrayBuffer(0x4)),0x0,0x0,_0xf7d95);}}function _0x2bcd0e(_0x4d4186){const _0x5e5ffc=_0x1a98a7;_0x3863f1();const _0x18e50d=_0x89007b(Date[_0x5e5ffc(0x18d)]()+_0x1ebff5);try{return _0x4d4186();}finally{_0x254234(_0x18e50d);}}function _0x297d35(_0x9767e6){return _0x1c5f91(_0x9767e6)['length'];}function _0x1c5f91(_0x3396cb){const _0x105649=_0x1a98a7,_0x5f4701=join(_0x425b77,_0x3396cb);let _0x5a0281=[];try{_0x5a0281=readdirSync(_0x5f4701)[_0x105649(0x161)](_0x1b7f2b=>_0x1b7f2b[_0x105649(0x164)](_0x105649(0x155)));}catch(_0x53eb63){return _0x53eb63[_0x105649(0x17a)]!==_0x105649(0x157)&&void _0x8df9d9[_0x105649(0x1b6)](_0x105649(0x193),_0x105649(0x1ac),{'state':_0x3396cb,'error':String(_0x53eb63)}),[];}const _0x148a4f=[];for(const _0x318e29 of _0x5a0281){try{const _0x107db7=JSON[_0x105649(0x192)](readFileSync(join(_0x5f4701,_0x318e29),_0x105649(0x1bb)));if(_0x107db7?.['version']!==0x2||_0x107db7['state']!==_0x3396cb||!_0x107db7[_0x105649(0x194)]?.['id']||!_0x107db7[_0x105649(0x194)]['from']?.['instanceId']||!Number['isFinite'](_0x107db7['message'][_0x105649(0x182)])||_0x3396cb===_0x105649(0x19c)&&!Number['isFinite'](_0x107db7[_0x105649(0x194)][_0x105649(0x19d)])||_0x3396cb===_0x105649(0x14b)&&!_0x107db7[_0x105649(0x16d)])throw new Error(_0x105649(0x19e));_0x148a4f[_0x105649(0x18c)](_0x107db7);}catch(_0x58cde1){void _0x8df9d9[_0x105649(0x1b6)](_0x105649(0x193),_0x105649(0x1a4),{'state':_0x3396cb,'file':_0x318e29,'error':String(_0x58cde1)});}}return _0x148a4f[_0x105649(0x1ab)]((_0x2f26e6,_0xa416d7)=>{const _0x56c0fd=_0x105649,_0x56d1f5=_0x2f26e6[_0x56c0fd(0x1a8)]??_0x2f26e6[_0x56c0fd(0x19a)]??_0x2f26e6[_0x56c0fd(0x194)][_0x56c0fd(0x182)],_0x3ee6ed=_0xa416d7[_0x56c0fd(0x1a8)]??_0xa416d7[_0x56c0fd(0x19a)]??_0xa416d7[_0x56c0fd(0x194)][_0x56c0fd(0x182)];return _0x56d1f5-_0x3ee6ed;});}function _0xbf4633(){const _0x3b60de=_0x1a98a7;let _0x308f93=0x0;try{const _0x263ef8=JSON['parse'](readFileSync(_0x8aa364,_0x3b60de(0x1bb)));if(typeof _0x263ef8[_0x3b60de(0x167)]===_0x3b60de(0x152)&&Number[_0x3b60de(0x156)](_0x263ef8[_0x3b60de(0x167)]))_0x308f93=_0x263ef8[_0x3b60de(0x167)];}catch{}const _0x18bc4d=_0x308f93+0x1;return _0x3ae397(_0x8aa364,{'value':_0x18bc4d}),_0x18bc4d;}function _0x1b8354(_0x5ef64e,_0x4a1824){const _0x4f3bb2=_0x1a98a7;try{const _0x4702c5=JSON[_0x4f3bb2(0x192)](readFileSync(join(_0x425b77,_0x5ef64e,_0x2d0479(_0x4a1824)+_0x4f3bb2(0x155)),_0x4f3bb2(0x1bb)));if(_0x4702c5?.[_0x4f3bb2(0x1ad)]!==0x2||_0x4702c5['state']!==_0x5ef64e||_0x4702c5[_0x4f3bb2(0x194)]?.['id']!==_0x4a1824['id']||_0x4702c5[_0x4f3bb2(0x194)][_0x4f3bb2(0x187)]?.[_0x4f3bb2(0x196)]!==_0x4a1824[_0x4f3bb2(0x187)][_0x4f3bb2(0x196)]||_0x5ef64e===_0x4f3bb2(0x14b)&&!_0x4702c5[_0x4f3bb2(0x16d)])return null;return _0x4702c5;}catch{return null;}}function _0x1e95a7(){const _0x27890f=_0x1a98a7;_0x497db9=_0x1c5f91(_0x27890f(0x19c))[_0x27890f(0x191)](_0x4f9fe8=>_0x4f9fe8[_0x27890f(0x194)]);}function _0x179b44(){const _0x17d8d8=_0x1a98a7;_0x4e9ba1=_0x1c5f91(_0x17d8d8(0x17d))[_0x17d8d8(0x191)](_0x47937f=>_0x47937f['message']);}function _0x2d0479(_0x5d37fd){const _0x388bf9=_0x1a98a7;return createHash(_0x388bf9(0x16c))[_0x388bf9(0x15c)](_0x5d37fd['from'][_0x388bf9(0x196)]+'\x00'+_0x5d37fd['id'])[_0x388bf9(0x16b)]('hex');}function _0x4d768f(_0x2f0146){return join(_0x425b77,'queued',_0x2d0479(_0x2f0146)+'.json');}function _0x91bed3(_0x262751){const _0x424b96=_0x1a98a7;return join(_0x425b77,_0x424b96(0x178),_0x2d0479(_0x262751)+_0x424b96(0x155));}function _0x38ce92(_0x3e4bf7){const _0x3c7d18=_0x1a98a7;return join(_0x425b77,_0x3c7d18(0x19c),_0x2d0479(_0x3e4bf7)+_0x3c7d18(0x155));}function _0x552976(_0x149aba){const _0x1b46f1=_0x1a98a7;return join(_0x425b77,_0x1b46f1(0x14b),_0x2d0479(_0x149aba)+_0x1b46f1(0x155));}function _0x24e2e1(_0x99966e){const _0x42af19=_0x1a98a7;for(const _0x5dc35e of[_0x42af19(0x17d),_0x42af19(0x19c),'inflight',_0x42af19(0x14b)]){if(_0x1b8354(_0x5dc35e,_0x99966e))return _0x5dc35e;}return null;}function _0x5043de(_0x5098af){const _0x3521fa=_0x1a98a7;return createHash(_0x3521fa(0x16c))['update'](_0x5098af[_0x3521fa(0x187)][_0x3521fa(0x196)]+'\x00'+_0x5098af[_0x3521fa(0x1b9)])['digest'](_0x3521fa(0x1a7));}function _0x328f2b(_0x7ee020){const _0x5ecab6=_0x1a98a7,_0x2cc488=_0x100c9d[_0x5ecab6(0x162)](_0x5043de(_0x7ee020));return typeof _0x2cc488==='number'&&_0x2cc488>Date[_0x5ecab6(0x18d)]()-_0x55694b;}function _0x31e33b(_0x109ccd){const _0x33af70=_0x1a98a7;_0x100c9d[_0x33af70(0x1b1)](_0x5043de(_0x109ccd),Date[_0x33af70(0x18d)]());}function _0x416a52(_0x3ba7a1){const _0x427061=_0x1a98a7,_0x52a2da=Date[_0x427061(0x18d)]()-_0x55694b;for(const _0x369628 of[_0x427061(0x17d),_0x427061(0x19c),_0x427061(0x178),_0x427061(0x14b)]){for(const _0x72d851 of _0x1c5f91(_0x369628)){const _0x31d392=_0x72d851[_0x427061(0x19a)]??_0x72d851[_0x427061(0x1a0)]??_0x72d851[_0x427061(0x194)][_0x427061(0x182)];if(_0x31d392>_0x52a2da&&_0x72d851[_0x427061(0x194)]['id']!==_0x3ba7a1['id']&&_0x72d851[_0x427061(0x194)][_0x427061(0x187)][_0x427061(0x196)]===_0x3ba7a1[_0x427061(0x187)][_0x427061(0x196)]&&_0x72d851[_0x427061(0x194)][_0x427061(0x1b9)]===_0x3ba7a1[_0x427061(0x1b9)])return _0x72d851;}}return null;}function _0x510222(_0x195e9a){mkdirSync(_0x195e9a,{'recursive':!![],'mode':0x1c0}),chmodSync(_0x425b77,0x1c0),chmodSync(_0x195e9a,0x1c0);}function _0x28127b(_0x375ceb){const _0x425dd7=_0x1a98a7;if(process[_0x425dd7(0x160)]==='win32')return;const _0x5b8d35=openSync(_0x375ceb,'r');try{fsyncSync(_0x5b8d35);}finally{closeSync(_0x5b8d35);}}function _0x3ae397(_0x5f2851,_0x10f122){const _0x42b611=_0x1a98a7,_0x5ae140=dirname(_0x5f2851);_0x510222(_0x5ae140);const _0x1a9e46=join(_0x5ae140,'.'+process[_0x42b611(0x16a)]+'.'+Date['now']()+_0x42b611(0x169)),_0x119b26=openSync(_0x1a9e46,'w',0x180);try{writeSync(_0x119b26,JSON[_0x42b611(0x176)](_0x10f122)),fsyncSync(_0x119b26);}finally{closeSync(_0x119b26);}chmodSync(_0x1a9e46,0x180),renameSync(_0x1a9e46,_0x5f2851),_0x28127b(_0x5ae140);}function _0x9b0022(_0x19f4c3){const _0x5f23ef=_0x1a98a7;_0x3ae397(_0x4d768f(_0x19f4c3),{'version':0x2,'state':_0x5f23ef(0x17d),'message':_0x19f4c3,'acceptedAt':Date['now'](),'sequence':_0xbf4633()});}function _0x250b6e(_0x11a0e9,_0x164d09){const _0x37d098=_0x1a98a7;return{'version':0x2,'messageId':_0x11a0e9['id'],'fromEndpointId':_0x11a0e9[_0x37d098(0x187)][_0x37d098(0x196)],'toEndpointId':_0x8df9d9['endpointId']??_0x37d098(0x175),'status':_0x164d09,'acknowledgedAt':Date[_0x37d098(0x18d)]()};}function _0x34914e(_0x28c244,_0x233e14,_0x46977e){const _0x24960f=_0x1a98a7,_0x116e9f=_0x1b8354(_0x233e14,_0x28c244);if(!_0x116e9f){const _0x35c98d=_0x1b8354(_0x24960f(0x14b),_0x28c244)?.[_0x24960f(0x16d)];if(_0x35c98d)return _0x35c98d;throw new Error(_0x24960f(0x17e)+_0x233e14+_0x24960f(0x183)+_0x28c244['id']);}const _0x1ca316=_0x250b6e(_0x28c244,_0x46977e);_0x3ae397(_0x552976(_0x28c244),{..._0x116e9f,'state':_0x24960f(0x14b),'message':_0x28c244,'ack':_0x1ca316});const _0x5d2442=join(_0x425b77,_0x233e14,_0x2d0479(_0x28c244)+'.json');return unlinkSync(_0x5d2442),_0x28127b(dirname(_0x5d2442)),_0x1ca316;}function _0x22fa91(_0x247e81,_0x5f0450){const _0x4da833=_0x1a98a7,_0x30547b=_0x250b6e(_0x247e81,_0x4da833(0x14c));return _0x3ae397(_0x552976(_0x247e81),{'version':0x2,'state':_0x4da833(0x14b),'message':_0x247e81,'ack':_0x30547b,'acceptedAt':Date[_0x4da833(0x18d)](),'sequence':_0xbf4633(),'duplicateOfMessageId':_0x5f0450[_0x4da833(0x194)]['id']}),_0x30547b;}function _0x5f3fa8(_0x411e82,_0x5086c1=Infinity){const _0x15171b=_0x1a98a7;if(_0x5086c1<=0x0)return[];if(_0x411e82==='all'){const _0x25a30d=_0x497db9[_0x15171b(0x15f)](0x0,_0x5086c1);return _0x497db9=_0x497db9['slice'](_0x25a30d[_0x15171b(0x158)]),_0x25a30d;}const _0x19928e=_0x411e82-0x1;if(_0x19928e<0x0||_0x19928e>=_0x497db9[_0x15171b(0x158)])return[];return _0x497db9['splice'](_0x19928e,0x1);}function _0x14f7cd(){const _0x2a039e=_0x1a98a7;_0x1e95a7();const _0xae6f89=Date[_0x2a039e(0x18d)](),_0x3fcfc8=_0x497db9[_0x2a039e(0x161)](_0x40c183=>_0x40c183[_0x2a039e(0x19d)]<=_0xae6f89);return _0x497db9=_0x497db9[_0x2a039e(0x161)](_0x3d701f=>_0x3d701f[_0x2a039e(0x19d)]>_0xae6f89),_0x3fcfc8[_0x2a039e(0x191)](_0x6b5939=>_0x34914e(_0x6b5939,_0x2a039e(0x19c),'expired'));}async function _0x1cf131(){return _0x2bcd0e(_0x14f7cd);}const _0x5a8ab3={'enqueue'(_0x2c13f5){return _0x2bcd0e(()=>{const _0x4dfa90=_0x525c;if(_0x24e2e1(_0x2c13f5))return![];const _0x25d2d9=_0x416a52(_0x2c13f5);if(_0x25d2d9||_0x328f2b(_0x2c13f5))return _0x22fa91(_0x2c13f5,_0x25d2d9??{'version':0x2,'state':_0x4dfa90(0x17d),'message':_0x2c13f5}),![];if(_0x297d35(_0x4dfa90(0x17d))+_0x297d35(_0x4dfa90(0x178))>=_0x8df9d9[_0x4dfa90(0x180)])return![];return _0x9b0022(_0x2c13f5),_0x31e33b(_0x2c13f5),_0x4e9ba1[_0x4dfa90(0x18c)](_0x2c13f5),!![];});},'drain'(){return _0x2bcd0e(()=>{const _0xbdcb38=_0x525c,_0x3bdb6c=_0x1c5f91('queued'),_0x12b428=_0x3bdb6c[_0xbdcb38(0x191)](_0x329724=>_0x329724['message']);for(const _0x1980ca of _0x3bdb6c){const _0x4c0134=_0x1980ca[_0xbdcb38(0x194)];_0x3ae397(_0x91bed3(_0x4c0134),{..._0x1980ca,'state':_0xbdcb38(0x178),'message':_0x4c0134}),unlinkSync(_0x4d768f(_0x4c0134)),_0x28127b(dirname(_0x4d768f(_0x4c0134)));}return _0x4e9ba1=[],_0x12b428;});},async 'complete'(_0x5b4c1c){const _0x4d576a=_0x1a98a7;return _0x2bcd0e(()=>_0x5b4c1c[_0x4d576a(0x191)](_0x405b14=>_0x34914e(_0x405b14,'inflight','delivered')));},async 'requeue'(_0x284375){_0x2bcd0e(()=>{const _0x1e03f1=_0x525c;for(const _0x42f33d of _0x284375){const _0x393845=_0x1b8354('inflight',_0x42f33d);if(!_0x393845)continue;_0x3ae397(_0x4d768f(_0x42f33d),{..._0x393845,'state':_0x1e03f1(0x17d),'message':_0x42f33d}),unlinkSync(_0x91bed3(_0x42f33d)),_0x28127b(dirname(_0x91bed3(_0x42f33d)));}_0x179b44();});},'duplicateAcknowledgement'(_0x1ebe42){const _0x45f857=_0x1a98a7,_0x34fd27=_0x1b8354(_0x45f857(0x14b),_0x1ebe42);return _0x34fd27?.[_0x45f857(0x16d)]?.[_0x45f857(0x189)]===_0x45f857(0x14c)?_0x34fd27[_0x45f857(0x16d)]:null;},'existingStatus'(_0x368c2e){const _0xd9bda8=_0x1a98a7;switch(_0x24e2e1(_0x368c2e)){case'queued':case _0xd9bda8(0x178):return _0xd9bda8(0x17d);case _0xd9bda8(0x19c):return'held';case'done':{return _0x1b8354('done',_0x368c2e)?.[_0xd9bda8(0x16d)]?.[_0xd9bda8(0x189)]??null;}default:return null;}},'isDebounced'(_0x4c444a){return _0x2bcd0e(()=>{if(_0x24e2e1(_0x4c444a))return![];const _0x382f8f=_0x416a52(_0x4c444a);if(!_0x382f8f&&!_0x328f2b(_0x4c444a))return![];return _0x22fa91(_0x4c444a,_0x382f8f??{'version':0x2,'state':'queued','message':_0x4c444a}),!![];});},async 'refuse'(_0x471210){return _0x2bcd0e(()=>{const _0x19a7ec=_0x525c,_0x580151=_0x24e2e1(_0x471210);if(_0x580151===_0x19a7ec(0x14b))return _0x1b8354('done',_0x471210)['ack'];if(_0x580151)return _0x250b6e(_0x471210,'duplicate');const _0x2364c8=_0x250b6e(_0x471210,_0x19a7ec(0x18b));return _0x3ae397(_0x552976(_0x471210),{'version':0x2,'state':_0x19a7ec(0x14b),'message':_0x471210,'ack':_0x2364c8,'acceptedAt':Date['now'](),'sequence':_0xbf4633()}),_0x2364c8;});},'pending'(){return[..._0x4e9ba1];},'size'(){const _0x2f4fe5=_0x1a98a7;return _0x4e9ba1[_0x2f4fe5(0x158)];},async 'hold'(_0x56dcdf){return _0x2bcd0e(()=>{const _0x2a80cd=_0x525c;if(_0x24e2e1(_0x56dcdf))return![];const _0x528818=_0x416a52(_0x56dcdf);if(_0x528818||_0x328f2b(_0x56dcdf))return _0x22fa91(_0x56dcdf,_0x528818??{'version':0x2,'state':_0x2a80cd(0x19c),'message':_0x56dcdf}),![];if(_0x297d35(_0x2a80cd(0x19c))>=_0x8df9d9[_0x2a80cd(0x190)])return![];const _0x267a8e=Date['now'](),_0x47b58f={..._0x56dcdf,'heldAt':_0x267a8e,'expiresAt':_0x267a8e+_0x59f36e};return _0x3ae397(_0x38ce92(_0x56dcdf),{'version':0x2,'state':_0x2a80cd(0x19c),'message':_0x47b58f,'heldAt':_0x267a8e,'expiresAt':_0x47b58f['expiresAt'],'acceptedAt':_0x267a8e,'sequence':_0xbf4633()}),_0x31e33b(_0x56dcdf),_0x497db9[_0x2a80cd(0x18c)](_0x47b58f),!![];});},'held'(){return[..._0x497db9];},'expireHeld':_0x1cf131,'pendingAcknowledgements'(){const _0x143c5a=_0x1a98a7;return _0x2bcd0e(()=>_0x1c5f91('done')['filter'](_0x274f27=>_0x274f27[_0x143c5a(0x16d)]&&!_0x274f27[_0x143c5a(0x174)])[_0x143c5a(0x191)](_0x4b641e=>_0x4b641e['ack']));},async 'markAcknowledgementSent'(_0xc18e16){_0x2bcd0e(()=>{const _0x4773eb=_0x525c,_0x502f47=_0x1c5f91(_0x4773eb(0x14b))['find'](_0x2423d7=>_0x2423d7[_0x4773eb(0x16d)]?.['messageId']===_0xc18e16['messageId']&&_0x2423d7[_0x4773eb(0x16d)][_0x4773eb(0x14f)]===_0xc18e16[_0x4773eb(0x14f)]&&_0x2423d7[_0x4773eb(0x16d)][_0x4773eb(0x151)]===_0xc18e16[_0x4773eb(0x151)]);if(!_0x502f47)return;_0x3ae397(_0x552976(_0x502f47['message']),{..._0x502f47,'ackSentAt':Date[_0x4773eb(0x18d)]()});});},async 'acceptHeld'(_0x27cea1){return _0x2bcd0e(()=>{const _0x57d542=_0x525c;_0x14f7cd(),_0x1e95a7();const _0x535160=_0x297d35(_0x57d542(0x17d))+_0x297d35(_0x57d542(0x178)),_0x3108e9=_0x5f3fa8(_0x27cea1,Math[_0x57d542(0x17b)](0x0,_0x8df9d9[_0x57d542(0x180)]-_0x535160));for(const _0x358f1a of _0x3108e9){const {heldAt:_0x50245a,expiresAt:_0x403e22,..._0x11d79}=_0x358f1a,_0x5cae5d=_0x1b8354(_0x57d542(0x19c),_0x358f1a);_0x3ae397(_0x4d768f(_0x11d79),{..._0x5cae5d??{'version':0x2,'acceptedAt':Date[_0x57d542(0x18d)](),'sequence':_0xbf4633()},'state':_0x57d542(0x17d),'message':_0x11d79,'heldAt':undefined,'expiresAt':undefined,'ack':undefined}),unlinkSync(_0x38ce92(_0x358f1a)),_0x28127b(dirname(_0x38ce92(_0x358f1a)));}return _0x179b44(),_0x1e95a7(),_0x3108e9;});},async 'dropHeld'(_0x171bf0){return _0x2bcd0e(()=>{const _0x189969=_0x525c;_0x14f7cd(),_0x1e95a7();const _0x2c4775=_0x5f3fa8(_0x171bf0);for(const _0xa0d6b0 of _0x2c4775)_0x34914e(_0xa0d6b0,_0x189969(0x19c),_0x189969(0x19f));return _0x1e95a7(),_0x2c4775[_0x189969(0x158)];});},async 'loadHeld'(){_0x2bcd0e(()=>{const _0x45dae8=_0x525c,_0x2d7aa9=join(_0x425b77,_0x45dae8(0x178));for(const _0x11c545 of _0x1c5f91(_0x45dae8(0x178))){const _0x37ff6f=_0x11c545[_0x45dae8(0x194)];!_0x1b8354('done',_0x37ff6f)&&_0x3ae397(_0x4d768f(_0x37ff6f),{..._0x11c545,'state':_0x45dae8(0x17d),'message':_0x37ff6f}),unlinkSync(_0x91bed3(_0x37ff6f)),_0x28127b(_0x2d7aa9);}const _0x342fe8=Date[_0x45dae8(0x18d)]()-_0x74b03e;for(const _0x222e6e of _0x1c5f91(_0x45dae8(0x14b))){typeof _0x222e6e[_0x45dae8(0x16d)]?.[_0x45dae8(0x1b3)]===_0x45dae8(0x152)&&_0x222e6e[_0x45dae8(0x16d)]['acknowledgedAt']<=_0x342fe8&&unlinkSync(_0x552976(_0x222e6e[_0x45dae8(0x194)]));}_0x179b44(),_0x1e95a7();try{renameSync(_0x8df9d9[_0x45dae8(0x170)],_0x8df9d9[_0x45dae8(0x170)]+_0x45dae8(0x184)+Date[_0x45dae8(0x18d)]());}catch(_0x331f5b){_0x331f5b[_0x45dae8(0x17a)]!==_0x45dae8(0x157)&&void _0x8df9d9['logger'](_0x45dae8(0x193),_0x45dae8(0x188),{'error':String(_0x331f5b)});}});},'withExclusiveLock'(_0x2efb54){return _0x2bcd0e(_0x2efb54);}};return _0x5a8ab3;}export function RateLimiter(_0x5e306a){const _0x55e812=new Map();return _0x4bbb1a=>{const _0x459687=_0x525c,_0x5ee618=Date[_0x459687(0x18d)](),_0x5c4890=_0x5ee618-0xea60,_0xf6004c=(_0x55e812[_0x459687(0x162)](_0x4bbb1a)??[])[_0x459687(0x161)](_0x1ee95c=>_0x1ee95c>_0x5c4890);if(_0xf6004c[_0x459687(0x158)]>=_0x5e306a)return _0x55e812[_0x459687(0x1b1)](_0x4bbb1a,_0xf6004c),![];return _0xf6004c[_0x459687(0x18c)](_0x5ee618),_0x55e812[_0x459687(0x1b1)](_0x4bbb1a,_0xf6004c),!![];};}
|
|
2
|
+
//# sourceMappingURL=.js.map
|