@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 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,5 @@
1
+ export * from '@allmightypush/push-core';
2
+ export * from '@allmightypush/push-webpush';
3
+ export * from '@allmightypush/push-storage-sqlite';
4
+ export const version = '1.0.0';
5
+ //# sourceMappingURL=index.js.map
@@ -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,5 @@
1
+ export * from '@allmightypush/push-core';
2
+ export * from '@allmightypush/push-webpush';
3
+ export * from '@allmightypush/push-storage-sqlite';
4
+ export declare const version = "1.0.0";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -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
+ }