@allmightypush/push 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 +267 -0
- package/dist/cjs/index.js +22 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
# @allmightypush/push
|
|
2
|
+
|
|
3
|
+
> Modular, TypeScript-first push notification library for Node.js with Web Push (VAPID) support
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🚀 **Production-ready** - Comprehensive error handling and retry logic
|
|
8
|
+
- 📦 **Modular** - Use only what you need with pluggable adapters
|
|
9
|
+
- 🔒 **Type-safe** - Full TypeScript support with strict mode
|
|
10
|
+
- ⚡ **Reliable** - Circuit breaker, rate limiting, and exponential backoff
|
|
11
|
+
- 🔄 **Automatic retries** - Background worker for failed notifications
|
|
12
|
+
- 🎯 **Batch sending** - Efficient bulk notification delivery
|
|
13
|
+
- 📊 **Observable** - Lifecycle hooks and metrics integration
|
|
14
|
+
- 🛡️ **Graceful shutdown** - No data loss on termination
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @allmightypush/push
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
This meta-package includes:
|
|
23
|
+
- `@allmightypush/push-core` - Core runtime engine
|
|
24
|
+
- `@allmightypush/push-webpush` - Web Push (VAPID) provider
|
|
25
|
+
- `@allmightypush/push-storage-sqlite` - SQLite storage adapter
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { PushCore, RetryWorker, SQLiteStorageAdapter, WebPushProvider } from '@allmightypush/push';
|
|
31
|
+
|
|
32
|
+
// 1. Configure the push system
|
|
33
|
+
const pushCore = new PushCore();
|
|
34
|
+
const storage = new SQLiteStorageAdapter({ filename: './push.db' });
|
|
35
|
+
|
|
36
|
+
pushCore.configure({
|
|
37
|
+
vapidKeys: {
|
|
38
|
+
publicKey: 'your-vapid-public-key',
|
|
39
|
+
privateKey: 'your-vapid-private-key',
|
|
40
|
+
subject: 'mailto:admin@example.com',
|
|
41
|
+
},
|
|
42
|
+
storageAdapter: storage,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// 2. Create a subscription
|
|
46
|
+
const subscription = await storage.createSubscription({
|
|
47
|
+
endpoint: 'https://fcm.googleapis.com/fcm/send/...',
|
|
48
|
+
keys: {
|
|
49
|
+
p256dh: 'user-public-key',
|
|
50
|
+
auth: 'user-auth-secret',
|
|
51
|
+
},
|
|
52
|
+
status: 'active',
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// 3. Send a notification
|
|
56
|
+
const result = await pushCore.sendNotification(subscription, {
|
|
57
|
+
title: 'Hello!',
|
|
58
|
+
body: 'This is a push notification',
|
|
59
|
+
icon: '/icon.png',
|
|
60
|
+
data: { url: '/news/article-1' },
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
console.log('Notification sent:', result.success);
|
|
64
|
+
|
|
65
|
+
// 4. Start worker for retry processing (optional)
|
|
66
|
+
const worker = new RetryWorker(
|
|
67
|
+
storage,
|
|
68
|
+
new WebPushProvider({
|
|
69
|
+
vapidPublicKey: 'your-vapid-public-key',
|
|
70
|
+
vapidPrivateKey: 'your-vapid-private-key',
|
|
71
|
+
vapidSubject: 'mailto:admin@example.com',
|
|
72
|
+
}),
|
|
73
|
+
{
|
|
74
|
+
maxRetries: 8,
|
|
75
|
+
baseDelay: 1000,
|
|
76
|
+
backoffFactor: 2,
|
|
77
|
+
maxDelay: 3600000,
|
|
78
|
+
jitter: true,
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
await worker.start();
|
|
83
|
+
|
|
84
|
+
// 5. Graceful shutdown
|
|
85
|
+
process.on('SIGTERM', async () => {
|
|
86
|
+
await worker.stop();
|
|
87
|
+
await pushCore.shutdown();
|
|
88
|
+
process.exit(0);
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Batch Sending
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
const subscriptions = await storage.findSubscriptions({ status: 'active' });
|
|
96
|
+
|
|
97
|
+
const result = await pushCore.batchSend(subscriptions, {
|
|
98
|
+
title: 'Breaking News',
|
|
99
|
+
body: 'Important update for all users',
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
console.log(`Sent to ${result.success}/${result.total} subscriptions`);
|
|
103
|
+
console.log(`Failed: ${result.failed}, Retried: ${result.retried}`);
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Advanced Configuration
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
pushCore.configure({
|
|
110
|
+
vapidKeys: {
|
|
111
|
+
publicKey: process.env.VAPID_PUBLIC_KEY!,
|
|
112
|
+
privateKey: process.env.VAPID_PRIVATE_KEY!,
|
|
113
|
+
subject: 'mailto:admin@example.com',
|
|
114
|
+
},
|
|
115
|
+
storageAdapter: storage,
|
|
116
|
+
|
|
117
|
+
// Retry policy
|
|
118
|
+
retryPolicy: {
|
|
119
|
+
maxRetries: 8,
|
|
120
|
+
baseDelay: 1000,
|
|
121
|
+
backoffFactor: 2,
|
|
122
|
+
maxDelay: 3600000,
|
|
123
|
+
jitter: true,
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
// Circuit breaker
|
|
127
|
+
circuitBreaker: {
|
|
128
|
+
failureThreshold: 5,
|
|
129
|
+
resetTimeout: 60000,
|
|
130
|
+
halfOpenMaxAttempts: 3,
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
// Batch configuration
|
|
134
|
+
batchConfig: {
|
|
135
|
+
batchSize: 50,
|
|
136
|
+
concurrency: 10,
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
// Lifecycle hooks
|
|
140
|
+
lifecycleHooks: {
|
|
141
|
+
onSend: async (subscription, payload) => {
|
|
142
|
+
console.log('Sending to:', subscription.id);
|
|
143
|
+
},
|
|
144
|
+
onSuccess: async (subscription, result) => {
|
|
145
|
+
console.log('Success:', subscription.id);
|
|
146
|
+
},
|
|
147
|
+
onFailure: async (subscription, error) => {
|
|
148
|
+
console.error('Failed:', subscription.id, error);
|
|
149
|
+
},
|
|
150
|
+
onRetry: async (subscription, attempt) => {
|
|
151
|
+
console.log('Retry attempt:', attempt, 'for:', subscription.id);
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Generating VAPID Keys
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
import { generateVapidKeys } from '@allmightypush/push';
|
|
161
|
+
|
|
162
|
+
const vapidKeys = generateVapidKeys();
|
|
163
|
+
console.log('Public Key:', vapidKeys.publicKey);
|
|
164
|
+
console.log('Private Key:', vapidKeys.privateKey);
|
|
165
|
+
|
|
166
|
+
// Save these keys securely - you'll need them for all notifications
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Storage Adapters
|
|
170
|
+
|
|
171
|
+
### SQLite (included)
|
|
172
|
+
```typescript
|
|
173
|
+
import { SQLiteStorageAdapter } from '@allmightypush/push';
|
|
174
|
+
|
|
175
|
+
const storage = new SQLiteStorageAdapter({
|
|
176
|
+
filename: './push.db',
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### PostgreSQL (separate package)
|
|
181
|
+
```bash
|
|
182
|
+
npm install @allmightypush/push-storage-postgres
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### MongoDB (separate package)
|
|
186
|
+
```bash
|
|
187
|
+
npm install @allmightypush/push-storage-mongo
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## API Reference
|
|
191
|
+
|
|
192
|
+
### PushCore
|
|
193
|
+
|
|
194
|
+
#### `configure(options: PushConfiguration): void`
|
|
195
|
+
Configure the push notification system.
|
|
196
|
+
|
|
197
|
+
#### `sendNotification(subscription: Subscription, payload: NotificationPayload, options?: SendOptions): Promise<SendResult>`
|
|
198
|
+
Send a notification to a single subscription.
|
|
199
|
+
|
|
200
|
+
#### `batchSend(subscriptions: Subscription[], payload: NotificationPayload, options?: SendOptions): Promise<BatchResult>`
|
|
201
|
+
Send notifications to multiple subscriptions efficiently.
|
|
202
|
+
|
|
203
|
+
#### `verifySubscription(subscription: Subscription): Promise<void>`
|
|
204
|
+
Verify that a subscription is valid.
|
|
205
|
+
|
|
206
|
+
#### `shutdown(timeout?: number): Promise<void>`
|
|
207
|
+
Gracefully shutdown the system.
|
|
208
|
+
|
|
209
|
+
### RetryWorker
|
|
210
|
+
|
|
211
|
+
#### `start(): Promise<void>`
|
|
212
|
+
Start the worker polling loop.
|
|
213
|
+
|
|
214
|
+
#### `stop(): Promise<void>`
|
|
215
|
+
Stop the worker gracefully.
|
|
216
|
+
|
|
217
|
+
#### `isRunning(): boolean`
|
|
218
|
+
Check if the worker is running.
|
|
219
|
+
|
|
220
|
+
## Error Handling
|
|
221
|
+
|
|
222
|
+
The library provides typed errors for different scenarios:
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
import {
|
|
226
|
+
ConfigurationError,
|
|
227
|
+
ValidationError,
|
|
228
|
+
ProviderError,
|
|
229
|
+
StorageError,
|
|
230
|
+
CircuitBreakerOpenError,
|
|
231
|
+
RateLimitError
|
|
232
|
+
} from '@allmightypush/push';
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
await pushCore.sendNotification(subscription, payload);
|
|
236
|
+
} catch (error) {
|
|
237
|
+
if (error instanceof ValidationError) {
|
|
238
|
+
console.error('Invalid subscription:', error.message);
|
|
239
|
+
} else if (error instanceof CircuitBreakerOpenError) {
|
|
240
|
+
console.error('Circuit breaker is open, try again later');
|
|
241
|
+
} else if (error instanceof ProviderError) {
|
|
242
|
+
console.error('Provider error:', error.statusCode);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Testing
|
|
248
|
+
|
|
249
|
+
The library includes 230+ tests with ~90% coverage:
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
npm test
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## License
|
|
256
|
+
|
|
257
|
+
MIT
|
|
258
|
+
|
|
259
|
+
## Contributing
|
|
260
|
+
|
|
261
|
+
Contributions welcome! Please read our contributing guidelines first.
|
|
262
|
+
|
|
263
|
+
## Support
|
|
264
|
+
|
|
265
|
+
- 📖 [Documentation](https://github.com/samtes64/all-mighty-push)
|
|
266
|
+
- 🐛 [Issue Tracker](https://github.com/samtes64/all-mighty-push/issues)
|
|
267
|
+
- 💬 [Discussions](https://github.com/samtes64/all-mighty-push/discussions)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.version = void 0;
|
|
18
|
+
__exportStar(require("@allmightypush/push-core"), exports);
|
|
19
|
+
__exportStar(require("@allmightypush/push-webpush"), exports);
|
|
20
|
+
__exportStar(require("@allmightypush/push-storage-sqlite"), exports);
|
|
21
|
+
exports.version = '1.0.0';
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAMA,2DAAyC;AAGzC,8DAA4C;AAG5C,qEAAmD;AAGtC,QAAA,OAAO,GAAG,OAAO,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAMA,cAAc,0BAA0B,CAAC;AAGzC,cAAc,6BAA6B,CAAC;AAG5C,cAAc,oCAAoC,CAAC;AAGnD,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAMA,cAAc,0BAA0B,CAAC;AAGzC,cAAc,6BAA6B,CAAC;AAG5C,cAAc,oCAAoC,CAAC;AAGnD,eAAO,MAAM,OAAO,UAAU,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@allmightypush/push",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Modular TypeScript-first push notification library for Node.js",
|
|
5
|
+
"main": "dist/cjs/index.js",
|
|
6
|
+
"module": "dist/esm/index.js",
|
|
7
|
+
"types": "dist/types/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"require": "./dist/cjs/index.js",
|
|
11
|
+
"import": "./dist/esm/index.js",
|
|
12
|
+
"types": "./dist/types/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "npm run build:cjs && npm run build:esm && npm run build:types",
|
|
20
|
+
"build:cjs": "tsc -p tsconfig.cjs.json",
|
|
21
|
+
"build:esm": "tsc -p tsconfig.esm.json",
|
|
22
|
+
"build:types": "tsc -p tsconfig.types.json",
|
|
23
|
+
"test": "jest --passWithNoTests",
|
|
24
|
+
"test:watch": "jest --watch",
|
|
25
|
+
"test:coverage": "jest --coverage --passWithNoTests",
|
|
26
|
+
"clean": "rm -rf dist"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"push",
|
|
30
|
+
"notification",
|
|
31
|
+
"webpush",
|
|
32
|
+
"vapid",
|
|
33
|
+
"typescript",
|
|
34
|
+
"nodejs"
|
|
35
|
+
],
|
|
36
|
+
"author": "Samtes64",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "https://github.com/Samtes64/all-mighty-push.git",
|
|
41
|
+
"directory": "packages/push"
|
|
42
|
+
},
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/Samtes64/all-mighty-push/issues"
|
|
45
|
+
},
|
|
46
|
+
"homepage": "https://github.com/Samtes64/all-mighty-push/tree/main/packages/push#readme",
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@allmightypush/push-core": "^1.0.0",
|
|
49
|
+
"@allmightypush/push-webpush": "^1.0.0",
|
|
50
|
+
"@allmightypush/push-storage-sqlite": "^1.0.0"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=16.0.0"
|
|
54
|
+
}
|
|
55
|
+
}
|