@voltro/plugin-notifications 0.25.0 → 0.27.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 +541 -0
- package/dist/index.d.ts +78 -1
- package/dist/index.js +245 -177
- 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.d.ts
CHANGED
|
@@ -127,6 +127,8 @@ export declare interface InboxItem {
|
|
|
127
127
|
readonly body: string;
|
|
128
128
|
readonly data: Record<string, unknown>;
|
|
129
129
|
readonly readAt: string | null;
|
|
130
|
+
/** When the user cleared it out of the inbox. A different state from read. */
|
|
131
|
+
readonly archivedAt: string | null;
|
|
130
132
|
readonly createdAt: string;
|
|
131
133
|
readonly tenantId: string | null;
|
|
132
134
|
}
|
|
@@ -139,6 +141,17 @@ export declare const inboxTable: Table<"_voltro_notification_inbox", FieldDefini
|
|
|
139
141
|
readonly body: ColumnBuilder<string, "text", boolean>;
|
|
140
142
|
readonly data: ColumnBuilder<Record<string, unknown>, "json", boolean>;
|
|
141
143
|
readonly readAt: ColumnBuilder<Date | null, "timestamp", boolean>;
|
|
144
|
+
/**
|
|
145
|
+
* ARCHIVED is a different state from READ, and for a user the more important
|
|
146
|
+
* one: it is what empties the inbox.
|
|
147
|
+
*
|
|
148
|
+
* Reported as the reason an app could not adopt this plugin. `readAt` covers
|
|
149
|
+
* read and `status` on the delivery table is the delivery outcome
|
|
150
|
+
* ('sent' | 'failed' | 'skipped') — neither is an archive, and the word did
|
|
151
|
+
* not appear anywhere in this plugin's types. An inbox a user cannot clear is
|
|
152
|
+
* one they stop opening.
|
|
153
|
+
*/
|
|
154
|
+
readonly archivedAt: ColumnBuilder<Date | null, "timestamp", boolean>;
|
|
142
155
|
readonly createdAt: ColumnBuilder<Date, "timestamp", true>;
|
|
143
156
|
readonly tenantId: ColumnBuilder<string | null, "text", boolean>;
|
|
144
157
|
}>, true, "byInboxSubject">;
|
|
@@ -147,6 +160,35 @@ export declare const inboxTable: Table<"_voltro_notification_inbox", FieldDefini
|
|
|
147
160
|
* midnight, e.g. 22:00→08:00). An empty window (start === end) is never active. */
|
|
148
161
|
export declare const inQuietHours: (qh: QuietHours, at: Date) => boolean;
|
|
149
162
|
|
|
163
|
+
/**
|
|
164
|
+
* WHO an inbox belongs to.
|
|
165
|
+
*
|
|
166
|
+
* `subject.id` is the framework's answer and it is not always the app's. A
|
|
167
|
+
* reporter's addressing unit is the EMPLOYEE: a shift change, an absence
|
|
168
|
+
* request or a task reminder is addressed to a person, and a person does not
|
|
169
|
+
* necessarily have an auth user. Their numbers, on 14 670 rows:
|
|
170
|
+
*
|
|
171
|
+
* employee WITH a userId 4 677 representable
|
|
172
|
+
* employee WITHOUT one 668 NOT — 4 people, 516 of those rows read,
|
|
173
|
+
* most recent 2026-06-19
|
|
174
|
+
*
|
|
175
|
+
* The 668 are live traffic, read by someone, and unaddressable under a
|
|
176
|
+
* subject-only model. Worse is what comes after a migration: every producer
|
|
177
|
+
* would resolve employee → userId and silently deliver NOTHING for anyone
|
|
178
|
+
* without an auth user — the exact failure this plugin's own docstring warns
|
|
179
|
+
* about, one level up and structural rather than accidental.
|
|
180
|
+
*
|
|
181
|
+
* So the app supplies it, the same seam `auth.resolveScopes` already offers for
|
|
182
|
+
* this shape. Absent keeps today's behaviour exactly.
|
|
183
|
+
*/
|
|
184
|
+
export declare const makeSubjectId: (resolve: NotificationsPluginOptions["resolveSubjectId"]) => (ctx: {
|
|
185
|
+
request: {
|
|
186
|
+
subject: {
|
|
187
|
+
id?: string | null;
|
|
188
|
+
};
|
|
189
|
+
};
|
|
190
|
+
}) => string;
|
|
191
|
+
|
|
150
192
|
export declare const memoryNotificationStore: () => NotificationStore;
|
|
151
193
|
|
|
152
194
|
/** The minute-of-day (0–1439) `at` falls on in the IANA `tz`. Uses `Intl` so no
|
|
@@ -166,6 +208,13 @@ export declare interface NotificationServiceShape {
|
|
|
166
208
|
}) => Promise<ReadonlyArray<InboxItem>>;
|
|
167
209
|
readonly unreadCount: (subjectId: string) => Promise<number>;
|
|
168
210
|
readonly markRead: (id: string, subjectId: string) => Promise<boolean>;
|
|
211
|
+
/** Undo a read. An inbox without the way back is a one-way ratchet. */
|
|
212
|
+
readonly markUnread: (id: string, subjectId: string) => Promise<boolean>;
|
|
213
|
+
/** Read everything; returns how many rows changed. */
|
|
214
|
+
readonly markAllRead: (subjectId: string) => Promise<number>;
|
|
215
|
+
/** Archive / unarchive. A different state from read — and the one that
|
|
216
|
+
* empties the inbox, which is why it matters more to a user. */
|
|
217
|
+
readonly setArchived: (id: string, subjectId: string, archived: boolean) => Promise<boolean>;
|
|
169
218
|
readonly getPreferences: (subjectId: string) => Promise<ReadonlyArray<ChannelPreference>>;
|
|
170
219
|
readonly setPreference: (pref: ChannelPreference) => Promise<void>;
|
|
171
220
|
readonly subscribe: (topic: string, subjectId: string, tenantId?: string | null) => Promise<void>;
|
|
@@ -180,6 +229,27 @@ export declare interface NotificationServiceShape {
|
|
|
180
229
|
export declare const notificationsPlugin: (options?: NotificationsPluginOptions) => VoltroPlugin;
|
|
181
230
|
|
|
182
231
|
export declare interface NotificationsPluginOptions {
|
|
232
|
+
/**
|
|
233
|
+
* Resolve WHO the caller's inbox belongs to, when that is not `subject.id`.
|
|
234
|
+
*
|
|
235
|
+
* The addressing unit is the app's, not the framework's. If yours is an
|
|
236
|
+
* employee, a member or a contact — something that need not have an auth user
|
|
237
|
+
* — return its id here and the whole surface (`inbox`, `unreadCount`,
|
|
238
|
+
* `markRead`, `archive`, preferences, quiet hours) follows.
|
|
239
|
+
*
|
|
240
|
+
* notificationsPlugin({ resolveSubjectId: (ctx) => resolveCallerEmployeeId(ctx) })
|
|
241
|
+
*
|
|
242
|
+
* Absent keeps `subject.id`, so nothing changes for an app whose units line
|
|
243
|
+
* up. Returning `undefined` for one caller falls back the same way rather
|
|
244
|
+
* than failing the read.
|
|
245
|
+
*/
|
|
246
|
+
readonly resolveSubjectId?: (ctx: {
|
|
247
|
+
readonly request: {
|
|
248
|
+
readonly subject: {
|
|
249
|
+
readonly id?: string | null;
|
|
250
|
+
};
|
|
251
|
+
};
|
|
252
|
+
}) => string | undefined;
|
|
183
253
|
/** Delivery channels. The in-app inbox channel is added automatically unless
|
|
184
254
|
* you pass your own `inApp` channel. Default `[consoleChannel()]` + in-app. */
|
|
185
255
|
readonly channels?: ReadonlyArray<Channel>;
|
|
@@ -198,7 +268,7 @@ export declare interface NotificationsPluginOptions {
|
|
|
198
268
|
}
|
|
199
269
|
|
|
200
270
|
export declare interface NotificationStore {
|
|
201
|
-
readonly addInbox: (item: Omit<InboxItem, 'id' | 'readAt' | 'createdAt'> & {
|
|
271
|
+
readonly addInbox: (item: Omit<InboxItem, 'id' | 'readAt' | 'archivedAt' | 'createdAt'> & {
|
|
202
272
|
id: string;
|
|
203
273
|
createdAt: string;
|
|
204
274
|
}) => Promise<void>;
|
|
@@ -207,6 +277,13 @@ export declare interface NotificationStore {
|
|
|
207
277
|
limit?: number;
|
|
208
278
|
}) => Promise<ReadonlyArray<InboxItem>>;
|
|
209
279
|
readonly markRead: (id: string, subjectId: string) => Promise<boolean>;
|
|
280
|
+
/** Clear the read stamp — an inbox needs the way back, not just forward. */
|
|
281
|
+
readonly markUnread: (id: string, subjectId: string) => Promise<boolean>;
|
|
282
|
+
/** Read EVERYTHING for this subject. Returns how many rows changed. */
|
|
283
|
+
readonly markAllRead: (subjectId: string) => Promise<number>;
|
|
284
|
+
/** Archive / unarchive — a different state from read, and the one that
|
|
285
|
+
* actually empties the inbox. */
|
|
286
|
+
readonly setArchived: (id: string, subjectId: string, archived: boolean) => Promise<boolean>;
|
|
210
287
|
readonly unreadCount: (subjectId: string) => Promise<number>;
|
|
211
288
|
readonly getPreferences: (subjectId: string) => Promise<ReadonlyArray<ChannelPreference>>;
|
|
212
289
|
readonly setPreference: (pref: ChannelPreference) => Promise<void>;
|