@classic-homes/notifications 0.1.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 ADDED
@@ -0,0 +1,483 @@
1
+ import { api } from '@classic-homes/auth/core';
2
+
3
+ // src/core/api.ts
4
+ var notificationsApi = {
5
+ // ============================================================================
6
+ // Notifications CRUD
7
+ // ============================================================================
8
+ /**
9
+ * List notifications with optional filters.
10
+ */
11
+ async list(params, customFetch) {
12
+ const queryParams = new URLSearchParams();
13
+ const page = params?.page || 1;
14
+ const limit = params?.limit || 20;
15
+ const offset = (page - 1) * limit;
16
+ queryParams.append("limit", limit.toString());
17
+ queryParams.append("offset", offset.toString());
18
+ if (params?.unreadOnly) {
19
+ queryParams.append("read", "false");
20
+ } else if (params?.readOnly) {
21
+ queryParams.append("read", "true");
22
+ }
23
+ if (params?.type) {
24
+ queryParams.append("type", params.type);
25
+ }
26
+ const response = await api.get(
27
+ `/notifications?${queryParams.toString()}`,
28
+ true,
29
+ customFetch
30
+ );
31
+ return response;
32
+ },
33
+ /**
34
+ * Get a single notification by ID.
35
+ */
36
+ async get(id, customFetch) {
37
+ const response = await api.get(
38
+ `/notifications/${id}`,
39
+ true,
40
+ customFetch
41
+ );
42
+ return response.notification;
43
+ },
44
+ /**
45
+ * Mark a notification as read.
46
+ */
47
+ async markRead(id) {
48
+ await api.patch(`/notifications/${id}/read`, {}, true);
49
+ },
50
+ /**
51
+ * Mark multiple notifications as read.
52
+ */
53
+ async markManyRead(ids) {
54
+ await api.post("/notifications/mark-read", { ids }, true);
55
+ },
56
+ /**
57
+ * Mark all notifications as read.
58
+ */
59
+ async markAllRead() {
60
+ await api.post("/notifications/mark-read", { all: true }, true);
61
+ },
62
+ /**
63
+ * Dismiss (delete) a notification.
64
+ */
65
+ async dismiss(id) {
66
+ await api.delete(`/notifications/${id}`, true);
67
+ },
68
+ /**
69
+ * Delete multiple notifications in bulk.
70
+ */
71
+ async bulkDelete(ids) {
72
+ await api.post("/notifications/bulk-delete", { ids }, true);
73
+ },
74
+ /**
75
+ * Delete all notifications.
76
+ */
77
+ async deleteAll() {
78
+ await api.post("/notifications/bulk-delete", { all: true }, true);
79
+ },
80
+ // ============================================================================
81
+ // Notification Channels
82
+ // ============================================================================
83
+ /**
84
+ * Get available notification channels.
85
+ */
86
+ async getChannels(customFetch) {
87
+ const response = await api.get("/notifications/channels", true, customFetch);
88
+ return response;
89
+ },
90
+ // ============================================================================
91
+ // Notification Preferences
92
+ // ============================================================================
93
+ /**
94
+ * Get notification preferences.
95
+ */
96
+ async getPreferences(params, customFetch) {
97
+ const queryParams = new URLSearchParams();
98
+ if (params?.channelId) queryParams.append("channelId", params.channelId);
99
+ if (params?.notificationType) queryParams.append("notificationType", params.notificationType);
100
+ const response = await api.get(
101
+ `/notifications/preferences?${queryParams.toString()}`,
102
+ true,
103
+ customFetch
104
+ );
105
+ return response;
106
+ },
107
+ /**
108
+ * Update a notification preference.
109
+ */
110
+ async updatePreference(preference) {
111
+ const response = await api.put(
112
+ "/notifications/preferences",
113
+ preference,
114
+ true
115
+ );
116
+ return response;
117
+ },
118
+ /**
119
+ * Batch update notification preferences.
120
+ */
121
+ async batchUpdatePreferences(preferences) {
122
+ const response = await api.post(
123
+ "/notifications/preferences/batch",
124
+ { preferences },
125
+ true
126
+ );
127
+ const data = response;
128
+ return data.data || data;
129
+ },
130
+ /**
131
+ * Delete a notification preference.
132
+ */
133
+ async deletePreference(subscriptionId) {
134
+ const response = await api.delete(
135
+ `/notifications/preferences/${subscriptionId}`,
136
+ true
137
+ );
138
+ return response;
139
+ },
140
+ // ============================================================================
141
+ // Test Notifications (Dev/Admin)
142
+ // ============================================================================
143
+ /**
144
+ * Generate test notifications.
145
+ */
146
+ async generateTestNotifications(params) {
147
+ const response = await api.post(
148
+ "/notifications/test",
149
+ params || {},
150
+ true
151
+ );
152
+ const data = response;
153
+ return data.data ?? data;
154
+ }
155
+ };
156
+
157
+ // src/core/service.ts
158
+ var NotificationService = class {
159
+ // ============================================================================
160
+ // Notifications CRUD
161
+ // ============================================================================
162
+ /**
163
+ * List notifications with optional filters.
164
+ */
165
+ async list(params, customFetch) {
166
+ return await notificationsApi.list(params, customFetch);
167
+ }
168
+ /**
169
+ * Get a single notification by ID.
170
+ */
171
+ async get(id, customFetch) {
172
+ return await notificationsApi.get(id, customFetch);
173
+ }
174
+ /**
175
+ * Mark a notification as read.
176
+ */
177
+ async markRead(id) {
178
+ await notificationsApi.markRead(id);
179
+ }
180
+ /**
181
+ * Mark multiple notifications as read.
182
+ */
183
+ async markManyRead(ids) {
184
+ await notificationsApi.markManyRead(ids);
185
+ }
186
+ /**
187
+ * Mark all notifications as read.
188
+ */
189
+ async markAllRead() {
190
+ await notificationsApi.markAllRead();
191
+ }
192
+ /**
193
+ * Dismiss (delete) a notification.
194
+ */
195
+ async dismiss(id) {
196
+ await notificationsApi.dismiss(id);
197
+ }
198
+ /**
199
+ * Delete multiple notifications in bulk.
200
+ */
201
+ async bulkDelete(ids) {
202
+ await notificationsApi.bulkDelete(ids);
203
+ }
204
+ /**
205
+ * Delete all notifications.
206
+ */
207
+ async deleteAll() {
208
+ await notificationsApi.deleteAll();
209
+ }
210
+ // ============================================================================
211
+ // Notification Channels
212
+ // ============================================================================
213
+ /**
214
+ * Get available notification channels.
215
+ */
216
+ async getChannels(customFetch) {
217
+ return await notificationsApi.getChannels(customFetch);
218
+ }
219
+ // ============================================================================
220
+ // Notification Preferences
221
+ // ============================================================================
222
+ /**
223
+ * Get notification preferences.
224
+ */
225
+ async getPreferences(params, customFetch) {
226
+ return await notificationsApi.getPreferences(params, customFetch);
227
+ }
228
+ /**
229
+ * Update a notification preference.
230
+ */
231
+ async updatePreference(preference) {
232
+ return await notificationsApi.updatePreference(preference);
233
+ }
234
+ /**
235
+ * Batch update notification preferences.
236
+ */
237
+ async batchUpdatePreferences(preferences) {
238
+ return await notificationsApi.batchUpdatePreferences(preferences);
239
+ }
240
+ /**
241
+ * Delete a notification preference.
242
+ */
243
+ async deletePreference(subscriptionId) {
244
+ return await notificationsApi.deletePreference(subscriptionId);
245
+ }
246
+ // ============================================================================
247
+ // Test Notifications
248
+ // ============================================================================
249
+ /**
250
+ * Generate test notifications (dev/admin only).
251
+ */
252
+ async generateTestNotifications(params) {
253
+ return await notificationsApi.generateTestNotifications(params);
254
+ }
255
+ };
256
+ var notificationService = new NotificationService();
257
+
258
+ // src/svelte/stores/notifications.svelte.ts
259
+ var NotificationStore = class {
260
+ constructor() {
261
+ this.subscribers = /* @__PURE__ */ new Set();
262
+ this.state = {
263
+ notifications: [],
264
+ unreadCount: 0,
265
+ isLoading: false,
266
+ error: null,
267
+ pagination: {
268
+ page: 1,
269
+ limit: 20,
270
+ total: 0,
271
+ totalPages: 0
272
+ }
273
+ };
274
+ }
275
+ /**
276
+ * Subscribe to state changes (Svelte store contract).
277
+ */
278
+ subscribe(subscriber) {
279
+ this.subscribers.add(subscriber);
280
+ subscriber(this.state);
281
+ return () => this.subscribers.delete(subscriber);
282
+ }
283
+ notify() {
284
+ this.subscribers.forEach((sub) => sub(this.state));
285
+ }
286
+ setState(partial) {
287
+ this.state = { ...this.state, ...partial };
288
+ this.notify();
289
+ }
290
+ // Getters for direct access
291
+ get notifications() {
292
+ return this.state.notifications;
293
+ }
294
+ get unreadCount() {
295
+ return this.state.unreadCount;
296
+ }
297
+ get isLoading() {
298
+ return this.state.isLoading;
299
+ }
300
+ get error() {
301
+ return this.state.error;
302
+ }
303
+ /**
304
+ * Fetch notifications from the API.
305
+ */
306
+ async fetch(params) {
307
+ this.setState({ isLoading: true, error: null });
308
+ try {
309
+ const response = await notificationsApi.list(params);
310
+ this.setState({
311
+ notifications: response.notifications,
312
+ unreadCount: response.unreadCount,
313
+ pagination: response.pagination,
314
+ isLoading: false
315
+ });
316
+ } catch (error) {
317
+ this.setState({
318
+ error: error instanceof Error ? error.message : "Failed to fetch notifications",
319
+ isLoading: false
320
+ });
321
+ }
322
+ }
323
+ /**
324
+ * Refresh notifications (re-fetch with current params).
325
+ */
326
+ async refresh() {
327
+ await this.fetch({
328
+ page: this.state.pagination.page,
329
+ limit: this.state.pagination.limit
330
+ });
331
+ }
332
+ /**
333
+ * Load more notifications (next page).
334
+ */
335
+ async loadMore() {
336
+ if (this.state.pagination.page >= this.state.pagination.totalPages) {
337
+ return;
338
+ }
339
+ this.setState({ isLoading: true, error: null });
340
+ try {
341
+ const response = await notificationsApi.list({
342
+ page: this.state.pagination.page + 1,
343
+ limit: this.state.pagination.limit
344
+ });
345
+ this.setState({
346
+ notifications: [...this.state.notifications, ...response.notifications],
347
+ unreadCount: response.unreadCount,
348
+ pagination: response.pagination,
349
+ isLoading: false
350
+ });
351
+ } catch (error) {
352
+ this.setState({
353
+ error: error instanceof Error ? error.message : "Failed to load more notifications",
354
+ isLoading: false
355
+ });
356
+ }
357
+ }
358
+ /**
359
+ * Mark a notification as read.
360
+ */
361
+ async markRead(id) {
362
+ try {
363
+ await notificationsApi.markRead(id);
364
+ const notifications2 = this.state.notifications.map(
365
+ (n) => n.id === id ? { ...n, read: true, readAt: (/* @__PURE__ */ new Date()).toISOString() } : n
366
+ );
367
+ const unreadCount2 = Math.max(0, this.state.unreadCount - 1);
368
+ this.setState({ notifications: notifications2, unreadCount: unreadCount2 });
369
+ } catch (error) {
370
+ this.setState({
371
+ error: error instanceof Error ? error.message : "Failed to mark notification as read"
372
+ });
373
+ }
374
+ }
375
+ /**
376
+ * Mark multiple notifications as read.
377
+ */
378
+ async markManyRead(ids) {
379
+ try {
380
+ await notificationsApi.markManyRead(ids);
381
+ const notifications2 = this.state.notifications.map(
382
+ (n) => ids.includes(n.id) ? { ...n, read: true, readAt: (/* @__PURE__ */ new Date()).toISOString() } : n
383
+ );
384
+ const readCount = this.state.notifications.filter(
385
+ (n) => ids.includes(n.id) && !n.read
386
+ ).length;
387
+ const unreadCount2 = Math.max(0, this.state.unreadCount - readCount);
388
+ this.setState({ notifications: notifications2, unreadCount: unreadCount2 });
389
+ } catch (error) {
390
+ this.setState({
391
+ error: error instanceof Error ? error.message : "Failed to mark notifications as read"
392
+ });
393
+ }
394
+ }
395
+ /**
396
+ * Mark all notifications as read.
397
+ */
398
+ async markAllRead() {
399
+ try {
400
+ await notificationsApi.markAllRead();
401
+ const notifications2 = this.state.notifications.map((n) => ({
402
+ ...n,
403
+ read: true,
404
+ readAt: n.readAt || (/* @__PURE__ */ new Date()).toISOString()
405
+ }));
406
+ this.setState({ notifications: notifications2, unreadCount: 0 });
407
+ } catch (error) {
408
+ this.setState({
409
+ error: error instanceof Error ? error.message : "Failed to mark all notifications as read"
410
+ });
411
+ }
412
+ }
413
+ /**
414
+ * Dismiss (delete) a notification.
415
+ */
416
+ async dismiss(id) {
417
+ try {
418
+ await notificationsApi.dismiss(id);
419
+ const dismissed = this.state.notifications.find((n) => n.id === id);
420
+ const notifications2 = this.state.notifications.filter((n) => n.id !== id);
421
+ const unreadCount2 = dismissed && !dismissed.read ? Math.max(0, this.state.unreadCount - 1) : this.state.unreadCount;
422
+ this.setState({ notifications: notifications2, unreadCount: unreadCount2 });
423
+ } catch (error) {
424
+ this.setState({
425
+ error: error instanceof Error ? error.message : "Failed to dismiss notification"
426
+ });
427
+ }
428
+ }
429
+ /**
430
+ * Delete all notifications.
431
+ */
432
+ async deleteAll() {
433
+ try {
434
+ await notificationsApi.deleteAll();
435
+ this.setState({ notifications: [], unreadCount: 0 });
436
+ } catch (error) {
437
+ this.setState({
438
+ error: error instanceof Error ? error.message : "Failed to delete all notifications"
439
+ });
440
+ }
441
+ }
442
+ /**
443
+ * Clear the error state.
444
+ */
445
+ clearError() {
446
+ this.setState({ error: null });
447
+ }
448
+ /**
449
+ * Reset the store to initial state.
450
+ */
451
+ reset() {
452
+ this.setState({
453
+ notifications: [],
454
+ unreadCount: 0,
455
+ isLoading: false,
456
+ error: null,
457
+ pagination: {
458
+ page: 1,
459
+ limit: 20,
460
+ total: 0,
461
+ totalPages: 0
462
+ }
463
+ });
464
+ }
465
+ };
466
+ var notificationStore = new NotificationStore();
467
+ var unreadCount = {
468
+ subscribe: (subscriber) => {
469
+ return notificationStore.subscribe((state) => subscriber(state.unreadCount));
470
+ }
471
+ };
472
+ var notifications = {
473
+ subscribe: (subscriber) => {
474
+ return notificationStore.subscribe((state) => subscriber(state.notifications));
475
+ }
476
+ };
477
+ var isLoadingNotifications = {
478
+ subscribe: (subscriber) => {
479
+ return notificationStore.subscribe((state) => subscriber(state.isLoading));
480
+ }
481
+ };
482
+
483
+ export { NotificationService, isLoadingNotifications, notificationService, notificationStore, notifications, notificationsApi, unreadCount };
@@ -0,0 +1,101 @@
1
+ import { b as Notification, d as NotificationListParams } from '../types-BSztr7EQ.js';
2
+ export { a as NotificationPriority, N as NotificationType } from '../types-BSztr7EQ.js';
3
+
4
+ /**
5
+ * Notifications Store
6
+ *
7
+ * Reactive notification state management.
8
+ * Uses a simple observable pattern that works with Svelte's reactivity.
9
+ */
10
+
11
+ type Subscriber<T> = (value: T) => void;
12
+ type Unsubscriber = () => void;
13
+ interface NotificationState {
14
+ notifications: Notification[];
15
+ unreadCount: number;
16
+ isLoading: boolean;
17
+ error: string | null;
18
+ pagination: {
19
+ page: number;
20
+ limit: number;
21
+ total: number;
22
+ totalPages: number;
23
+ };
24
+ }
25
+ declare class NotificationStore {
26
+ private state;
27
+ private subscribers;
28
+ constructor();
29
+ /**
30
+ * Subscribe to state changes (Svelte store contract).
31
+ */
32
+ subscribe(subscriber: Subscriber<NotificationState>): Unsubscriber;
33
+ private notify;
34
+ private setState;
35
+ get notifications(): Notification[];
36
+ get unreadCount(): number;
37
+ get isLoading(): boolean;
38
+ get error(): string | null;
39
+ /**
40
+ * Fetch notifications from the API.
41
+ */
42
+ fetch(params?: NotificationListParams): Promise<void>;
43
+ /**
44
+ * Refresh notifications (re-fetch with current params).
45
+ */
46
+ refresh(): Promise<void>;
47
+ /**
48
+ * Load more notifications (next page).
49
+ */
50
+ loadMore(): Promise<void>;
51
+ /**
52
+ * Mark a notification as read.
53
+ */
54
+ markRead(id: string): Promise<void>;
55
+ /**
56
+ * Mark multiple notifications as read.
57
+ */
58
+ markManyRead(ids: string[]): Promise<void>;
59
+ /**
60
+ * Mark all notifications as read.
61
+ */
62
+ markAllRead(): Promise<void>;
63
+ /**
64
+ * Dismiss (delete) a notification.
65
+ */
66
+ dismiss(id: string): Promise<void>;
67
+ /**
68
+ * Delete all notifications.
69
+ */
70
+ deleteAll(): Promise<void>;
71
+ /**
72
+ * Clear the error state.
73
+ */
74
+ clearError(): void;
75
+ /**
76
+ * Reset the store to initial state.
77
+ */
78
+ reset(): void;
79
+ }
80
+ /** Singleton notification store instance */
81
+ declare const notificationStore: NotificationStore;
82
+ /**
83
+ * Derived store for unread count.
84
+ */
85
+ declare const unreadCount: {
86
+ subscribe: (subscriber: Subscriber<number>) => Unsubscriber;
87
+ };
88
+ /**
89
+ * Derived store for notifications list.
90
+ */
91
+ declare const notifications: {
92
+ subscribe: (subscriber: Subscriber<Notification[]>) => Unsubscriber;
93
+ };
94
+ /**
95
+ * Derived store for loading state.
96
+ */
97
+ declare const isLoadingNotifications: {
98
+ subscribe: (subscriber: Subscriber<boolean>) => Unsubscriber;
99
+ };
100
+
101
+ export { Notification, isLoadingNotifications, notificationStore, notifications, unreadCount };