@voltro/plugin-notifications 0.26.0 → 0.28.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/dist/index.js CHANGED
@@ -1,18 +1,18 @@
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";
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 te, unsubscribeDescriptor as ne } from "./rpc.js";
2
+ import { Context as d, Effect as f, Layer as p, Schema as m } from "effect";
3
+ import { and as h, boolean as g, eq as _, generateId as v, id as y, integer as b, isNotNull as re, isNull as x, json as S, lte as C, registerRetention as w, retentionTtlMsFromEnv as T, table as E, text as D, timestamp as O } from "@voltro/database";
4
+ import { definePlugin as k } from "@voltro/protocol";
5
+ import { randomUUID as A } from "node:crypto";
6
6
  //#region src/errors.ts
7
- var M = class extends h.TaggedError()("PushTokenRejected", {
8
- token: h.String,
9
- reason: h.String
10
- }) {}, N = () => ({
7
+ var j = class extends m.TaggedError()("PushTokenRejected", {
8
+ token: m.String,
9
+ reason: m.String
10
+ }) {}, M = () => ({
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
- }), P = (e) => ({
15
+ }), ie = (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 M = class extends h.TaggedError()("PushTokenRejected", {
25
25
  });
26
26
  if (!r.ok) throw Error(`webhook ${e.id ?? "slack"} POST ${r.status}`);
27
27
  }
28
- }), F = (e) => ({
28
+ }), ae = (e) => ({
29
29
  id: "email",
30
30
  deliver: (t) => e({
31
31
  to: t.to,
@@ -33,13 +33,13 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
33
33
  html: `<p>${t.body}</p>`,
34
34
  text: t.body
35
35
  })
36
- }), I = (e) => ({
36
+ }), N = (e) => ({
37
37
  id: "sms",
38
38
  deliver: (t) => e(t.to, `${t.title}: ${t.body}`)
39
- }), re = (e, t) => ({
39
+ }), P = (e, t) => ({
40
40
  id: e,
41
41
  deliver: t
42
- }), ie = (e) => ({
42
+ }), F = (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,17 +54,17 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
54
54
  try {
55
55
  await e.transport(n);
56
56
  } catch (e) {
57
- throw e instanceof M ? e : new M({
57
+ throw e instanceof j ? e : new j({
58
58
  token: r,
59
59
  reason: e instanceof Error ? e.message : String(e)
60
60
  });
61
61
  }
62
62
  }
63
63
  }
64
- }), L = (e, t, n, r, i) => {
64
+ }), I = (e, t, n, r, i) => {
65
65
  let a = n ? e.filter((e) => n.includes(e)) : [...e], o = new Set(r.filter((e) => e.subjectId === i && e.category === t && e.enabled === !1).map((e) => e.channel));
66
66
  return a.filter((e) => !o.has(e));
67
- }, R = () => {
67
+ }, L = () => {
68
68
  let e = [], t = /* @__PURE__ */ new Map(), n = [], r = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Map(), a = [], o = (e) => `${e.subjectId}|${e.category}|${e.channel}`, s = (e, t) => `${e}|${t}`;
69
69
  return {
70
70
  addInbox: async (t) => {
@@ -145,7 +145,7 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
145
145
  for (let e = a.length - 1; e >= 0; e--) t.has(a[e].id) && a.splice(e, 1);
146
146
  }
147
147
  };
148
- }, z = (e) => e instanceof Date ? e.toISOString() : typeof e == "string" ? e : "", B = (e) => {
148
+ }, R = (e) => e instanceof Date ? e.toISOString() : typeof e == "string" ? e : "", z = (e) => {
149
149
  let t = async (t, n, r, i) => await e.query({
150
150
  table: t,
151
151
  predicate: n,
@@ -160,9 +160,9 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
160
160
  title: String(e.title),
161
161
  body: String(e.body),
162
162
  data: e.data ?? {},
163
- readAt: e.readAt == null ? null : z(e.readAt),
164
- archivedAt: e.archivedAt == null ? null : z(e.archivedAt),
165
- createdAt: z(e.createdAt),
163
+ readAt: e.readAt == null ? null : R(e.readAt),
164
+ archivedAt: e.archivedAt == null ? null : R(e.archivedAt),
165
+ createdAt: R(e.createdAt),
166
166
  tenantId: e.tenantId ?? null
167
167
  }), r = (e) => ({
168
168
  subjectId: String(e.subjectId),
@@ -176,7 +176,7 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
176
176
  category: String(e.category),
177
177
  channel: String(e.channel),
178
178
  status: e.status,
179
- at: z(e.at)
179
+ at: R(e.at)
180
180
  };
181
181
  return e.error == null ? t : {
182
182
  ...t,
@@ -197,7 +197,7 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
197
197
  kind: e.kind === "quiet" ? "quiet" : "digest",
198
198
  subjectId: String(e.subjectId),
199
199
  send: e.send ?? {},
200
- flushAt: z(e.flushAt)
200
+ flushAt: R(e.flushAt)
201
201
  });
202
202
  return {
203
203
  addInbox: async (t) => {
@@ -215,24 +215,24 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
215
215
  });
216
216
  },
217
217
  listInbox: async (e, r) => {
218
- let i = r?.unreadOnly ? g(v("subjectId", e), S("readAt")) : v("subjectId", e);
218
+ let i = r?.unreadOnly ? h(_("subjectId", e), x("readAt")) : _("subjectId", e);
219
219
  return (await t("_voltro_notification_inbox", i, [{
220
220
  column: "createdAt",
221
221
  direction: "desc"
222
222
  }], r?.limit)).map(n);
223
223
  },
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,
224
+ markRead: async (n, r) => (await t("_voltro_notification_inbox", h(_("id", n), _("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", h(_("id", n), _("subjectId", r)), [], 1))[0] ? (await e.update("_voltro_notification_inbox", n, { readAt: null }), !0) : !1,
226
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();
227
+ let r = await t("_voltro_notification_inbox", h(_("subjectId", n), x("readAt")), [], void 0), i = (/* @__PURE__ */ new Date()).toISOString();
228
228
  for (let t of r) await e.update("_voltro_notification_inbox", String(t.id), { readAt: i });
229
229
  return r.length;
230
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),
231
+ setArchived: async (n, r, i) => (await t("_voltro_notification_inbox", h(_("id", n), _("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", h(_("subjectId", e), x("readAt")), [], void 0)).length,
233
+ getPreferences: async (e) => (await t("_voltro_notification_preferences", _("subjectId", e), [], void 0)).map(r),
234
234
  setPreference: async (t) => {
235
- let n = y({
235
+ let n = v({
236
236
  kind: "typeid",
237
237
  prefix: "notifpref"
238
238
  }, "_voltro_notification_preferences");
@@ -267,7 +267,7 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
267
267
  direction: "desc"
268
268
  }], e?.limit)).map(i),
269
269
  subscribeTopic: async (t) => {
270
- let n = y({
270
+ let n = v({
271
271
  kind: "typeid",
272
272
  prefix: "notiftsub"
273
273
  }, "_voltro_notification_topic_subscriptions");
@@ -282,16 +282,16 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
282
282
  });
283
283
  },
284
284
  unsubscribeTopic: async (n, r) => {
285
- let i = await t("_voltro_notification_topic_subscriptions", g(v("topic", n), v("subjectId", r)), [], 1);
285
+ let i = await t("_voltro_notification_topic_subscriptions", h(_("topic", n), _("subjectId", r)), [], 1);
286
286
  i[0] && await e.delete("_voltro_notification_topic_subscriptions", String(i[0].id));
287
287
  },
288
- listTopicSubscribers: async (e) => (await t("_voltro_notification_topic_subscriptions", v("topic", e), [], void 0)).map(a),
288
+ listTopicSubscribers: async (e) => (await t("_voltro_notification_topic_subscriptions", _("topic", e), [], void 0)).map(a),
289
289
  getQuietHours: async (e) => {
290
- let n = await t("_voltro_notification_quiet_hours", v("subjectId", e), [], 1);
290
+ let n = await t("_voltro_notification_quiet_hours", _("subjectId", e), [], 1);
291
291
  return n[0] ? o(n[0]) : null;
292
292
  },
293
293
  setQuietHours: async (t) => {
294
- let n = y({
294
+ let n = v({
295
295
  kind: "typeid",
296
296
  prefix: "notifqh"
297
297
  }, "_voltro_notification_quiet_hours");
@@ -313,7 +313,7 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
313
313
  });
314
314
  },
315
315
  clearQuietHours: async (n) => {
316
- let r = await t("_voltro_notification_quiet_hours", v("subjectId", n), [], 1);
316
+ let r = await t("_voltro_notification_quiet_hours", _("subjectId", n), [], 1);
317
317
  r[0] && await e.delete("_voltro_notification_quiet_hours", String(r[0].id));
318
318
  },
319
319
  enqueueHeld: async (t) => {
@@ -325,11 +325,11 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
325
325
  flushAt: t.flushAt
326
326
  });
327
327
  },
328
- pendingDigest: async (e) => (await t("_voltro_notification_held", g(v("kind", "digest"), v("subjectId", e)), [{
328
+ pendingDigest: async (e) => (await t("_voltro_notification_held", h(_("kind", "digest"), _("subjectId", e)), [{
329
329
  column: "flushAt",
330
330
  direction: "asc"
331
331
  }], void 0)).map(s),
332
- dueHeld: async (e) => (await t("_voltro_notification_held", w("flushAt", e), [{
332
+ dueHeld: async (e) => (await t("_voltro_notification_held", C("flushAt", e), [{
333
333
  column: "flushAt",
334
334
  direction: "asc"
335
335
  }], void 0)).map(s),
@@ -337,11 +337,11 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
337
337
  for (let n of t) await e.delete("_voltro_notification_held", n);
338
338
  }
339
339
  };
340
- }, V = (e) => ({
340
+ }, B = (e) => ({
341
341
  id: "inApp",
342
342
  deliver: async (t) => {
343
343
  await e.addInbox({
344
- id: j(),
344
+ id: A(),
345
345
  subjectId: t.to,
346
346
  category: t.category,
347
347
  title: t.title,
@@ -351,7 +351,7 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
351
351
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
352
352
  });
353
353
  }
354
- }), H = (e, t) => {
354
+ }), V = (e, t) => {
355
355
  try {
356
356
  let n = new Intl.DateTimeFormat("en-US", {
357
357
  timeZone: t,
@@ -363,16 +363,16 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
363
363
  } catch {
364
364
  return e.getUTCHours() * 60 + e.getUTCMinutes();
365
365
  }
366
- }, U = (e, t) => {
366
+ }, H = (e, t) => {
367
367
  if (e.startMinute === e.endMinute) return !1;
368
- let n = H(t, e.tz ?? "UTC");
368
+ let n = V(t, e.tz ?? "UTC");
369
369
  return e.startMinute < e.endMinute ? n >= e.startMinute && n < e.endMinute : n >= e.startMinute || n < e.endMinute;
370
- }, W = (e, t) => {
371
- let n = H(t, e.tz ?? "UTC"), r = e.endMinute - n;
370
+ }, U = (e, t) => {
371
+ let n = V(t, e.tz ?? "UTC"), r = e.endMinute - n;
372
372
  return r <= 0 && (r += 1440), new Date(t.getTime() + r * 6e4);
373
- }, G = (e) => {
373
+ }, W = (e) => {
374
374
  let t = new Map(e.channels.map((e) => [e.id, e])), n = e.channels.map((e) => e.id), r = e.now ?? (() => (/* @__PURE__ */ new Date()).toISOString()), i = e.digestWindowMs ?? 0, a = async (i) => {
375
- let a = await e.store.getPreferences(i.to), o = L(n, i.category, i.channels, a, i.to), s = n.filter((e) => !o.includes(e)), c = [], l = [], u = {
375
+ let a = await e.store.getPreferences(i.to), o = I(n, i.category, i.channels, a, i.to), s = n.filter((e) => !o.includes(e)), c = [], l = [], u = {
376
376
  to: i.to,
377
377
  category: i.category,
378
378
  title: i.title,
@@ -384,7 +384,7 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
384
384
  let a = t.get(n);
385
385
  if (!a) continue;
386
386
  let o = {
387
- id: j(),
387
+ id: A(),
388
388
  to: i.to,
389
389
  category: i.category,
390
390
  channel: n,
@@ -414,17 +414,17 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
414
414
  };
415
415
  }, o = async (t) => {
416
416
  let n = await e.store.getQuietHours(t.to), o = new Date(r());
417
- if (n && U(n, o)) return (n.policy ?? "hold") === "drop" ? {
417
+ if (n && H(n, o)) return (n.policy ?? "hold") === "drop" ? {
418
418
  delivered: [],
419
419
  failed: [],
420
420
  skipped: [],
421
421
  held: "quiet-drop"
422
422
  } : (await e.store.enqueueHeld({
423
- id: j(),
423
+ id: A(),
424
424
  kind: "quiet",
425
425
  subjectId: t.to,
426
426
  send: t,
427
- flushAt: W(n, o).toISOString()
427
+ flushAt: U(n, o).toISOString()
428
428
  }), {
429
429
  delivered: [],
430
430
  failed: [],
@@ -434,7 +434,7 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
434
434
  if (i > 0 && !t.channels) {
435
435
  let n = (await e.store.pendingDigest(t.to))[0]?.flushAt ?? new Date(o.getTime() + i).toISOString();
436
436
  return await e.store.enqueueHeld({
437
- id: j(),
437
+ id: A(),
438
438
  kind: "digest",
439
439
  subjectId: t.to,
440
440
  send: t,
@@ -488,11 +488,11 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
488
488
  let t = i.get(e.subjectId) ?? [];
489
489
  t.push(e), i.set(e.subjectId, t);
490
490
  }
491
- for (let [e, t] of i) await a(ae(e, t));
491
+ for (let [e, t] of i) await a(G(e, t));
492
492
  return await e.store.clearHeld(n.map((e) => e.id)), n.length;
493
493
  }
494
494
  };
495
- }, ae = (e, t) => {
495
+ }, G = (e, t) => {
496
496
  if (t.length === 1) return t[0].send;
497
497
  let n = t.map((e) => ({
498
498
  category: e.send.category,
@@ -507,70 +507,76 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
507
507
  data: { items: n },
508
508
  tenantId: t[0].send.tenantId ?? null
509
509
  };
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)
510
+ }, K = E("_voltro_notification_inbox", {
511
+ id: y({ prefix: "notif" }),
512
+ subjectId: D(),
513
+ category: D(),
514
+ title: D(),
515
+ body: D(),
516
+ data: S(),
517
+ readAt: O().nullable(),
518
+ archivedAt: O().nullable(),
519
+ createdAt: O().default("now"),
520
+ tenantId: D().nullable()
521
+ }).renamedFrom("notification_inbox").index("byInboxSubject", ["subjectId"]), q = E("_voltro_notification_preferences", {
522
+ id: y({ prefix: "notifpref" }),
523
+ subjectId: D(),
524
+ category: D(),
525
+ channel: D(),
526
+ enabled: g().default(!0)
527
527
  }).renamedFrom("notification_preferences").unique("byPreferencesSubjectCategoryChannel", [
528
528
  "subjectId",
529
529
  "category",
530
530
  "channel"
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({
531
+ ]), J = E("_voltro_notification_deliveries", {
532
+ id: y({ prefix: "notifdlv" }),
533
+ recipient: D(),
534
+ category: D(),
535
+ channel: D(),
536
+ status: D(),
537
+ error: D().nullable(),
538
+ at: O().default("now")
539
+ }).renamedFrom("notification_deliveries").index("byDeliveriesAt", ["at"]), Y = E("_voltro_notification_topic_subscriptions", {
540
+ id: y({ prefix: "notiftsub" }),
541
+ topic: D(),
542
+ subjectId: D(),
543
+ tenantId: D().nullable()
544
+ }).renamedFrom("notification_topic_subscriptions").unique("byTopicSubject", ["topic", "subjectId"]).index("byTopic", ["topic"]), X = E("_voltro_notification_quiet_hours", {
545
+ id: y({ prefix: "notifqh" }),
546
+ subjectId: D(),
547
+ startMinute: b(),
548
+ endMinute: b(),
549
+ tz: D().default("UTC"),
550
+ policy: D().default("hold")
551
+ }).renamedFrom("notification_quiet_hours").unique("byQuietHoursSubject", ["subjectId"]), Z = E("_voltro_notification_held", {
552
+ id: y({ prefix: "notifheld" }),
553
+ kind: D(),
554
+ subjectId: D(),
555
+ send: S(),
556
+ flushAt: O()
557
+ }).renamedFrom("notification_held").index("byHeldFlushAt", ["flushAt"]).index("byHeldSubjectKind", ["subjectId", "kind"]), Q = class extends d.Tag("@voltro/plugin-notifications/NotificationService")() {}, $ = (e) => async (t) => {
558
+ if (e !== void 0) try {
559
+ let n = await e(t);
560
+ if (typeof n == "string" && n !== "") return n;
561
+ } catch {}
562
+ return t.request.subject.id ?? "anonymous";
563
+ }, oe = (e) => e.request.subject.tenantId ?? null, se = (d = {}) => {
564
+ let m = $(d.resolveSubjectId), h = d.name ? `@voltro/plugin-notifications#${d.name}` : "@voltro/plugin-notifications";
565
+ w({
560
566
  table: "_voltro_notification_deliveries",
561
567
  timeColumn: "at",
562
- ttlMs: E(process.env.VOLTRO_NOTIFICATION_DELIVERIES_TTL_HOURS, 2160)
563
- }), T({
568
+ ttlMs: T(process.env.VOLTRO_NOTIFICATION_DELIVERIES_TTL_HOURS, 2160)
569
+ }), w({
564
570
  table: "_voltro_notification_inbox",
565
571
  timeColumn: "createdAt",
566
- ttlMs: E(process.env.VOLTRO_NOTIFICATION_INBOX_READ_TTL_HOURS, 4320),
567
- where: ne("readAt")
568
- }), T({
572
+ ttlMs: T(process.env.VOLTRO_NOTIFICATION_INBOX_READ_TTL_HOURS, 4320),
573
+ where: re("readAt")
574
+ }), w({
569
575
  table: "_voltro_notification_held",
570
576
  timeColumn: "flushAt",
571
- ttlMs: E(process.env.VOLTRO_NOTIFICATION_HELD_TTL_HOURS, 168)
577
+ ttlMs: T(process.env.VOLTRO_NOTIFICATION_HELD_TTL_HOURS, 168)
572
578
  });
573
- let g = f.store === void 0, _ = { current: f.store ?? R() }, v = {
579
+ let g = d.store === void 0, _ = { current: d.store ?? L() }, v = {
574
580
  addInbox: (e) => _.current.addInbox(e),
575
581
  listInbox: (e, t) => _.current.listInbox(e, t),
576
582
  markRead: (e, t) => _.current.markRead(e, t),
@@ -592,58 +598,58 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
592
598
  pendingDigest: (e) => _.current.pendingDigest(e),
593
599
  dueHeld: (e) => _.current.dueHeld(e),
594
600
  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({
601
+ }, y = d.channels ?? [M()], b = y.some((e) => e.id === "inApp") ? y : [...y, B(v)], x = d.digestWindowMs ?? 0, S = W({
596
602
  channels: b,
597
603
  store: v,
598
604
  digestWindowMs: x
599
- }), C, w = [
605
+ }), C, E = [
600
606
  {
601
607
  ...n,
602
608
  description: "The caller's in-app inbox items.",
603
- execute: (e, t) => p.promise(() => S.inbox($(t), e))
609
+ execute: (e, t) => f.promise(async () => S.inbox(await m(t), e))
604
610
  },
605
611
  {
606
- ...d,
612
+ ...te,
607
613
  description: "The caller's unread count.",
608
- execute: (e, t) => p.promise(async () => ({ count: await S.unreadCount($(t)) }))
614
+ execute: (e, t) => f.promise(async () => ({ count: await S.unreadCount(await m(t)) }))
609
615
  },
610
616
  {
611
617
  ...i,
612
618
  description: "Mark an inbox item read.",
613
- execute: (e, t) => p.promise(async () => ({ ok: await S.markRead(e.id, $(t)) }))
619
+ execute: (e, t) => f.promise(async () => ({ ok: await S.markRead(e.id, await m(t)) }))
614
620
  },
615
621
  {
616
622
  ...a,
617
623
  description: "Mark an inbox item unread again.",
618
- execute: (e, t) => p.promise(async () => ({ ok: await S.markUnread(e.id, $(t)) }))
624
+ execute: (e, t) => f.promise(async () => ({ ok: await S.markUnread(e.id, await m(t)) }))
619
625
  },
620
626
  {
621
627
  ...r,
622
628
  description: "Mark every unread item in the caller's inbox read.",
623
- execute: (e, t) => p.promise(async () => ({ count: await S.markAllRead($(t)) }))
629
+ execute: (e, t) => f.promise(async () => ({ count: await S.markAllRead(await m(t)) }))
624
630
  },
625
631
  {
626
632
  ...e,
627
633
  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) }))
634
+ execute: (e, t) => f.promise(async () => ({ ok: await S.setArchived(e.id, await m(t), !0) }))
629
635
  },
630
636
  {
631
637
  ...ee,
632
638
  description: "Return an archived item to the inbox.",
633
- execute: (e, t) => p.promise(async () => ({ ok: await S.setArchived(e.id, $(t), !1) }))
639
+ execute: (e, t) => f.promise(async () => ({ ok: await S.setArchived(e.id, await m(t), !1) }))
634
640
  },
635
641
  {
636
642
  ...s,
637
643
  description: "The caller's channel preferences.",
638
- execute: (e, t) => p.promise(() => S.getPreferences($(t)))
644
+ execute: (e, t) => f.promise(async () => S.getPreferences(await m(t)))
639
645
  },
640
646
  {
641
647
  ...c,
642
648
  description: "Toggle a channel on/off for a category.",
643
- execute: (e, t) => p.promise(async () => {
649
+ execute: (e, t) => f.promise(async () => {
644
650
  let { category: n, channel: r, enabled: i } = e;
645
651
  return await S.setPreference({
646
- subjectId: $(t),
652
+ subjectId: await m(t),
647
653
  category: n,
648
654
  channel: r,
649
655
  enabled: i
@@ -653,20 +659,20 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
653
659
  {
654
660
  ...u,
655
661
  description: "Subscribe the caller to a broadcast topic.",
656
- execute: (e, t) => p.promise(async () => (await S.subscribe(e.topic, $(t), oe(t)), { ok: !0 }))
662
+ execute: (e, t) => f.promise(async () => (await S.subscribe(e.topic, await m(t), oe(t)), { ok: !0 }))
657
663
  },
658
664
  {
659
- ...te,
665
+ ...ne,
660
666
  description: "Unsubscribe the caller from a broadcast topic.",
661
- execute: (e, t) => p.promise(async () => (await S.unsubscribe(e.topic, $(t)), { ok: !0 }))
667
+ execute: (e, t) => f.promise(async () => (await S.unsubscribe(e.topic, await m(t)), { ok: !0 }))
662
668
  },
663
669
  {
664
670
  ...l,
665
671
  description: "Set the caller's quiet-hours (DND) window.",
666
- execute: (e, t) => p.promise(async () => {
672
+ execute: (e, t) => f.promise(async () => {
667
673
  let n = e;
668
674
  return await S.setQuietHours({
669
- subjectId: $(t),
675
+ subjectId: await m(t),
670
676
  startMinute: n.startMinute,
671
677
  endMinute: n.endMinute,
672
678
  ...n.tz ? { tz: n.tz } : {},
@@ -677,7 +683,7 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
677
683
  {
678
684
  ...t,
679
685
  description: "Clear the caller's quiet-hours window.",
680
- execute: (e, t) => p.promise(async () => (await S.clearQuietHours($(t)), { ok: !0 }))
686
+ execute: (e, t) => f.promise(async () => (await S.clearQuietHours(await m(t)), { ok: !0 }))
681
687
  }
682
688
  ], D = (e) => ({
683
689
  kind: "json",
@@ -686,8 +692,8 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
686
692
  kind: "json",
687
693
  status: e,
688
694
  data: { error: t }
689
- }), k = (e, t) => new URLSearchParams(new URL(e, "http://x").search).get(t);
690
- return A({
695
+ }), A = (e, t) => new URLSearchParams(new URL(e, "http://x").search).get(t);
696
+ return k({
691
697
  name: h,
692
698
  description: "Unified notifications — email/slack/sms/push/in-app with preference routing, inbox + delivery log.",
693
699
  permissions: ["inspect:read", "store:write"],
@@ -699,14 +705,14 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
699
705
  X,
700
706
  Z
701
707
  ] },
702
- services: m.succeed(Q, S),
703
- routes: w,
708
+ services: p.succeed(Q, S),
709
+ routes: E,
704
710
  rpcClientDescriptors: o,
705
711
  inspectEndpoints: [{
706
712
  method: "GET",
707
713
  path: "/deliveries",
708
714
  description: "Recent delivery records (newest first) + per-channel + per-status counts.",
709
- handler: () => p.promise(async () => {
715
+ handler: () => f.promise(async () => {
710
716
  let e = await v.listDeliveries({ limit: 200 }), t = {}, n = 0, r = 0;
711
717
  for (let i of e) t[i.channel] = (t[i.channel] ?? 0) + 1, i.status === "sent" ? n++ : r++;
712
718
  return D({
@@ -724,28 +730,28 @@ var M = class extends h.TaggedError()("PushTokenRejected", {
724
730
  path: "/inbox",
725
731
  description: "In-app inbox for a subject (?subjectId=…).",
726
732
  handler: (e) => {
727
- let t = k(e.url, "subjectId");
728
- return t ? p.promise(async () => D({
733
+ let t = A(e.url, "subjectId");
734
+ return t ? f.promise(async () => D({
729
735
  items: await v.listInbox(t, { limit: 100 }),
730
736
  unread: await v.unreadCount(t)
731
- })) : p.succeed(O(400, "subjectId query param required"));
737
+ })) : f.succeed(O(400, "subjectId query param required"));
732
738
  }
733
739
  }],
734
740
  bindDataStore: (e) => {
735
- g && (_.current = B(e));
736
- let t = f.flushIntervalMs ?? 3e4;
741
+ g && (_.current = z(e));
742
+ let t = d.flushIntervalMs ?? 3e4;
737
743
  C = setInterval(() => {
738
744
  S.flushDue().catch(() => {});
739
745
  }, t), typeof C.unref == "function" && C.unref();
740
746
  },
741
- onActivate: (e) => p.sync(() => e.logger.info("notifications active", {
747
+ onActivate: (e) => f.sync(() => e.logger.info("notifications active", {
742
748
  channels: b.map((e) => e.id),
743
749
  digestWindowMs: x
744
750
  })),
745
- onDeactivate: () => p.sync(() => {
751
+ onDeactivate: () => f.sync(() => {
746
752
  C && clearInterval(C), C = void 0;
747
753
  })
748
754
  });
749
755
  };
750
756
  //#endregion
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 };
757
+ export { Q as NotificationService, j as PushTokenRejected, W as buildNotificationService, M as consoleChannel, P as customChannel, z as dataStoreNotificationStore, J as deliveriesTable, ae as emailChannel, Z as heldTable, B as inAppChannel, H as inQuietHours, K as inboxTable, $ as makeSubjectId, L as memoryNotificationStore, V as minuteOfDayInZone, se as notificationsPlugin, q as preferencesTable, F as pushChannel, U as quietHoursEnd, X as quietHoursTable, I as resolveChannels, N as smsChannel, Y as topicSubscriptionsTable, ie as webhookChannel };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voltro/plugin-notifications",
3
- "version": "0.26.0",
3
+ "version": "0.28.0",
4
4
  "description": "One unified notification surface — email, Slack/webhook, SMS, push, in-app — with per-subject preference routing, an in-app inbox, and a delivery log. NotificationService + typed routes + useInbox/useUnreadCount hooks.",
5
5
  "keywords": [
6
6
  "voltro",
@@ -42,9 +42,9 @@
42
42
  "node": ">=24.0.0"
43
43
  },
44
44
  "dependencies": {
45
- "@voltro/client": "0.26.0",
46
- "@voltro/database": "0.26.0",
47
- "@voltro/protocol": "0.26.0"
45
+ "@voltro/client": "0.28.0",
46
+ "@voltro/database": "0.28.0",
47
+ "@voltro/protocol": "0.28.0"
48
48
  },
49
49
  "peerDependencies": {
50
50
  "effect": "^3.22.0"