@voltro/plugin-notifications 0.24.0 → 0.26.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/CHANGELOG.md +670 -0
- package/dist/index.d.ts +28 -1
- package/dist/index.js +220 -158
- package/dist/rpc.d.ts +22 -0
- package/dist/rpc.js +24 -8
- package/dist/web.d.ts +2 -0
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Context as
|
|
3
|
-
import { and as
|
|
4
|
-
import { definePlugin as
|
|
5
|
-
import { randomUUID as
|
|
1
|
+
import { archiveDescriptor as e, clearQuietHoursDescriptor as t, inboxDescriptor as n, markAllReadDescriptor as r, markReadDescriptor as i, markUnreadDescriptor as a, notificationsRpcClientImports as o, preferencesDescriptor as s, setPreferenceDescriptor as c, setQuietHoursDescriptor as l, subscribeDescriptor as u, unarchiveDescriptor as ee, unreadCountDescriptor as d, unsubscribeDescriptor as te } from "./rpc.js";
|
|
2
|
+
import { Context as f, Effect as p, Layer as m, Schema as h } from "effect";
|
|
3
|
+
import { and as g, boolean as _, eq as v, generateId as y, id as b, integer as x, isNotNull as ne, isNull as S, json as C, lte as w, registerRetention as T, retentionTtlMsFromEnv as E, table as D, text as O, timestamp as k } from "@voltro/database";
|
|
4
|
+
import { definePlugin as A } from "@voltro/protocol";
|
|
5
|
+
import { randomUUID as j } from "node:crypto";
|
|
6
6
|
//#region src/errors.ts
|
|
7
|
-
var
|
|
8
|
-
token:
|
|
9
|
-
reason:
|
|
10
|
-
}) {},
|
|
7
|
+
var M = class extends h.TaggedError()("PushTokenRejected", {
|
|
8
|
+
token: h.String,
|
|
9
|
+
reason: h.String
|
|
10
|
+
}) {}, N = () => ({
|
|
11
11
|
id: "console",
|
|
12
12
|
deliver: async (e) => {
|
|
13
13
|
process.stdout.write(`[notify:${e.category}] → ${e.to}: ${e.title} — ${e.body}\n`);
|
|
14
14
|
}
|
|
15
|
-
}),
|
|
15
|
+
}), P = (e) => ({
|
|
16
16
|
id: e.id ?? "slack",
|
|
17
17
|
deliver: async (t) => {
|
|
18
18
|
let n = e.format ? e.format(t) : { text: `*${t.title}*\n${t.body}` }, r = await fetch(e.url, {
|
|
@@ -25,7 +25,7 @@ var A = class extends p.TaggedError()("PushTokenRejected", {
|
|
|
25
25
|
});
|
|
26
26
|
if (!r.ok) throw Error(`webhook ${e.id ?? "slack"} POST ${r.status}`);
|
|
27
27
|
}
|
|
28
|
-
}),
|
|
28
|
+
}), F = (e) => ({
|
|
29
29
|
id: "email",
|
|
30
30
|
deliver: (t) => e({
|
|
31
31
|
to: t.to,
|
|
@@ -33,13 +33,13 @@ var A = class extends p.TaggedError()("PushTokenRejected", {
|
|
|
33
33
|
html: `<p>${t.body}</p>`,
|
|
34
34
|
text: t.body
|
|
35
35
|
})
|
|
36
|
-
}),
|
|
36
|
+
}), I = (e) => ({
|
|
37
37
|
id: "sms",
|
|
38
38
|
deliver: (t) => e(t.to, `${t.title}: ${t.body}`)
|
|
39
|
-
}),
|
|
39
|
+
}), re = (e, t) => ({
|
|
40
40
|
id: e,
|
|
41
41
|
deliver: t
|
|
42
|
-
}),
|
|
42
|
+
}), ie = (e) => ({
|
|
43
43
|
id: e.id ?? "push",
|
|
44
44
|
deliver: async (t) => {
|
|
45
45
|
let n = await e.tokensFor(t.to), r = t.data?.badge, i = typeof r == "number" ? r : void 0;
|
|
@@ -54,7 +54,7 @@ var A = class extends p.TaggedError()("PushTokenRejected", {
|
|
|
54
54
|
try {
|
|
55
55
|
await e.transport(n);
|
|
56
56
|
} catch (e) {
|
|
57
|
-
throw e instanceof
|
|
57
|
+
throw e instanceof M ? e : new M({
|
|
58
58
|
token: r,
|
|
59
59
|
reason: e instanceof Error ? e.message : String(e)
|
|
60
60
|
});
|
|
@@ -71,6 +71,7 @@ var A = class extends p.TaggedError()("PushTokenRejected", {
|
|
|
71
71
|
e.unshift({
|
|
72
72
|
...t,
|
|
73
73
|
readAt: null,
|
|
74
|
+
archivedAt: null,
|
|
74
75
|
data: t.data ?? {},
|
|
75
76
|
tenantId: t.tenantId ?? null
|
|
76
77
|
});
|
|
@@ -86,6 +87,31 @@ var A = class extends p.TaggedError()("PushTokenRejected", {
|
|
|
86
87
|
readAt: (/* @__PURE__ */ new Date(0)).toISOString()
|
|
87
88
|
}, !0);
|
|
88
89
|
},
|
|
90
|
+
markUnread: async (t, n) => {
|
|
91
|
+
let r = e.findIndex((e) => e.id === t && e.subjectId === n);
|
|
92
|
+
return r === -1 ? !1 : (e[r] = {
|
|
93
|
+
...e[r],
|
|
94
|
+
readAt: null
|
|
95
|
+
}, !0);
|
|
96
|
+
},
|
|
97
|
+
markAllRead: async (t) => {
|
|
98
|
+
let n = 0;
|
|
99
|
+
for (let r = 0; r < e.length; r++) {
|
|
100
|
+
let i = e[r];
|
|
101
|
+
i.subjectId !== t || i.readAt !== null || (e[r] = {
|
|
102
|
+
...i,
|
|
103
|
+
readAt: (/* @__PURE__ */ new Date(0)).toISOString()
|
|
104
|
+
}, n++);
|
|
105
|
+
}
|
|
106
|
+
return n;
|
|
107
|
+
},
|
|
108
|
+
setArchived: async (t, n, r) => {
|
|
109
|
+
let i = e.findIndex((e) => e.id === t && e.subjectId === n);
|
|
110
|
+
return i === -1 ? !1 : (e[i] = {
|
|
111
|
+
...e[i],
|
|
112
|
+
archivedAt: r ? (/* @__PURE__ */ new Date(0)).toISOString() : null
|
|
113
|
+
}, !0);
|
|
114
|
+
},
|
|
89
115
|
unreadCount: async (t) => e.filter((e) => e.subjectId === t && e.readAt === null).length,
|
|
90
116
|
getPreferences: async (e) => [...t.values()].filter((t) => t.subjectId === e),
|
|
91
117
|
setPreference: async (e) => {
|
|
@@ -135,6 +161,7 @@ var A = class extends p.TaggedError()("PushTokenRejected", {
|
|
|
135
161
|
body: String(e.body),
|
|
136
162
|
data: e.data ?? {},
|
|
137
163
|
readAt: e.readAt == null ? null : z(e.readAt),
|
|
164
|
+
archivedAt: e.archivedAt == null ? null : z(e.archivedAt),
|
|
138
165
|
createdAt: z(e.createdAt),
|
|
139
166
|
tenantId: e.tenantId ?? null
|
|
140
167
|
}), r = (e) => ({
|
|
@@ -182,22 +209,30 @@ var A = class extends p.TaggedError()("PushTokenRejected", {
|
|
|
182
209
|
body: t.body,
|
|
183
210
|
data: t.data ?? {},
|
|
184
211
|
readAt: null,
|
|
212
|
+
archivedAt: null,
|
|
185
213
|
createdAt: t.createdAt,
|
|
186
214
|
tenantId: t.tenantId ?? null
|
|
187
215
|
});
|
|
188
216
|
},
|
|
189
217
|
listInbox: async (e, r) => {
|
|
190
|
-
let i = r?.unreadOnly ?
|
|
218
|
+
let i = r?.unreadOnly ? g(v("subjectId", e), S("readAt")) : v("subjectId", e);
|
|
191
219
|
return (await t("_voltro_notification_inbox", i, [{
|
|
192
220
|
column: "createdAt",
|
|
193
221
|
direction: "desc"
|
|
194
222
|
}], r?.limit)).map(n);
|
|
195
223
|
},
|
|
196
|
-
markRead: async (n, r) => (await t("_voltro_notification_inbox",
|
|
197
|
-
|
|
198
|
-
|
|
224
|
+
markRead: async (n, r) => (await t("_voltro_notification_inbox", g(v("id", n), v("subjectId", r)), [], 1))[0] ? (await e.update("_voltro_notification_inbox", n, { readAt: (/* @__PURE__ */ new Date()).toISOString() }), !0) : !1,
|
|
225
|
+
markUnread: async (n, r) => (await t("_voltro_notification_inbox", g(v("id", n), v("subjectId", r)), [], 1))[0] ? (await e.update("_voltro_notification_inbox", n, { readAt: null }), !0) : !1,
|
|
226
|
+
markAllRead: async (n) => {
|
|
227
|
+
let r = await t("_voltro_notification_inbox", g(v("subjectId", n), S("readAt")), [], void 0), i = (/* @__PURE__ */ new Date()).toISOString();
|
|
228
|
+
for (let t of r) await e.update("_voltro_notification_inbox", String(t.id), { readAt: i });
|
|
229
|
+
return r.length;
|
|
230
|
+
},
|
|
231
|
+
setArchived: async (n, r, i) => (await t("_voltro_notification_inbox", g(v("id", n), v("subjectId", r)), [], 1))[0] ? (await e.update("_voltro_notification_inbox", n, { archivedAt: i ? (/* @__PURE__ */ new Date()).toISOString() : null }), !0) : !1,
|
|
232
|
+
unreadCount: async (e) => (await t("_voltro_notification_inbox", g(v("subjectId", e), S("readAt")), [], void 0)).length,
|
|
233
|
+
getPreferences: async (e) => (await t("_voltro_notification_preferences", v("subjectId", e), [], void 0)).map(r),
|
|
199
234
|
setPreference: async (t) => {
|
|
200
|
-
let n =
|
|
235
|
+
let n = y({
|
|
201
236
|
kind: "typeid",
|
|
202
237
|
prefix: "notifpref"
|
|
203
238
|
}, "_voltro_notification_preferences");
|
|
@@ -232,7 +267,7 @@ var A = class extends p.TaggedError()("PushTokenRejected", {
|
|
|
232
267
|
direction: "desc"
|
|
233
268
|
}], e?.limit)).map(i),
|
|
234
269
|
subscribeTopic: async (t) => {
|
|
235
|
-
let n =
|
|
270
|
+
let n = y({
|
|
236
271
|
kind: "typeid",
|
|
237
272
|
prefix: "notiftsub"
|
|
238
273
|
}, "_voltro_notification_topic_subscriptions");
|
|
@@ -247,16 +282,16 @@ var A = class extends p.TaggedError()("PushTokenRejected", {
|
|
|
247
282
|
});
|
|
248
283
|
},
|
|
249
284
|
unsubscribeTopic: async (n, r) => {
|
|
250
|
-
let i = await t("_voltro_notification_topic_subscriptions",
|
|
285
|
+
let i = await t("_voltro_notification_topic_subscriptions", g(v("topic", n), v("subjectId", r)), [], 1);
|
|
251
286
|
i[0] && await e.delete("_voltro_notification_topic_subscriptions", String(i[0].id));
|
|
252
287
|
},
|
|
253
|
-
listTopicSubscribers: async (e) => (await t("_voltro_notification_topic_subscriptions",
|
|
288
|
+
listTopicSubscribers: async (e) => (await t("_voltro_notification_topic_subscriptions", v("topic", e), [], void 0)).map(a),
|
|
254
289
|
getQuietHours: async (e) => {
|
|
255
|
-
let n = await t("_voltro_notification_quiet_hours",
|
|
290
|
+
let n = await t("_voltro_notification_quiet_hours", v("subjectId", e), [], 1);
|
|
256
291
|
return n[0] ? o(n[0]) : null;
|
|
257
292
|
},
|
|
258
293
|
setQuietHours: async (t) => {
|
|
259
|
-
let n =
|
|
294
|
+
let n = y({
|
|
260
295
|
kind: "typeid",
|
|
261
296
|
prefix: "notifqh"
|
|
262
297
|
}, "_voltro_notification_quiet_hours");
|
|
@@ -278,7 +313,7 @@ var A = class extends p.TaggedError()("PushTokenRejected", {
|
|
|
278
313
|
});
|
|
279
314
|
},
|
|
280
315
|
clearQuietHours: async (n) => {
|
|
281
|
-
let r = await t("_voltro_notification_quiet_hours",
|
|
316
|
+
let r = await t("_voltro_notification_quiet_hours", v("subjectId", n), [], 1);
|
|
282
317
|
r[0] && await e.delete("_voltro_notification_quiet_hours", String(r[0].id));
|
|
283
318
|
},
|
|
284
319
|
enqueueHeld: async (t) => {
|
|
@@ -290,11 +325,11 @@ var A = class extends p.TaggedError()("PushTokenRejected", {
|
|
|
290
325
|
flushAt: t.flushAt
|
|
291
326
|
});
|
|
292
327
|
},
|
|
293
|
-
pendingDigest: async (e) => (await t("_voltro_notification_held",
|
|
328
|
+
pendingDigest: async (e) => (await t("_voltro_notification_held", g(v("kind", "digest"), v("subjectId", e)), [{
|
|
294
329
|
column: "flushAt",
|
|
295
330
|
direction: "asc"
|
|
296
331
|
}], void 0)).map(s),
|
|
297
|
-
dueHeld: async (e) => (await t("_voltro_notification_held",
|
|
332
|
+
dueHeld: async (e) => (await t("_voltro_notification_held", w("flushAt", e), [{
|
|
298
333
|
column: "flushAt",
|
|
299
334
|
direction: "asc"
|
|
300
335
|
}], void 0)).map(s),
|
|
@@ -306,7 +341,7 @@ var A = class extends p.TaggedError()("PushTokenRejected", {
|
|
|
306
341
|
id: "inApp",
|
|
307
342
|
deliver: async (t) => {
|
|
308
343
|
await e.addInbox({
|
|
309
|
-
id:
|
|
344
|
+
id: j(),
|
|
310
345
|
subjectId: t.to,
|
|
311
346
|
category: t.category,
|
|
312
347
|
title: t.title,
|
|
@@ -349,7 +384,7 @@ var A = class extends p.TaggedError()("PushTokenRejected", {
|
|
|
349
384
|
let a = t.get(n);
|
|
350
385
|
if (!a) continue;
|
|
351
386
|
let o = {
|
|
352
|
-
id:
|
|
387
|
+
id: j(),
|
|
353
388
|
to: i.to,
|
|
354
389
|
category: i.category,
|
|
355
390
|
channel: n,
|
|
@@ -385,7 +420,7 @@ var A = class extends p.TaggedError()("PushTokenRejected", {
|
|
|
385
420
|
skipped: [],
|
|
386
421
|
held: "quiet-drop"
|
|
387
422
|
} : (await e.store.enqueueHeld({
|
|
388
|
-
id:
|
|
423
|
+
id: j(),
|
|
389
424
|
kind: "quiet",
|
|
390
425
|
subjectId: t.to,
|
|
391
426
|
send: t,
|
|
@@ -399,7 +434,7 @@ var A = class extends p.TaggedError()("PushTokenRejected", {
|
|
|
399
434
|
if (i > 0 && !t.channels) {
|
|
400
435
|
let n = (await e.store.pendingDigest(t.to))[0]?.flushAt ?? new Date(o.getTime() + i).toISOString();
|
|
401
436
|
return await e.store.enqueueHeld({
|
|
402
|
-
id:
|
|
437
|
+
id: j(),
|
|
403
438
|
kind: "digest",
|
|
404
439
|
subjectId: t.to,
|
|
405
440
|
send: t,
|
|
@@ -418,6 +453,9 @@ var A = class extends p.TaggedError()("PushTokenRejected", {
|
|
|
418
453
|
inbox: (t, n) => e.store.listInbox(t, n),
|
|
419
454
|
unreadCount: (t) => e.store.unreadCount(t),
|
|
420
455
|
markRead: (t, n) => e.store.markRead(t, n),
|
|
456
|
+
markUnread: (t, n) => e.store.markUnread(t, n),
|
|
457
|
+
markAllRead: (t) => e.store.markAllRead(t),
|
|
458
|
+
setArchived: (t, n, r) => e.store.setArchived(t, n, r),
|
|
421
459
|
getPreferences: (t) => e.store.getPreferences(t),
|
|
422
460
|
setPreference: (t) => e.store.setPreference(t),
|
|
423
461
|
subscribe: (t, n, r) => e.store.subscribeTopic({
|
|
@@ -450,11 +488,11 @@ var A = class extends p.TaggedError()("PushTokenRejected", {
|
|
|
450
488
|
let t = i.get(e.subjectId) ?? [];
|
|
451
489
|
t.push(e), i.set(e.subjectId, t);
|
|
452
490
|
}
|
|
453
|
-
for (let [e, t] of i) await a(
|
|
491
|
+
for (let [e, t] of i) await a(ae(e, t));
|
|
454
492
|
return await e.store.clearHeld(n.map((e) => e.id)), n.length;
|
|
455
493
|
}
|
|
456
494
|
};
|
|
457
|
-
},
|
|
495
|
+
}, ae = (e, t) => {
|
|
458
496
|
if (t.length === 1) return t[0].send;
|
|
459
497
|
let n = t.map((e) => ({
|
|
460
498
|
category: e.send.category,
|
|
@@ -469,118 +507,142 @@ var A = class extends p.TaggedError()("PushTokenRejected", {
|
|
|
469
507
|
data: { items: n },
|
|
470
508
|
tenantId: t[0].send.tenantId ?? null
|
|
471
509
|
};
|
|
472
|
-
}, K =
|
|
473
|
-
id:
|
|
474
|
-
subjectId:
|
|
475
|
-
category:
|
|
476
|
-
title:
|
|
477
|
-
body:
|
|
478
|
-
data:
|
|
479
|
-
readAt:
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
510
|
+
}, K = D("_voltro_notification_inbox", {
|
|
511
|
+
id: b({ prefix: "notif" }),
|
|
512
|
+
subjectId: O(),
|
|
513
|
+
category: O(),
|
|
514
|
+
title: O(),
|
|
515
|
+
body: O(),
|
|
516
|
+
data: C(),
|
|
517
|
+
readAt: k().nullable(),
|
|
518
|
+
archivedAt: k().nullable(),
|
|
519
|
+
createdAt: k().default("now"),
|
|
520
|
+
tenantId: O().nullable()
|
|
521
|
+
}).renamedFrom("notification_inbox").index("byInboxSubject", ["subjectId"]), q = D("_voltro_notification_preferences", {
|
|
522
|
+
id: b({ prefix: "notifpref" }),
|
|
523
|
+
subjectId: O(),
|
|
524
|
+
category: O(),
|
|
525
|
+
channel: O(),
|
|
526
|
+
enabled: _().default(!0)
|
|
488
527
|
}).renamedFrom("notification_preferences").unique("byPreferencesSubjectCategoryChannel", [
|
|
489
528
|
"subjectId",
|
|
490
529
|
"category",
|
|
491
530
|
"channel"
|
|
492
|
-
]), J =
|
|
493
|
-
id:
|
|
494
|
-
recipient:
|
|
495
|
-
category:
|
|
496
|
-
channel:
|
|
497
|
-
status:
|
|
498
|
-
error:
|
|
499
|
-
at:
|
|
500
|
-
}).renamedFrom("notification_deliveries").index("byDeliveriesAt", ["at"]), Y =
|
|
501
|
-
id:
|
|
502
|
-
topic:
|
|
503
|
-
subjectId:
|
|
504
|
-
tenantId:
|
|
505
|
-
}).renamedFrom("notification_topic_subscriptions").unique("byTopicSubject", ["topic", "subjectId"]).index("byTopic", ["topic"]), X =
|
|
506
|
-
id:
|
|
507
|
-
subjectId:
|
|
508
|
-
startMinute:
|
|
509
|
-
endMinute:
|
|
510
|
-
tz:
|
|
511
|
-
policy:
|
|
512
|
-
}).renamedFrom("notification_quiet_hours").unique("byQuietHoursSubject", ["subjectId"]), Z =
|
|
513
|
-
id:
|
|
514
|
-
kind:
|
|
515
|
-
subjectId:
|
|
516
|
-
send:
|
|
517
|
-
flushAt:
|
|
518
|
-
}).renamedFrom("notification_held").index("byHeldFlushAt", ["flushAt"]).index("byHeldSubjectKind", ["subjectId", "kind"]), Q = class extends
|
|
519
|
-
let
|
|
520
|
-
|
|
531
|
+
]), J = D("_voltro_notification_deliveries", {
|
|
532
|
+
id: b({ prefix: "notifdlv" }),
|
|
533
|
+
recipient: O(),
|
|
534
|
+
category: O(),
|
|
535
|
+
channel: O(),
|
|
536
|
+
status: O(),
|
|
537
|
+
error: O().nullable(),
|
|
538
|
+
at: k().default("now")
|
|
539
|
+
}).renamedFrom("notification_deliveries").index("byDeliveriesAt", ["at"]), Y = D("_voltro_notification_topic_subscriptions", {
|
|
540
|
+
id: b({ prefix: "notiftsub" }),
|
|
541
|
+
topic: O(),
|
|
542
|
+
subjectId: O(),
|
|
543
|
+
tenantId: O().nullable()
|
|
544
|
+
}).renamedFrom("notification_topic_subscriptions").unique("byTopicSubject", ["topic", "subjectId"]).index("byTopic", ["topic"]), X = D("_voltro_notification_quiet_hours", {
|
|
545
|
+
id: b({ prefix: "notifqh" }),
|
|
546
|
+
subjectId: O(),
|
|
547
|
+
startMinute: x(),
|
|
548
|
+
endMinute: x(),
|
|
549
|
+
tz: O().default("UTC"),
|
|
550
|
+
policy: O().default("hold")
|
|
551
|
+
}).renamedFrom("notification_quiet_hours").unique("byQuietHoursSubject", ["subjectId"]), Z = D("_voltro_notification_held", {
|
|
552
|
+
id: b({ prefix: "notifheld" }),
|
|
553
|
+
kind: O(),
|
|
554
|
+
subjectId: O(),
|
|
555
|
+
send: C(),
|
|
556
|
+
flushAt: k()
|
|
557
|
+
}).renamedFrom("notification_held").index("byHeldFlushAt", ["flushAt"]).index("byHeldSubjectKind", ["subjectId", "kind"]), Q = class extends f.Tag("@voltro/plugin-notifications/NotificationService")() {}, $ = (e) => e.request.subject.id ?? "anonymous", oe = (e) => e.request.subject.tenantId ?? null, se = (f = {}) => {
|
|
558
|
+
let h = f.name ? `@voltro/plugin-notifications#${f.name}` : "@voltro/plugin-notifications";
|
|
559
|
+
T({
|
|
521
560
|
table: "_voltro_notification_deliveries",
|
|
522
561
|
timeColumn: "at",
|
|
523
|
-
ttlMs:
|
|
524
|
-
}),
|
|
562
|
+
ttlMs: E(process.env.VOLTRO_NOTIFICATION_DELIVERIES_TTL_HOURS, 2160)
|
|
563
|
+
}), T({
|
|
525
564
|
table: "_voltro_notification_inbox",
|
|
526
565
|
timeColumn: "createdAt",
|
|
527
|
-
ttlMs:
|
|
528
|
-
where:
|
|
529
|
-
}),
|
|
566
|
+
ttlMs: E(process.env.VOLTRO_NOTIFICATION_INBOX_READ_TTL_HOURS, 4320),
|
|
567
|
+
where: ne("readAt")
|
|
568
|
+
}), T({
|
|
530
569
|
table: "_voltro_notification_held",
|
|
531
570
|
timeColumn: "flushAt",
|
|
532
|
-
ttlMs:
|
|
571
|
+
ttlMs: E(process.env.VOLTRO_NOTIFICATION_HELD_TTL_HOURS, 168)
|
|
533
572
|
});
|
|
534
|
-
let
|
|
535
|
-
addInbox: (e) =>
|
|
536
|
-
listInbox: (e, t) =>
|
|
537
|
-
markRead: (e, t) =>
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
573
|
+
let g = f.store === void 0, _ = { current: f.store ?? R() }, v = {
|
|
574
|
+
addInbox: (e) => _.current.addInbox(e),
|
|
575
|
+
listInbox: (e, t) => _.current.listInbox(e, t),
|
|
576
|
+
markRead: (e, t) => _.current.markRead(e, t),
|
|
577
|
+
markUnread: (e, t) => _.current.markUnread(e, t),
|
|
578
|
+
markAllRead: (e) => _.current.markAllRead(e),
|
|
579
|
+
setArchived: (e, t, n) => _.current.setArchived(e, t, n),
|
|
580
|
+
unreadCount: (e) => _.current.unreadCount(e),
|
|
581
|
+
getPreferences: (e) => _.current.getPreferences(e),
|
|
582
|
+
setPreference: (e) => _.current.setPreference(e),
|
|
583
|
+
recordDelivery: (e) => _.current.recordDelivery(e),
|
|
584
|
+
listDeliveries: (e) => _.current.listDeliveries(e),
|
|
585
|
+
subscribeTopic: (e) => _.current.subscribeTopic(e),
|
|
586
|
+
unsubscribeTopic: (e, t) => _.current.unsubscribeTopic(e, t),
|
|
587
|
+
listTopicSubscribers: (e) => _.current.listTopicSubscribers(e),
|
|
588
|
+
getQuietHours: (e) => _.current.getQuietHours(e),
|
|
589
|
+
setQuietHours: (e) => _.current.setQuietHours(e),
|
|
590
|
+
clearQuietHours: (e) => _.current.clearQuietHours(e),
|
|
591
|
+
enqueueHeld: (e) => _.current.enqueueHeld(e),
|
|
592
|
+
pendingDigest: (e) => _.current.pendingDigest(e),
|
|
593
|
+
dueHeld: (e) => _.current.dueHeld(e),
|
|
594
|
+
clearHeld: (e) => _.current.clearHeld(e)
|
|
595
|
+
}, y = f.channels ?? [N()], b = y.some((e) => e.id === "inApp") ? y : [...y, V(v)], x = f.digestWindowMs ?? 0, S = G({
|
|
596
|
+
channels: b,
|
|
597
|
+
store: v,
|
|
598
|
+
digestWindowMs: x
|
|
599
|
+
}), C, w = [
|
|
558
600
|
{
|
|
559
|
-
...
|
|
601
|
+
...n,
|
|
560
602
|
description: "The caller's in-app inbox items.",
|
|
561
|
-
execute: (e, t) =>
|
|
603
|
+
execute: (e, t) => p.promise(() => S.inbox($(t), e))
|
|
562
604
|
},
|
|
563
605
|
{
|
|
564
|
-
...
|
|
606
|
+
...d,
|
|
565
607
|
description: "The caller's unread count.",
|
|
566
|
-
execute: (e, t) =>
|
|
608
|
+
execute: (e, t) => p.promise(async () => ({ count: await S.unreadCount($(t)) }))
|
|
567
609
|
},
|
|
568
610
|
{
|
|
569
|
-
...
|
|
611
|
+
...i,
|
|
570
612
|
description: "Mark an inbox item read.",
|
|
571
|
-
execute: (e, t) =>
|
|
613
|
+
execute: (e, t) => p.promise(async () => ({ ok: await S.markRead(e.id, $(t)) }))
|
|
572
614
|
},
|
|
573
615
|
{
|
|
574
|
-
...
|
|
616
|
+
...a,
|
|
617
|
+
description: "Mark an inbox item unread again.",
|
|
618
|
+
execute: (e, t) => p.promise(async () => ({ ok: await S.markUnread(e.id, $(t)) }))
|
|
619
|
+
},
|
|
620
|
+
{
|
|
621
|
+
...r,
|
|
622
|
+
description: "Mark every unread item in the caller's inbox read.",
|
|
623
|
+
execute: (e, t) => p.promise(async () => ({ count: await S.markAllRead($(t)) }))
|
|
624
|
+
},
|
|
625
|
+
{
|
|
626
|
+
...e,
|
|
627
|
+
description: "Archive an inbox item — a different state from read; this is what empties the inbox.",
|
|
628
|
+
execute: (e, t) => p.promise(async () => ({ ok: await S.setArchived(e.id, $(t), !0) }))
|
|
629
|
+
},
|
|
630
|
+
{
|
|
631
|
+
...ee,
|
|
632
|
+
description: "Return an archived item to the inbox.",
|
|
633
|
+
execute: (e, t) => p.promise(async () => ({ ok: await S.setArchived(e.id, $(t), !1) }))
|
|
634
|
+
},
|
|
635
|
+
{
|
|
636
|
+
...s,
|
|
575
637
|
description: "The caller's channel preferences.",
|
|
576
|
-
execute: (e, t) =>
|
|
638
|
+
execute: (e, t) => p.promise(() => S.getPreferences($(t)))
|
|
577
639
|
},
|
|
578
640
|
{
|
|
579
|
-
...
|
|
641
|
+
...c,
|
|
580
642
|
description: "Toggle a channel on/off for a category.",
|
|
581
|
-
execute: (e, t) =>
|
|
643
|
+
execute: (e, t) => p.promise(async () => {
|
|
582
644
|
let { category: n, channel: r, enabled: i } = e;
|
|
583
|
-
return await
|
|
645
|
+
return await S.setPreference({
|
|
584
646
|
subjectId: $(t),
|
|
585
647
|
category: n,
|
|
586
648
|
channel: r,
|
|
@@ -589,21 +651,21 @@ var A = class extends p.TaggedError()("PushTokenRejected", {
|
|
|
589
651
|
})
|
|
590
652
|
},
|
|
591
653
|
{
|
|
592
|
-
...
|
|
654
|
+
...u,
|
|
593
655
|
description: "Subscribe the caller to a broadcast topic.",
|
|
594
|
-
execute: (e, t) =>
|
|
656
|
+
execute: (e, t) => p.promise(async () => (await S.subscribe(e.topic, $(t), oe(t)), { ok: !0 }))
|
|
595
657
|
},
|
|
596
658
|
{
|
|
597
|
-
...
|
|
659
|
+
...te,
|
|
598
660
|
description: "Unsubscribe the caller from a broadcast topic.",
|
|
599
|
-
execute: (e, t) =>
|
|
661
|
+
execute: (e, t) => p.promise(async () => (await S.unsubscribe(e.topic, $(t)), { ok: !0 }))
|
|
600
662
|
},
|
|
601
663
|
{
|
|
602
|
-
...
|
|
664
|
+
...l,
|
|
603
665
|
description: "Set the caller's quiet-hours (DND) window.",
|
|
604
|
-
execute: (e, t) =>
|
|
666
|
+
execute: (e, t) => p.promise(async () => {
|
|
605
667
|
let n = e;
|
|
606
|
-
return await
|
|
668
|
+
return await S.setQuietHours({
|
|
607
669
|
subjectId: $(t),
|
|
608
670
|
startMinute: n.startMinute,
|
|
609
671
|
endMinute: n.endMinute,
|
|
@@ -613,20 +675,20 @@ var A = class extends p.TaggedError()("PushTokenRejected", {
|
|
|
613
675
|
})
|
|
614
676
|
},
|
|
615
677
|
{
|
|
616
|
-
...
|
|
678
|
+
...t,
|
|
617
679
|
description: "Clear the caller's quiet-hours window.",
|
|
618
|
-
execute: (e, t) =>
|
|
680
|
+
execute: (e, t) => p.promise(async () => (await S.clearQuietHours($(t)), { ok: !0 }))
|
|
619
681
|
}
|
|
620
|
-
],
|
|
682
|
+
], D = (e) => ({
|
|
621
683
|
kind: "json",
|
|
622
684
|
data: e
|
|
623
|
-
}),
|
|
685
|
+
}), O = (e, t) => ({
|
|
624
686
|
kind: "json",
|
|
625
687
|
status: e,
|
|
626
688
|
data: { error: t }
|
|
627
|
-
}),
|
|
628
|
-
return
|
|
629
|
-
name:
|
|
689
|
+
}), k = (e, t) => new URLSearchParams(new URL(e, "http://x").search).get(t);
|
|
690
|
+
return A({
|
|
691
|
+
name: h,
|
|
630
692
|
description: "Unified notifications — email/slack/sms/push/in-app with preference routing, inbox + delivery log.",
|
|
631
693
|
permissions: ["inspect:read", "store:write"],
|
|
632
694
|
extendSchema: { tables: [
|
|
@@ -637,19 +699,19 @@ var A = class extends p.TaggedError()("PushTokenRejected", {
|
|
|
637
699
|
X,
|
|
638
700
|
Z
|
|
639
701
|
] },
|
|
640
|
-
services:
|
|
641
|
-
routes:
|
|
642
|
-
rpcClientDescriptors:
|
|
702
|
+
services: m.succeed(Q, S),
|
|
703
|
+
routes: w,
|
|
704
|
+
rpcClientDescriptors: o,
|
|
643
705
|
inspectEndpoints: [{
|
|
644
706
|
method: "GET",
|
|
645
707
|
path: "/deliveries",
|
|
646
708
|
description: "Recent delivery records (newest first) + per-channel + per-status counts.",
|
|
647
|
-
handler: () =>
|
|
648
|
-
let e = await
|
|
709
|
+
handler: () => p.promise(async () => {
|
|
710
|
+
let e = await v.listDeliveries({ limit: 200 }), t = {}, n = 0, r = 0;
|
|
649
711
|
for (let i of e) t[i.channel] = (t[i.channel] ?? 0) + 1, i.status === "sent" ? n++ : r++;
|
|
650
|
-
return
|
|
712
|
+
return D({
|
|
651
713
|
deliveries: e.slice(0, 100),
|
|
652
|
-
channels:
|
|
714
|
+
channels: b.map((e) => e.id),
|
|
653
715
|
stats: {
|
|
654
716
|
sent: n,
|
|
655
717
|
failed: r,
|
|
@@ -662,28 +724,28 @@ var A = class extends p.TaggedError()("PushTokenRejected", {
|
|
|
662
724
|
path: "/inbox",
|
|
663
725
|
description: "In-app inbox for a subject (?subjectId=…).",
|
|
664
726
|
handler: (e) => {
|
|
665
|
-
let t =
|
|
666
|
-
return t ?
|
|
667
|
-
items: await
|
|
668
|
-
unread: await
|
|
669
|
-
})) :
|
|
727
|
+
let t = k(e.url, "subjectId");
|
|
728
|
+
return t ? p.promise(async () => D({
|
|
729
|
+
items: await v.listInbox(t, { limit: 100 }),
|
|
730
|
+
unread: await v.unreadCount(t)
|
|
731
|
+
})) : p.succeed(O(400, "subjectId query param required"));
|
|
670
732
|
}
|
|
671
733
|
}],
|
|
672
734
|
bindDataStore: (e) => {
|
|
673
|
-
|
|
674
|
-
let t =
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
}, t), typeof
|
|
678
|
-
},
|
|
679
|
-
onActivate: (e) =>
|
|
680
|
-
channels:
|
|
681
|
-
digestWindowMs:
|
|
735
|
+
g && (_.current = B(e));
|
|
736
|
+
let t = f.flushIntervalMs ?? 3e4;
|
|
737
|
+
C = setInterval(() => {
|
|
738
|
+
S.flushDue().catch(() => {});
|
|
739
|
+
}, t), typeof C.unref == "function" && C.unref();
|
|
740
|
+
},
|
|
741
|
+
onActivate: (e) => p.sync(() => e.logger.info("notifications active", {
|
|
742
|
+
channels: b.map((e) => e.id),
|
|
743
|
+
digestWindowMs: x
|
|
682
744
|
})),
|
|
683
|
-
onDeactivate: () =>
|
|
684
|
-
|
|
745
|
+
onDeactivate: () => p.sync(() => {
|
|
746
|
+
C && clearInterval(C), C = void 0;
|
|
685
747
|
})
|
|
686
748
|
});
|
|
687
749
|
};
|
|
688
750
|
//#endregion
|
|
689
|
-
export { Q as NotificationService,
|
|
751
|
+
export { Q as NotificationService, M as PushTokenRejected, G as buildNotificationService, N as consoleChannel, re as customChannel, B as dataStoreNotificationStore, J as deliveriesTable, F as emailChannel, Z as heldTable, V as inAppChannel, U as inQuietHours, K as inboxTable, R as memoryNotificationStore, H as minuteOfDayInZone, se as notificationsPlugin, q as preferencesTable, ie as pushChannel, W as quietHoursEnd, X as quietHoursTable, L as resolveChannels, I as smsChannel, Y as topicSubscriptionsTable, P as webhookChannel };
|