easy-ping 0.5.0 → 0.6.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 +548 -508
- package/dist/adapters/mongodb.cjs +142 -0
- package/dist/adapters/mongodb.cjs.map +1 -1
- package/dist/adapters/mongodb.d.cts +39 -1
- package/dist/adapters/mongodb.d.ts +39 -1
- package/dist/adapters/mongodb.js +73 -1
- package/dist/adapters/mongodb.js.map +1 -1
- package/dist/adapters/postgres.cjs +146 -0
- package/dist/adapters/postgres.cjs.map +1 -1
- package/dist/adapters/postgres.d.cts +36 -1
- package/dist/adapters/postgres.d.ts +36 -1
- package/dist/adapters/postgres.js +78 -3
- package/dist/adapters/postgres.js.map +1 -1
- package/dist/adapters/sqlite.js +1 -1
- package/dist/{chunk-GJNLOQJS.js → chunk-JKTMUMQK.js} +31 -6
- package/dist/chunk-JKTMUMQK.js.map +1 -0
- package/dist/chunk-ORZKH224.js +75 -0
- package/dist/chunk-ORZKH224.js.map +1 -0
- package/dist/{chunk-BECMTNK7.js → chunk-USQ6CQTJ.js} +88 -3
- package/dist/chunk-USQ6CQTJ.js.map +1 -0
- package/dist/client.cjs +288 -17
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +53 -1
- package/dist/client.d.ts +53 -1
- package/dist/client.js +288 -17
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +237 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +42 -1
- package/dist/index.d.ts +42 -1
- package/dist/index.js +55 -7
- package/dist/index.js.map +1 -1
- package/dist/node.cjs +26 -5
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.js +28 -6
- package/dist/node.js.map +1 -1
- package/dist/plugins/preferences.cjs.map +1 -1
- package/dist/plugins/preferences.js +2 -1
- package/dist/plugins/preferences.js.map +1 -1
- package/dist/plugins/push.cjs.map +1 -1
- package/dist/plugins/push.js +3 -2
- package/dist/plugins/push.js.map +1 -1
- package/dist/react.cjs +311 -19
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +52 -0
- package/dist/react.d.ts +52 -0
- package/dist/react.js +311 -19
- package/dist/react.js.map +1 -1
- package/dist/schema.js +1 -1
- package/dist/signals-kPmOlKDX.d.cts +27 -0
- package/dist/signals-kPmOlKDX.d.ts +27 -0
- package/dist/sw.cjs +39 -0
- package/dist/sw.cjs.map +1 -0
- package/dist/sw.d.cts +52 -0
- package/dist/sw.d.ts +52 -0
- package/dist/sw.js +36 -0
- package/dist/sw.js.map +1 -0
- package/package.json +6 -1
- package/dist/chunk-BECMTNK7.js.map +0 -1
- package/dist/chunk-GJNLOQJS.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -20,6 +20,9 @@ function decodeBase64Url(value) {
|
|
|
20
20
|
return bytes ? new TextDecoder().decode(bytes) : null;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
// src/core/config.ts
|
|
24
|
+
var INBOX_VERSION_HEADER = "x-easy-ping-inbox";
|
|
25
|
+
|
|
23
26
|
// src/core/definition.ts
|
|
24
27
|
function defineNotification(definition) {
|
|
25
28
|
return definition;
|
|
@@ -51,6 +54,78 @@ var consoleLogger = {
|
|
|
51
54
|
error: (message2, meta) => console.error(`[easy-ping] ${message2}`, meta ?? "")
|
|
52
55
|
};
|
|
53
56
|
|
|
57
|
+
// src/core/signals.ts
|
|
58
|
+
var DELIVERIES_CHANNEL = "deliveries";
|
|
59
|
+
var inboxChannel = (userId) => `inbox:${userId}`;
|
|
60
|
+
function createMemorySignals() {
|
|
61
|
+
const handlers = /* @__PURE__ */ new Map();
|
|
62
|
+
return {
|
|
63
|
+
crossProcess: false,
|
|
64
|
+
publish(channel) {
|
|
65
|
+
const set = handlers.get(channel);
|
|
66
|
+
if (!set) return;
|
|
67
|
+
for (const handler of [...set]) {
|
|
68
|
+
queueMicrotask(() => {
|
|
69
|
+
try {
|
|
70
|
+
handler();
|
|
71
|
+
} catch {
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
subscribe(channel, handler) {
|
|
77
|
+
let set = handlers.get(channel);
|
|
78
|
+
if (!set) {
|
|
79
|
+
set = /* @__PURE__ */ new Set();
|
|
80
|
+
handlers.set(channel, set);
|
|
81
|
+
}
|
|
82
|
+
set.add(handler);
|
|
83
|
+
return () => {
|
|
84
|
+
set?.delete(handler);
|
|
85
|
+
if (set?.size === 0) handlers.delete(channel);
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function createBridgedSignals(transport, onError) {
|
|
91
|
+
const local = createMemorySignals();
|
|
92
|
+
const remoteUnsubscribes = /* @__PURE__ */ new Map();
|
|
93
|
+
const counts = /* @__PURE__ */ new Map();
|
|
94
|
+
return {
|
|
95
|
+
crossProcess: true,
|
|
96
|
+
publish(channel) {
|
|
97
|
+
local.publish(channel);
|
|
98
|
+
Promise.resolve().then(() => transport.publish(channel)).catch(onError);
|
|
99
|
+
},
|
|
100
|
+
subscribe(channel, handler) {
|
|
101
|
+
const unsubscribeLocal = local.subscribe(channel, handler);
|
|
102
|
+
counts.set(channel, (counts.get(channel) ?? 0) + 1);
|
|
103
|
+
if (!remoteUnsubscribes.has(channel)) {
|
|
104
|
+
remoteUnsubscribes.set(
|
|
105
|
+
channel,
|
|
106
|
+
Promise.resolve().then(() => transport.subscribe(channel, () => local.publish(channel))).catch((error) => {
|
|
107
|
+
onError(error);
|
|
108
|
+
return () => {
|
|
109
|
+
};
|
|
110
|
+
})
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
return () => {
|
|
114
|
+
unsubscribeLocal();
|
|
115
|
+
const remaining = (counts.get(channel) ?? 1) - 1;
|
|
116
|
+
if (remaining > 0) {
|
|
117
|
+
counts.set(channel, remaining);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
counts.delete(channel);
|
|
121
|
+
const pending = remoteUnsubscribes.get(channel);
|
|
122
|
+
remoteUnsubscribes.delete(channel);
|
|
123
|
+
pending?.then((unsubscribe) => unsubscribe()).catch(onError);
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
54
129
|
// src/core/tokens.ts
|
|
55
130
|
var encoder = new TextEncoder();
|
|
56
131
|
var KEY_SALT = encoder.encode("easy-ping/tokens/v1");
|
|
@@ -304,6 +379,9 @@ function createHandler(deps) {
|
|
|
304
379
|
const userId = await resolveUserId(request);
|
|
305
380
|
if (userId === "error") return empty(500);
|
|
306
381
|
if (userId === null) return empty(401);
|
|
382
|
+
if (request.method === "GET" && path === "/events") {
|
|
383
|
+
return deps.events ? events(request, userId, deps.events) : empty(404);
|
|
384
|
+
}
|
|
307
385
|
if (request.method === "GET" && path === "/") {
|
|
308
386
|
const limitParam = Number(url.searchParams.get("limit") ?? 20);
|
|
309
387
|
const limit = Number.isFinite(limitParam) ? Math.min(Math.max(limitParam, 1), 100) : 20;
|
|
@@ -328,6 +406,7 @@ function createHandler(deps) {
|
|
|
328
406
|
const before = typeof parsed.body.before === "string" ? new Date(parsed.body.before) : null;
|
|
329
407
|
const cutoff = before && !Number.isNaN(before.getTime()) ? new Date(before.getTime() + 1) : /* @__PURE__ */ new Date();
|
|
330
408
|
await deps.adapter.markSeen(userId, cutoff);
|
|
409
|
+
deps.signals.publish(inboxChannel(userId));
|
|
331
410
|
return json({ ok: true });
|
|
332
411
|
}
|
|
333
412
|
if (request.method === "POST" && path === "/read") {
|
|
@@ -339,19 +418,99 @@ function createHandler(deps) {
|
|
|
339
418
|
return json({ error: `at most ${MAX_READ_IDS} ids per request` }, 400);
|
|
340
419
|
}
|
|
341
420
|
const updated = await deps.adapter.markRead(userId, ids);
|
|
421
|
+
if (updated > 0) deps.signals.publish(inboxChannel(userId));
|
|
342
422
|
return updated === 0 ? empty(404) : json({ updated });
|
|
343
423
|
}
|
|
344
424
|
if (request.method === "POST" && path === "/read-all") {
|
|
345
|
-
|
|
425
|
+
const updated = await deps.adapter.markAllRead(userId);
|
|
426
|
+
if (updated > 0) deps.signals.publish(inboxChannel(userId));
|
|
427
|
+
return json({ updated });
|
|
346
428
|
}
|
|
347
429
|
return empty(404);
|
|
348
430
|
}
|
|
431
|
+
async function fingerprint(userId) {
|
|
432
|
+
const [page, unseen] = await Promise.all([
|
|
433
|
+
deps.adapter.listNotifications({ userId, limit: 1 }),
|
|
434
|
+
deps.adapter.countUnseen(userId)
|
|
435
|
+
]);
|
|
436
|
+
const newest = page.notifications[0];
|
|
437
|
+
return `${newest?.id ?? ""}|${newest?.readAt ? 1 : 0}|${unseen}`;
|
|
438
|
+
}
|
|
439
|
+
function events(request, userId, settings) {
|
|
440
|
+
const encoder3 = new TextEncoder();
|
|
441
|
+
const timers = [];
|
|
442
|
+
let unsubscribe;
|
|
443
|
+
let closed = false;
|
|
444
|
+
let cleanup = () => {
|
|
445
|
+
};
|
|
446
|
+
const stream = new ReadableStream({
|
|
447
|
+
start(controller) {
|
|
448
|
+
const write = (text) => {
|
|
449
|
+
if (closed) return;
|
|
450
|
+
try {
|
|
451
|
+
controller.enqueue(encoder3.encode(text));
|
|
452
|
+
} catch {
|
|
453
|
+
cleanup();
|
|
454
|
+
}
|
|
455
|
+
};
|
|
456
|
+
cleanup = () => {
|
|
457
|
+
if (closed) return;
|
|
458
|
+
closed = true;
|
|
459
|
+
unsubscribe?.();
|
|
460
|
+
for (const timer of timers) clearInterval(timer);
|
|
461
|
+
try {
|
|
462
|
+
controller.close();
|
|
463
|
+
} catch {
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
const changed = () => write("event: changed\ndata: {}\n\n");
|
|
467
|
+
write("retry: 3000\n\nevent: ready\ndata: {}\n\n");
|
|
468
|
+
unsubscribe = deps.signals.subscribe(inboxChannel(userId), changed);
|
|
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
|
+
);
|
|
489
|
+
}
|
|
490
|
+
request.signal?.addEventListener("abort", cleanup, { once: true });
|
|
491
|
+
},
|
|
492
|
+
cancel() {
|
|
493
|
+
cleanup();
|
|
494
|
+
}
|
|
495
|
+
});
|
|
496
|
+
return new Response(stream, {
|
|
497
|
+
headers: {
|
|
498
|
+
"content-type": "text/event-stream; charset=utf-8",
|
|
499
|
+
"cache-control": "no-cache, no-store",
|
|
500
|
+
connection: "keep-alive",
|
|
501
|
+
"x-accel-buffering": "no",
|
|
502
|
+
"x-content-type-options": "nosniff"
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
}
|
|
349
506
|
async function handle(request) {
|
|
350
507
|
try {
|
|
351
508
|
return await route(request);
|
|
352
509
|
} catch (error) {
|
|
353
510
|
deps.logger.error("request failed", { url: request.url, error });
|
|
354
511
|
return empty(500);
|
|
512
|
+
} finally {
|
|
513
|
+
deps.sweepOnRequest?.();
|
|
355
514
|
}
|
|
356
515
|
}
|
|
357
516
|
return {
|
|
@@ -416,7 +575,7 @@ function backoffMs(attempt, strategy = "exponential") {
|
|
|
416
575
|
var nextAttemptAt = (attempt, strategy, now = /* @__PURE__ */ new Date()) => new Date(now.getTime() + backoffMs(attempt, strategy));
|
|
417
576
|
|
|
418
577
|
// src/core/runner.ts
|
|
419
|
-
var
|
|
578
|
+
var DEFAULT_WORKER_IDLE_MS = 1e4;
|
|
420
579
|
async function withTimeout(run, ms, label) {
|
|
421
580
|
const controller = new AbortController();
|
|
422
581
|
let timer;
|
|
@@ -605,22 +764,45 @@ function createRunner(deps) {
|
|
|
605
764
|
}
|
|
606
765
|
}
|
|
607
766
|
function startWorker(options = {}) {
|
|
608
|
-
const intervalMs = options.intervalMs ??
|
|
767
|
+
const intervalMs = options.intervalMs ?? DEFAULT_WORKER_IDLE_MS;
|
|
609
768
|
let stopped = false;
|
|
769
|
+
let wake;
|
|
770
|
+
let pending = false;
|
|
771
|
+
const unsubscribe = deps.signals?.subscribe(DELIVERIES_CHANNEL, () => {
|
|
772
|
+
pending = true;
|
|
773
|
+
wake?.();
|
|
774
|
+
});
|
|
775
|
+
const idle = (ms) => new Promise((resolve) => {
|
|
776
|
+
if (pending) {
|
|
777
|
+
pending = false;
|
|
778
|
+
resolve();
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
const timer = setTimeout(done, ms);
|
|
782
|
+
function done() {
|
|
783
|
+
clearTimeout(timer);
|
|
784
|
+
wake = void 0;
|
|
785
|
+
pending = false;
|
|
786
|
+
resolve();
|
|
787
|
+
}
|
|
788
|
+
wake = done;
|
|
789
|
+
});
|
|
610
790
|
const loop = (async () => {
|
|
611
791
|
while (!stopped) {
|
|
612
792
|
try {
|
|
613
793
|
const result = await runOnce({ limit: options.batchSize ?? deps.batchSize });
|
|
614
|
-
if (result.claimed === 0) await
|
|
794
|
+
if (result.claimed === 0 && !stopped) await idle(intervalMs);
|
|
615
795
|
} catch (error) {
|
|
616
796
|
deps.logger.error("worker sweep failed", { error });
|
|
617
|
-
await
|
|
797
|
+
if (!stopped) await idle(intervalMs);
|
|
618
798
|
}
|
|
619
799
|
}
|
|
620
800
|
})();
|
|
621
801
|
return {
|
|
622
802
|
stop: async () => {
|
|
623
803
|
stopped = true;
|
|
804
|
+
unsubscribe?.();
|
|
805
|
+
wake?.();
|
|
624
806
|
await loop;
|
|
625
807
|
}
|
|
626
808
|
};
|
|
@@ -958,6 +1140,7 @@ var CORE_ROUTES = [
|
|
|
958
1140
|
{ method: "POST", path: "/seen", scope: { type: "user" }, owner: "core" },
|
|
959
1141
|
{ method: "POST", path: "/read", scope: { type: "user" }, owner: "core" },
|
|
960
1142
|
{ method: "POST", path: "/read-all", scope: { type: "user" }, owner: "core" },
|
|
1143
|
+
{ method: "GET", path: "/events", scope: { type: "user" }, owner: "core" },
|
|
961
1144
|
{ method: "POST", path: "/cron", scope: { type: "machine" }, owner: "core" }
|
|
962
1145
|
];
|
|
963
1146
|
var DEFAULTS = {
|
|
@@ -1082,6 +1265,20 @@ function easyPing(config) {
|
|
|
1082
1265
|
}
|
|
1083
1266
|
}
|
|
1084
1267
|
for (const warning of warnings) logger.warn(warning);
|
|
1268
|
+
const baseSignals = config.signals ?? createMemorySignals();
|
|
1269
|
+
const inboxVersions = /* @__PURE__ */ new Map();
|
|
1270
|
+
const signals = {
|
|
1271
|
+
crossProcess: baseSignals.crossProcess,
|
|
1272
|
+
publish(channel) {
|
|
1273
|
+
if (channel.startsWith("inbox:")) {
|
|
1274
|
+
if (inboxVersions.size > 5e4) inboxVersions.clear();
|
|
1275
|
+
const userId = channel.slice("inbox:".length);
|
|
1276
|
+
inboxVersions.set(userId, (inboxVersions.get(userId) ?? 0) + 1);
|
|
1277
|
+
}
|
|
1278
|
+
baseSignals.publish(channel);
|
|
1279
|
+
},
|
|
1280
|
+
subscribe: (channel, handler2) => baseSignals.subscribe(channel, handler2)
|
|
1281
|
+
};
|
|
1085
1282
|
const runner = createRunner({
|
|
1086
1283
|
adapter: config.database,
|
|
1087
1284
|
definitions: config.notifications,
|
|
@@ -1091,15 +1288,34 @@ function easyPing(config) {
|
|
|
1091
1288
|
logger,
|
|
1092
1289
|
leaseMs,
|
|
1093
1290
|
batchSize: config.delivery?.batchSize ?? DEFAULTS.batchSize,
|
|
1094
|
-
backoff: config.delivery?.backoff ?? "exponential"
|
|
1291
|
+
backoff: config.delivery?.backoff ?? "exponential",
|
|
1292
|
+
signals
|
|
1095
1293
|
});
|
|
1096
1294
|
const pluginRoutes = plugins.flatMap((plugin) => plugin.routes ?? []);
|
|
1295
|
+
const events = config.events === false ? false : {
|
|
1296
|
+
heartbeatMs: config.events?.heartbeatMs ?? 25e3,
|
|
1297
|
+
probeIntervalMs: config.events?.probeIntervalMs ?? 3e4,
|
|
1298
|
+
maxDurationMs: config.events?.maxDurationMs ?? 0
|
|
1299
|
+
};
|
|
1300
|
+
const sweepConfig = config.delivery?.sweepOnRequest;
|
|
1301
|
+
let lastRequestSweep = 0;
|
|
1302
|
+
const sweepOnRequest = sweepConfig && mode !== "inline" ? () => {
|
|
1303
|
+
const settings = sweepConfig === true ? {} : sweepConfig;
|
|
1304
|
+
const now = Date.now();
|
|
1305
|
+
if (now - lastRequestSweep < (settings.everyMs ?? 5e3)) return;
|
|
1306
|
+
lastRequestSweep = now;
|
|
1307
|
+
const pass = runner.runOnce({ limit: settings.limit ?? 5 }).catch((error) => logger.error("request-driven sweep failed", { error }));
|
|
1308
|
+
config.delivery?.waitUntil?.(pass);
|
|
1309
|
+
} : void 0;
|
|
1097
1310
|
const handler = createHandler({
|
|
1098
1311
|
adapter: config.database,
|
|
1099
1312
|
session: config.session,
|
|
1100
1313
|
runner,
|
|
1101
1314
|
logger,
|
|
1102
1315
|
secret: config.secret,
|
|
1316
|
+
signals,
|
|
1317
|
+
events,
|
|
1318
|
+
sweepOnRequest,
|
|
1103
1319
|
basePath: config.basePath ?? DEFAULTS.basePath,
|
|
1104
1320
|
pluginRoutes,
|
|
1105
1321
|
trustedOrigins: config.trustedOrigins,
|
|
@@ -1131,6 +1347,10 @@ function easyPing(config) {
|
|
|
1131
1347
|
}
|
|
1132
1348
|
);
|
|
1133
1349
|
if (result.notifications.length > 0) {
|
|
1350
|
+
for (const notification of result.notifications) {
|
|
1351
|
+
signals.publish(inboxChannel(notification.userId));
|
|
1352
|
+
}
|
|
1353
|
+
signals.publish(DELIVERIES_CHANNEL);
|
|
1134
1354
|
const ids = result.notifications.flatMap(
|
|
1135
1355
|
(notification) => notification.deliveries.map((delivery) => delivery.id)
|
|
1136
1356
|
);
|
|
@@ -1163,8 +1383,13 @@ function easyPing(config) {
|
|
|
1163
1383
|
send,
|
|
1164
1384
|
handler,
|
|
1165
1385
|
startWorker: (options) => runner.startWorker(options ?? {}),
|
|
1386
|
+
inboxHeaders: (userId) => ({
|
|
1387
|
+
[INBOX_VERSION_HEADER]: String(inboxVersions.get(userId) ?? 0)
|
|
1388
|
+
}),
|
|
1166
1389
|
listRoutes: () => [
|
|
1167
|
-
...CORE_ROUTES.filter(
|
|
1390
|
+
...CORE_ROUTES.filter(
|
|
1391
|
+
(route) => (route.path !== "/cron" || Boolean(config.cron?.secret)) && (route.path !== "/events" || events !== false)
|
|
1392
|
+
),
|
|
1168
1393
|
...plugins.flatMap(
|
|
1169
1394
|
(plugin) => (plugin.routes ?? []).map((route) => ({
|
|
1170
1395
|
method: route.method,
|
|
@@ -1200,12 +1425,16 @@ function defineClientPlugin(plugin) {
|
|
|
1200
1425
|
|
|
1201
1426
|
exports.ConfigError = ConfigError;
|
|
1202
1427
|
exports.DEFAULT_TOKEN_TTL_SECONDS = DEFAULT_TOKEN_TTL_SECONDS;
|
|
1428
|
+
exports.DELIVERIES_CHANNEL = DELIVERIES_CHANNEL;
|
|
1203
1429
|
exports.EasyPingError = EasyPingError;
|
|
1430
|
+
exports.INBOX_VERSION_HEADER = INBOX_VERSION_HEADER;
|
|
1204
1431
|
exports.MAX_BODY_BYTES = MAX_BODY_BYTES;
|
|
1205
1432
|
exports.MAX_TOKEN_TTL_SECONDS = MAX_TOKEN_TTL_SECONDS;
|
|
1206
1433
|
exports.MIN_SECRET_LENGTH = MIN_SECRET_LENGTH;
|
|
1207
1434
|
exports.ValidationError = ValidationError;
|
|
1208
1435
|
exports.consoleLogger = consoleLogger;
|
|
1436
|
+
exports.createBridgedSignals = createBridgedSignals;
|
|
1437
|
+
exports.createMemorySignals = createMemorySignals;
|
|
1209
1438
|
exports.createRateLimiter = createRateLimiter;
|
|
1210
1439
|
exports.createRunner = createRunner;
|
|
1211
1440
|
exports.decodeBase64Url = decodeBase64Url;
|
|
@@ -1216,6 +1445,7 @@ exports.easyPing = easyPing;
|
|
|
1216
1445
|
exports.encodeBase64Url = encodeBase64Url;
|
|
1217
1446
|
exports.escapeHtml = escapeHtml;
|
|
1218
1447
|
exports.expiresIn = expiresIn;
|
|
1448
|
+
exports.inboxChannel = inboxChannel;
|
|
1219
1449
|
exports.readJsonBody = readJsonBody;
|
|
1220
1450
|
exports.redactErrorMessage = redactErrorMessage;
|
|
1221
1451
|
exports.signToken = signToken;
|