easy-ping 0.6.0 → 0.7.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 +21 -5
- package/dist/{adapter-D3lTy-4E.d.cts → adapter-BJ8Iejvs.d.cts} +1 -1
- package/dist/{adapter-D3lTy-4E.d.ts → adapter-BJ8Iejvs.d.ts} +1 -1
- package/dist/adapters/drizzle.d.cts +1 -1
- package/dist/adapters/drizzle.d.ts +1 -1
- package/dist/adapters/mongodb.d.cts +2 -2
- package/dist/adapters/mongodb.d.ts +2 -2
- package/dist/adapters/mysql.d.cts +2 -2
- package/dist/adapters/mysql.d.ts +2 -2
- package/dist/adapters/postgres.d.cts +2 -2
- package/dist/adapters/postgres.d.ts +2 -2
- package/dist/adapters/sqlite.d.cts +2 -2
- package/dist/adapters/sqlite.d.ts +2 -2
- package/dist/{chunk-USQ6CQTJ.js → chunk-JOVIZXO6.js} +105 -54
- package/dist/chunk-JOVIZXO6.js.map +1 -0
- package/dist/chunk-R3BE67L7.js +13 -0
- package/dist/chunk-R3BE67L7.js.map +1 -0
- package/dist/chunk-SSHVZHSJ.js +100 -0
- package/dist/chunk-SSHVZHSJ.js.map +1 -0
- package/dist/client.cjs +12 -3
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +6 -0
- package/dist/client.d.ts +6 -0
- package/dist/client.js +12 -3
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +106 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -4
- package/dist/index.d.ts +8 -4
- package/dist/index.js +7 -14
- package/dist/index.js.map +1 -1
- package/dist/node.cjs.map +1 -1
- package/dist/node.js +1 -1
- package/dist/{plugin-Cg9usuUi.d.ts → plugin-CSLKKgXT.d.ts} +1 -1
- package/dist/{plugin-CHd2ZiGC.d.cts → plugin-Wwp1nvo0.d.cts} +1 -1
- package/dist/plugins/digests.d.cts +2 -2
- package/dist/plugins/digests.d.ts +2 -2
- package/dist/plugins/preferences-client.d.cts +2 -2
- package/dist/plugins/preferences-client.d.ts +2 -2
- package/dist/plugins/preferences-react.d.cts +1 -1
- package/dist/plugins/preferences-react.d.ts +1 -1
- package/dist/plugins/preferences.cjs +3 -3
- package/dist/plugins/preferences.cjs.map +1 -1
- package/dist/plugins/preferences.d.cts +2 -2
- package/dist/plugins/preferences.d.ts +2 -2
- package/dist/plugins/preferences.js +2 -2
- package/dist/plugins/preferences.js.map +1 -1
- package/dist/plugins/push.cjs +2 -2
- package/dist/plugins/push.cjs.map +1 -1
- package/dist/plugins/push.d.cts +2 -2
- package/dist/plugins/push.d.ts +2 -2
- package/dist/plugins/push.js +1 -1
- package/dist/plugins/telegram.cjs +379 -0
- package/dist/plugins/telegram.cjs.map +1 -0
- package/dist/plugins/telegram.d.cts +153 -0
- package/dist/plugins/telegram.d.ts +153 -0
- package/dist/plugins/telegram.js +313 -0
- package/dist/plugins/telegram.js.map +1 -0
- package/dist/providers/telegram.cjs +103 -0
- package/dist/providers/telegram.cjs.map +1 -0
- package/dist/providers/telegram.d.cts +83 -0
- package/dist/providers/telegram.d.ts +83 -0
- package/dist/providers/telegram.js +3 -0
- package/dist/providers/telegram.js.map +1 -0
- package/dist/providers/web-push.d.cts +2 -2
- package/dist/providers/web-push.d.ts +2 -2
- package/dist/react.cjs +12 -3
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +6 -0
- package/dist/react.d.ts +6 -0
- package/dist/react.js +12 -3
- package/dist/react.js.map +1 -1
- package/dist/schema.d.cts +2 -2
- package/dist/schema.d.ts +2 -2
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/package.json +16 -4
- package/dist/chunk-USQ6CQTJ.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -206,15 +206,16 @@ function createScopedSigner(secret, pluginId, purposes, onViolation) {
|
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
// src/core/handler.ts
|
|
209
|
+
var STREAM_HIGH_WATER_MARK = 256;
|
|
209
210
|
var MAX_BODY_BYTES = 64 * 1024;
|
|
210
211
|
var MAX_READ_IDS = 200;
|
|
211
212
|
var PRIVATE_HEADERS = {
|
|
212
213
|
"cache-control": "private, no-store",
|
|
213
214
|
"x-content-type-options": "nosniff"
|
|
214
215
|
};
|
|
215
|
-
var json = (body, status = 200) => new Response(JSON.stringify(body), {
|
|
216
|
+
var json = (body, status = 200, headers = {}) => new Response(JSON.stringify(body), {
|
|
216
217
|
status,
|
|
217
|
-
headers: { "content-type": "application/json", ...PRIVATE_HEADERS }
|
|
218
|
+
headers: { "content-type": "application/json", ...PRIVATE_HEADERS, ...headers }
|
|
218
219
|
});
|
|
219
220
|
var empty = (status) => new Response(null, { status, headers: PRIVATE_HEADERS });
|
|
220
221
|
function harden(response) {
|
|
@@ -380,7 +381,14 @@ function createHandler(deps) {
|
|
|
380
381
|
if (userId === "error") return empty(500);
|
|
381
382
|
if (userId === null) return empty(401);
|
|
382
383
|
if (request.method === "GET" && path === "/events") {
|
|
383
|
-
|
|
384
|
+
if (!deps.events) return empty(404);
|
|
385
|
+
if ((openStreams.get(userId) ?? 0) >= deps.events.maxStreamsPerUser) {
|
|
386
|
+
return json({ error: "too many open event streams" }, 429, { "retry-after": "30" });
|
|
387
|
+
}
|
|
388
|
+
if (totalStreams >= deps.events.maxStreams) {
|
|
389
|
+
return json({ error: "event streams unavailable" }, 503, { "retry-after": "30" });
|
|
390
|
+
}
|
|
391
|
+
return events(request, userId, deps.events);
|
|
384
392
|
}
|
|
385
393
|
if (request.method === "GET" && path === "/") {
|
|
386
394
|
const limitParam = Number(url.searchParams.get("limit") ?? 20);
|
|
@@ -428,6 +436,18 @@ function createHandler(deps) {
|
|
|
428
436
|
}
|
|
429
437
|
return empty(404);
|
|
430
438
|
}
|
|
439
|
+
const openStreams = /* @__PURE__ */ new Map();
|
|
440
|
+
let totalStreams = 0;
|
|
441
|
+
const trackStream = (userId) => {
|
|
442
|
+
openStreams.set(userId, (openStreams.get(userId) ?? 0) + 1);
|
|
443
|
+
totalStreams += 1;
|
|
444
|
+
return () => {
|
|
445
|
+
const remaining = (openStreams.get(userId) ?? 1) - 1;
|
|
446
|
+
if (remaining > 0) openStreams.set(userId, remaining);
|
|
447
|
+
else openStreams.delete(userId);
|
|
448
|
+
totalStreams -= 1;
|
|
449
|
+
};
|
|
450
|
+
};
|
|
431
451
|
async function fingerprint(userId) {
|
|
432
452
|
const [page, unseen] = await Promise.all([
|
|
433
453
|
deps.adapter.listNotifications({ userId, limit: 1 }),
|
|
@@ -436,63 +456,92 @@ function createHandler(deps) {
|
|
|
436
456
|
const newest = page.notifications[0];
|
|
437
457
|
return `${newest?.id ?? ""}|${newest?.readAt ? 1 : 0}|${unseen}`;
|
|
438
458
|
}
|
|
459
|
+
const probes = /* @__PURE__ */ new Map();
|
|
460
|
+
function subscribeProbe(userId, onChanged, intervalMs) {
|
|
461
|
+
let probe = probes.get(userId);
|
|
462
|
+
if (!probe) {
|
|
463
|
+
const created = {
|
|
464
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
465
|
+
timer: setInterval(() => {
|
|
466
|
+
fingerprint(userId).then((value) => {
|
|
467
|
+
if (created.last !== void 0 && value !== created.last) {
|
|
468
|
+
for (const listener of created.listeners) listener();
|
|
469
|
+
}
|
|
470
|
+
created.last = value;
|
|
471
|
+
}).catch((error) => deps.logger.error("events probe failed", { error }));
|
|
472
|
+
}, intervalMs)
|
|
473
|
+
};
|
|
474
|
+
probe = created;
|
|
475
|
+
probes.set(userId, created);
|
|
476
|
+
fingerprint(userId).then((value) => {
|
|
477
|
+
if (created.last === void 0) created.last = value;
|
|
478
|
+
}).catch(() => {
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
probe.listeners.add(onChanged);
|
|
482
|
+
return () => {
|
|
483
|
+
const current = probes.get(userId);
|
|
484
|
+
if (!current) return;
|
|
485
|
+
current.listeners.delete(onChanged);
|
|
486
|
+
if (current.listeners.size === 0) {
|
|
487
|
+
clearInterval(current.timer);
|
|
488
|
+
probes.delete(userId);
|
|
489
|
+
}
|
|
490
|
+
};
|
|
491
|
+
}
|
|
439
492
|
function events(request, userId, settings) {
|
|
440
493
|
const encoder3 = new TextEncoder();
|
|
441
494
|
const timers = [];
|
|
442
|
-
|
|
495
|
+
const unsubscribes = [];
|
|
443
496
|
let closed = false;
|
|
444
497
|
let cleanup = () => {
|
|
445
498
|
};
|
|
446
|
-
const stream = new ReadableStream(
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
controller.
|
|
452
|
-
|
|
453
|
-
|
|
499
|
+
const stream = new ReadableStream(
|
|
500
|
+
{
|
|
501
|
+
start(controller) {
|
|
502
|
+
const write = (text) => {
|
|
503
|
+
if (closed) return;
|
|
504
|
+
if (controller.desiredSize !== null && controller.desiredSize <= 0) {
|
|
505
|
+
cleanup();
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
try {
|
|
509
|
+
controller.enqueue(encoder3.encode(text));
|
|
510
|
+
} catch {
|
|
511
|
+
cleanup();
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
cleanup = () => {
|
|
515
|
+
if (closed) return;
|
|
516
|
+
closed = true;
|
|
517
|
+
for (const unsubscribe of unsubscribes) unsubscribe();
|
|
518
|
+
for (const timer of timers) clearInterval(timer);
|
|
519
|
+
try {
|
|
520
|
+
controller.close();
|
|
521
|
+
} catch {
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
const changed = () => write("event: changed\ndata: {}\n\n");
|
|
525
|
+
unsubscribes.push(trackStream(userId));
|
|
526
|
+
write("retry: 3000\n\nevent: ready\ndata: {}\n\n");
|
|
527
|
+
unsubscribes.push(deps.signals.subscribe(inboxChannel(userId), changed));
|
|
528
|
+
timers.push(setInterval(() => write(": keepalive\n\n"), settings.heartbeatMs));
|
|
529
|
+
if (!deps.signals.crossProcess && settings.probeIntervalMs > 0) {
|
|
530
|
+
unsubscribes.push(subscribeProbe(userId, changed, settings.probeIntervalMs));
|
|
454
531
|
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
unsubscribe?.();
|
|
460
|
-
for (const timer of timers) clearInterval(timer);
|
|
461
|
-
try {
|
|
462
|
-
controller.close();
|
|
463
|
-
} catch {
|
|
532
|
+
if (settings.maxDurationMs > 0) {
|
|
533
|
+
timers.push(
|
|
534
|
+
setTimeout(cleanup, settings.maxDurationMs)
|
|
535
|
+
);
|
|
464
536
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
timers.push(setInterval(() => write(": keepalive\n\n"), settings.heartbeatMs));
|
|
470
|
-
if (!deps.signals.crossProcess && settings.probeIntervalMs > 0) {
|
|
471
|
-
let last;
|
|
472
|
-
fingerprint(userId).then((value) => {
|
|
473
|
-
last = value;
|
|
474
|
-
}).catch(() => {
|
|
475
|
-
});
|
|
476
|
-
timers.push(
|
|
477
|
-
setInterval(() => {
|
|
478
|
-
fingerprint(userId).then((value) => {
|
|
479
|
-
if (last !== void 0 && value !== last) changed();
|
|
480
|
-
last = value;
|
|
481
|
-
}).catch((error) => deps.logger.error("events probe failed", { error }));
|
|
482
|
-
}, settings.probeIntervalMs)
|
|
483
|
-
);
|
|
484
|
-
}
|
|
485
|
-
if (settings.maxDurationMs > 0) {
|
|
486
|
-
timers.push(
|
|
487
|
-
setTimeout(cleanup, settings.maxDurationMs)
|
|
488
|
-
);
|
|
537
|
+
request.signal?.addEventListener("abort", cleanup, { once: true });
|
|
538
|
+
},
|
|
539
|
+
cancel() {
|
|
540
|
+
cleanup();
|
|
489
541
|
}
|
|
490
|
-
request.signal?.addEventListener("abort", cleanup, { once: true });
|
|
491
542
|
},
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
}
|
|
495
|
-
});
|
|
543
|
+
{ highWaterMark: STREAM_HIGH_WATER_MARK }
|
|
544
|
+
);
|
|
496
545
|
return new Response(stream, {
|
|
497
546
|
headers: {
|
|
498
547
|
"content-type": "text/event-stream; charset=utf-8",
|
|
@@ -504,13 +553,15 @@ function createHandler(deps) {
|
|
|
504
553
|
});
|
|
505
554
|
}
|
|
506
555
|
async function handle(request) {
|
|
556
|
+
let response;
|
|
507
557
|
try {
|
|
508
|
-
|
|
558
|
+
response = await route(request);
|
|
559
|
+
return response;
|
|
509
560
|
} catch (error) {
|
|
510
561
|
deps.logger.error("request failed", { url: request.url, error });
|
|
511
562
|
return empty(500);
|
|
512
563
|
} finally {
|
|
513
|
-
deps.sweepOnRequest?.();
|
|
564
|
+
if (response && response.status < 400) deps.sweepOnRequest?.();
|
|
514
565
|
}
|
|
515
566
|
}
|
|
516
567
|
return {
|
|
@@ -1295,7 +1346,9 @@ function easyPing(config) {
|
|
|
1295
1346
|
const events = config.events === false ? false : {
|
|
1296
1347
|
heartbeatMs: config.events?.heartbeatMs ?? 25e3,
|
|
1297
1348
|
probeIntervalMs: config.events?.probeIntervalMs ?? 3e4,
|
|
1298
|
-
maxDurationMs: config.events?.maxDurationMs ?? 0
|
|
1349
|
+
maxDurationMs: config.events?.maxDurationMs ?? 0,
|
|
1350
|
+
maxStreamsPerUser: config.events?.maxStreamsPerUser ?? 10,
|
|
1351
|
+
maxStreams: config.events?.maxStreams ?? 5e3
|
|
1299
1352
|
};
|
|
1300
1353
|
const sweepConfig = config.delivery?.sweepOnRequest;
|
|
1301
1354
|
let lastRequestSweep = 0;
|