@vynelix/vynemit-core 1.0.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 +400 -0
- package/dist/index.d.mts +335 -0
- package/dist/index.d.ts +335 -0
- package/dist/index.js +829 -0
- package/dist/index.mjs +799 -0
- package/package.json +67 -0
package/README.md
ADDED
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
# @vynelix/vynemit-core
|
|
2
|
+
|
|
3
|
+
> A framework-agnostic notification system with unified dispatch, storage, and transport layers.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
β¨ **Unified Notification Model** - Single interface for in-app, push, email, SMS, and webhooks
|
|
8
|
+
**Event-Based Dispatch** - Reactive system with real-time subscriptions
|
|
9
|
+
π **Read/Unread Tracking** - Built-in state management
|
|
10
|
+
ποΈ **Channel Filters** - User preferences for notification channels
|
|
11
|
+
β‘ **Queue Support** - Redis, BullMQ, or in-memory queues
|
|
12
|
+
π **Pluggable Architecture** - Swap storage and transport adapters
|
|
13
|
+
π¨ **Template System** - Reusable notification templates
|
|
14
|
+
π **Middleware Support** - Rate limiting, deduplication, analytics
|
|
15
|
+
**Zero Dependencies** - Lightweight core with optional adapters
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @vynelix/vynemit-core
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import {
|
|
27
|
+
NotificationCenter,
|
|
28
|
+
MemoryStorageAdapter,
|
|
29
|
+
ConsoleTransportAdapter
|
|
30
|
+
} from '@vynelix/vynemit-core';
|
|
31
|
+
|
|
32
|
+
// Initialize
|
|
33
|
+
const center = new NotificationCenter({
|
|
34
|
+
storage: new MemoryStorageAdapter(),
|
|
35
|
+
transports: [
|
|
36
|
+
new ConsoleTransportAdapter('inapp'),
|
|
37
|
+
new ConsoleTransportAdapter('push')
|
|
38
|
+
]
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
await center.start();
|
|
42
|
+
|
|
43
|
+
// Send notification
|
|
44
|
+
await center.send({
|
|
45
|
+
userId: 'user:123',
|
|
46
|
+
type: 'comment',
|
|
47
|
+
title: 'New Comment',
|
|
48
|
+
body: 'Someone replied to your post',
|
|
49
|
+
channels: ['inapp', 'push'],
|
|
50
|
+
priority: 'normal'
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Subscribe to real-time updates
|
|
54
|
+
center.subscribe('user:123', (notification) => {
|
|
55
|
+
console.log('New notification:', notification);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Get notifications
|
|
59
|
+
const notifications = await center.getForUser('user:123', {
|
|
60
|
+
status: 'unread',
|
|
61
|
+
limit: 10
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Mark as read
|
|
65
|
+
await center.markAsRead(notifications[0].id);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Core Concepts
|
|
69
|
+
|
|
70
|
+
### 1. Notification Model
|
|
71
|
+
|
|
72
|
+
Every notification has a consistent structure:
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
interface Notification {
|
|
76
|
+
id: string;
|
|
77
|
+
type: string; // 'comment', 'like', 'system', etc.
|
|
78
|
+
title: string;
|
|
79
|
+
body: string;
|
|
80
|
+
data?: Record<string, unknown>;
|
|
81
|
+
|
|
82
|
+
userId: string; // Who receives it
|
|
83
|
+
groupId?: string; // Optional grouping
|
|
84
|
+
|
|
85
|
+
priority: 'low' | 'normal' | 'high' | 'urgent';
|
|
86
|
+
category?: string; // For filtering
|
|
87
|
+
|
|
88
|
+
status: 'pending' | 'sent' | 'delivered' | 'failed' | 'read';
|
|
89
|
+
channels: ChannelType[]; // ['inapp', 'push', 'email']
|
|
90
|
+
|
|
91
|
+
createdAt: Date;
|
|
92
|
+
readAt?: Date;
|
|
93
|
+
scheduledFor?: Date;
|
|
94
|
+
expiresAt?: Date;
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 2. Storage Adapters
|
|
99
|
+
|
|
100
|
+
Storage adapters handle persistence:
|
|
101
|
+
|
|
102
|
+
- `MemoryStorageAdapter` - In-memory (development/testing)
|
|
103
|
+
- `PostgresStorageAdapter` - PostgreSQL (production)
|
|
104
|
+
- `MongoStorageAdapter` - MongoDB
|
|
105
|
+
- `FirestoreStorageAdapter` - Google Firestore
|
|
106
|
+
- `RestStorageAdapter` - External API
|
|
107
|
+
|
|
108
|
+
### 3. Transport Adapters
|
|
109
|
+
|
|
110
|
+
Transport adapters handle delivery:
|
|
111
|
+
|
|
112
|
+
- `ConsoleTransportAdapter` - Console logging (development)
|
|
113
|
+
- `EmailTransportAdapter` - Email via SMTP/SendGrid
|
|
114
|
+
- `PushTransportAdapter` - Push via Firebase/OneSignal
|
|
115
|
+
- `SmsTransportAdapter` - SMS via Twilio
|
|
116
|
+
- `WebhookTransportAdapter` - Custom webhooks
|
|
117
|
+
|
|
118
|
+
### 4. Templates
|
|
119
|
+
|
|
120
|
+
Templates make notifications reusable:
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
center.registerTemplate({
|
|
124
|
+
id: 'new-comment',
|
|
125
|
+
type: 'comment',
|
|
126
|
+
defaults: {
|
|
127
|
+
title: (data) => `${data.author} commented on your post`,
|
|
128
|
+
body: (data) => data.text,
|
|
129
|
+
channels: ['inapp', 'push'],
|
|
130
|
+
priority: 'normal'
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Use template
|
|
135
|
+
await center.send({
|
|
136
|
+
template: 'new-comment',
|
|
137
|
+
userId: 'user:123',
|
|
138
|
+
data: { author: 'Alice', text: 'Great post!' }
|
|
139
|
+
});
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 5. User Preferences
|
|
143
|
+
|
|
144
|
+
Users control which notifications they receive:
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
await center.updatePreferences('user:123', {
|
|
148
|
+
userId: 'user:123',
|
|
149
|
+
channels: {
|
|
150
|
+
email: {
|
|
151
|
+
enabled: true,
|
|
152
|
+
categories: ['important', 'security'],
|
|
153
|
+
quietHours: {
|
|
154
|
+
start: '22:00',
|
|
155
|
+
end: '08:00'
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
push: {
|
|
159
|
+
enabled: true,
|
|
160
|
+
frequency: 'realtime'
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
globalMute: false
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### 6. Middleware
|
|
168
|
+
|
|
169
|
+
Extend functionality with middleware:
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
center.use({
|
|
173
|
+
name: 'rate-limit',
|
|
174
|
+
async beforeSend(notification) {
|
|
175
|
+
// Check rate limits
|
|
176
|
+
const allowed = await checkRateLimit(notification.userId);
|
|
177
|
+
return allowed ? notification : null; // null = skip
|
|
178
|
+
},
|
|
179
|
+
async afterSend(notification) {
|
|
180
|
+
// Track analytics
|
|
181
|
+
await analytics.track('notification_sent', notification);
|
|
182
|
+
},
|
|
183
|
+
async onError(error, notification) {
|
|
184
|
+
// Log errors
|
|
185
|
+
console.error('Failed:', error);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Advanced Usage
|
|
191
|
+
|
|
192
|
+
### Scheduled Notifications
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
// Send in 1 hour
|
|
196
|
+
await center.schedule({
|
|
197
|
+
userId: 'user:123',
|
|
198
|
+
type: 'reminder',
|
|
199
|
+
title: 'Meeting Soon',
|
|
200
|
+
body: 'Your meeting starts in 15 minutes',
|
|
201
|
+
channels: ['push'],
|
|
202
|
+
priority: 'urgent'
|
|
203
|
+
}, new Date(Date.now() + 3600000));
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Batch Operations
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
await center.sendBatch([
|
|
210
|
+
{ userId: 'user:1', type: 'update', title: 'A', body: 'B', channels: ['inapp'] },
|
|
211
|
+
{ userId: 'user:2', type: 'update', title: 'C', body: 'D', channels: ['inapp'] }
|
|
212
|
+
]);
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Real-time Subscriptions
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
// Subscribe to new notifications
|
|
219
|
+
const unsubscribe = center.subscribe('user:123', (notification) => {
|
|
220
|
+
console.log('New:', notification);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
// Subscribe to unread count changes
|
|
224
|
+
center.onUnreadCountChange('user:123', (count) => {
|
|
225
|
+
updateBadge(count);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// Subscribe to all events
|
|
229
|
+
center.subscribeToEvents('user:123', (event) => {
|
|
230
|
+
console.log(event.type); // 'sent', 'delivered', 'read', 'failed'
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Cleanup
|
|
234
|
+
unsubscribe();
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Digest Mode
|
|
238
|
+
|
|
239
|
+
Batch notifications into digests:
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
await center.enableDigest('user:123', {
|
|
243
|
+
userId: 'user:123',
|
|
244
|
+
frequency: 'daily',
|
|
245
|
+
channels: ['email'],
|
|
246
|
+
categories: ['social', 'updates']
|
|
247
|
+
});
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Delivery Status
|
|
251
|
+
|
|
252
|
+
Track delivery across channels:
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
const receipts = await center.getDeliveryStatus('notif_123');
|
|
256
|
+
receipts.forEach(receipt => {
|
|
257
|
+
console.log(`${receipt.channel}: ${receipt.status}`);
|
|
258
|
+
// inapp: delivered
|
|
259
|
+
// push: delivered
|
|
260
|
+
// email: failed
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// Retry failed
|
|
264
|
+
await center.retryFailed('notif_123', 'email');
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Architecture
|
|
268
|
+
|
|
269
|
+
```
|
|
270
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
271
|
+
β NotificationCenter (Core) β
|
|
272
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββ€
|
|
273
|
+
β β’ Event Dispatch β
|
|
274
|
+
β β’ Template Management β
|
|
275
|
+
β β’ Middleware Pipeline β
|
|
276
|
+
β β’ Subscription System β
|
|
277
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
278
|
+
β β β
|
|
279
|
+
ββββββ΄βββββ ββββββ΄βββββ ββββββ΄βββββ
|
|
280
|
+
β Storage β β Queue β βTransportβ
|
|
281
|
+
β Adapter β β Adapter β β Adapter β
|
|
282
|
+
βββββββββββ βββββββββββ βββββββββββ
|
|
283
|
+
β β β
|
|
284
|
+
ββββββ΄βββββ ββββββ΄βββββ ββββββ΄βββββ
|
|
285
|
+
βPostgres β β Redis β β Firebaseβ
|
|
286
|
+
β MongoDB β β BullMQ β β SendGridβ
|
|
287
|
+
βFirestoreβ β Memory β β Twilio β
|
|
288
|
+
βββββββββββ βββββββββββ βββββββββββ
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Framework Bindings
|
|
292
|
+
|
|
293
|
+
Use framework-specific bindings for seamless integration:
|
|
294
|
+
|
|
295
|
+
### React
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
npm install @vynelix/vynemit-react
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
```tsx
|
|
302
|
+
import { NotificationProvider, useNotifications } from '@vynelix/vynemit-react';
|
|
303
|
+
|
|
304
|
+
function App() {
|
|
305
|
+
return (
|
|
306
|
+
<NotificationProvider apiUrl="/api/notifications" userId="user:123">
|
|
307
|
+
<NotificationBell />
|
|
308
|
+
</NotificationProvider>
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function NotificationBell() {
|
|
313
|
+
const { notifications, unreadCount, markAsRead } = useNotifications();
|
|
314
|
+
|
|
315
|
+
return (
|
|
316
|
+
<Badge count={unreadCount}>
|
|
317
|
+
<Bell />
|
|
318
|
+
</Badge>
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### NestJS
|
|
324
|
+
|
|
325
|
+
```bash
|
|
326
|
+
npm install @vynelix/vynemit-nestjs
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
import { NotificationsModule } from '@vynelix/vynemit-nestjs';
|
|
331
|
+
|
|
332
|
+
@Module({
|
|
333
|
+
imports: [
|
|
334
|
+
NotificationsModule.forRoot({
|
|
335
|
+
storage: new PostgresStorageAdapter(),
|
|
336
|
+
transports: [new EmailTransportAdapter(), new PushTransportAdapter()]
|
|
337
|
+
})
|
|
338
|
+
]
|
|
339
|
+
})
|
|
340
|
+
export class AppModule {}
|
|
341
|
+
|
|
342
|
+
@Injectable()
|
|
343
|
+
export class UserService {
|
|
344
|
+
constructor(private notifications: NotificationCenter) {}
|
|
345
|
+
|
|
346
|
+
async welcomeUser(userId: string) {
|
|
347
|
+
await this.notifications.send({
|
|
348
|
+
userId,
|
|
349
|
+
type: 'welcome',
|
|
350
|
+
title: 'Welcome!',
|
|
351
|
+
body: 'Thanks for joining',
|
|
352
|
+
channels: ['inapp', 'email']
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### Flutter
|
|
359
|
+
|
|
360
|
+
```bash
|
|
361
|
+
flutter pub add synq_notifications
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
```dart
|
|
365
|
+
import 'package:synq_notifications/synq_notifications.dart';
|
|
366
|
+
|
|
367
|
+
final notificationCenter = NotificationCenter(
|
|
368
|
+
storage: MemoryStorageAdapter(),
|
|
369
|
+
transports: [ConsoleTransportAdapter()]
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
// Subscribe
|
|
373
|
+
notificationCenter.subscribe('user:123', (notification) {
|
|
374
|
+
print('New: ${notification.title}');
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
// Send
|
|
378
|
+
await notificationCenter.send(
|
|
379
|
+
userId: 'user:123',
|
|
380
|
+
type: 'comment',
|
|
381
|
+
title: 'New Comment',
|
|
382
|
+
body: 'Someone replied',
|
|
383
|
+
channels: ['inapp']
|
|
384
|
+
);
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
## License
|
|
388
|
+
|
|
389
|
+
MIT Β© [Your Name]
|
|
390
|
+
|
|
391
|
+
## Contributing
|
|
392
|
+
|
|
393
|
+
Contributions welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) first.
|
|
394
|
+
|
|
395
|
+
## Support
|
|
396
|
+
|
|
397
|
+
- π§ Email: support@synq.dev
|
|
398
|
+
- π¬ Discord: [Join our community](https://discord.gg/synq)
|
|
399
|
+
- π Docs: [docs.synq.dev](https://docs.synq.dev)
|
|
400
|
+
- π Issues: [GitHub Issues](https://github.com/yourusername/synq-notifications/issues)
|