@markwharton/pwa-push 2.0.0 → 3.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.
@@ -50,8 +50,8 @@ var PwaPush = (() => {
50
50
  function okVoid2() {
51
51
  return { ok: true };
52
52
  }
53
- function err2(error, statusCode) {
54
- return statusCode !== void 0 ? { ok: false, error, statusCode } : { ok: false, error };
53
+ function err2(error, status) {
54
+ return status !== void 0 ? { ok: false, error, status } : { ok: false, error };
55
55
  }
56
56
  function hasUsername(payload) {
57
57
  return "username" in payload && typeof payload.username === "string";
package/dist/server.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Requires: web-push package
5
5
  */
6
- import { Result, PushSubscription, NotificationPayload } from './shared';
6
+ import { Result, PushSubscription, NotificationPayload, BroadcastResult } from './shared';
7
7
  /**
8
8
  * Initializes VAPID configuration for Web Push. Call once at application startup.
9
9
  * @param config - VAPID configuration
@@ -77,14 +77,32 @@ export declare function sendPushToAll(subscriptions: PushSubscription[], payload
77
77
  * }
78
78
  */
79
79
  export declare function sendPushWithDetails(subscription: PushSubscription, payload: NotificationPayload): Promise<Result<void>>;
80
+ /**
81
+ * Broadcasts a push notification to multiple subscriptions in parallel.
82
+ * Returns structured results with counts and invalid endpoint tracking.
83
+ * Generic `<TSub>` lets the payload callback receive app-extended subscription types.
84
+ * @typeParam TSub - Push subscription type (extends PushSubscription)
85
+ * @param subscriptions - Array of push subscriptions
86
+ * @param payload - Static payload or per-subscription callback
87
+ * @returns BroadcastResult with sent/failed counts and invalid endpoints
88
+ * @example
89
+ * const result = await broadcastPush(subscriptions, { title: 'Alert', body: 'Update' });
90
+ * await cleanupInvalid(result.invalidEndpoints);
91
+ *
92
+ * // Per-subscription payload:
93
+ * const result = await broadcastPush(subscriptions, (sub) => ({
94
+ * title: 'Alert', body: 'Update', basePath: sub.basePath
95
+ * }));
96
+ */
97
+ export declare function broadcastPush<TSub extends PushSubscription>(subscriptions: TSub[], payload: NotificationPayload | ((subscription: TSub) => NotificationPayload)): Promise<BroadcastResult>;
80
98
  /**
81
99
  * Checks if a status code indicates an expired subscription (410 Gone).
82
100
  * Use this to clean up stale subscriptions from your database.
83
- * @param statusCode - The HTTP status code from a failed push attempt
101
+ * @param status - The HTTP status code from a failed push attempt
84
102
  * @returns True if the subscription should be deleted
85
103
  * @example
86
- * if (!result.ok && isSubscriptionExpired(result.statusCode)) {
104
+ * if (!result.ok && isSubscriptionExpired(result.status)) {
87
105
  * await db.deleteSubscription(subscription.endpoint);
88
106
  * }
89
107
  */
90
- export declare function isSubscriptionExpired(statusCode: number | undefined): boolean;
108
+ export declare function isSubscriptionExpired(status: number | undefined): boolean;
package/dist/server.js CHANGED
@@ -14,6 +14,7 @@ exports.getVapidPublicKey = getVapidPublicKey;
14
14
  exports.sendPushNotification = sendPushNotification;
15
15
  exports.sendPushToAll = sendPushToAll;
16
16
  exports.sendPushWithDetails = sendPushWithDetails;
17
+ exports.broadcastPush = broadcastPush;
17
18
  exports.isSubscriptionExpired = isSubscriptionExpired;
18
19
  const web_push_1 = __importDefault(require("web-push"));
19
20
  const shared_1 = require("./shared");
@@ -130,16 +131,53 @@ async function sendPushWithDetails(subscription, payload) {
130
131
  return (0, shared_1.err)(webPushError.message || 'Unknown error', webPushError.statusCode);
131
132
  }
132
133
  }
134
+ /**
135
+ * Broadcasts a push notification to multiple subscriptions in parallel.
136
+ * Returns structured results with counts and invalid endpoint tracking.
137
+ * Generic `<TSub>` lets the payload callback receive app-extended subscription types.
138
+ * @typeParam TSub - Push subscription type (extends PushSubscription)
139
+ * @param subscriptions - Array of push subscriptions
140
+ * @param payload - Static payload or per-subscription callback
141
+ * @returns BroadcastResult with sent/failed counts and invalid endpoints
142
+ * @example
143
+ * const result = await broadcastPush(subscriptions, { title: 'Alert', body: 'Update' });
144
+ * await cleanupInvalid(result.invalidEndpoints);
145
+ *
146
+ * // Per-subscription payload:
147
+ * const result = await broadcastPush(subscriptions, (sub) => ({
148
+ * title: 'Alert', body: 'Update', basePath: sub.basePath
149
+ * }));
150
+ */
151
+ async function broadcastPush(subscriptions, payload) {
152
+ let sent = 0;
153
+ let failed = 0;
154
+ const invalidEndpoints = [];
155
+ await Promise.all(subscriptions.map(async (subscription) => {
156
+ const actualPayload = typeof payload === 'function'
157
+ ? payload(subscription) : payload;
158
+ const result = await sendPushWithDetails(subscription, actualPayload);
159
+ if (result.ok) {
160
+ sent++;
161
+ }
162
+ else {
163
+ failed++;
164
+ if (isSubscriptionExpired(result.status)) {
165
+ invalidEndpoints.push(subscription.endpoint);
166
+ }
167
+ }
168
+ }));
169
+ return { sent, failed, invalidEndpoints };
170
+ }
133
171
  /**
134
172
  * Checks if a status code indicates an expired subscription (410 Gone).
135
173
  * Use this to clean up stale subscriptions from your database.
136
- * @param statusCode - The HTTP status code from a failed push attempt
174
+ * @param status - The HTTP status code from a failed push attempt
137
175
  * @returns True if the subscription should be deleted
138
176
  * @example
139
- * if (!result.ok && isSubscriptionExpired(result.statusCode)) {
177
+ * if (!result.ok && isSubscriptionExpired(result.status)) {
140
178
  * await db.deleteSubscription(subscription.endpoint);
141
179
  * }
142
180
  */
143
- function isSubscriptionExpired(statusCode) {
144
- return statusCode === 410;
181
+ function isSubscriptionExpired(status) {
182
+ return status === 410;
145
183
  }
package/dist/shared.d.ts CHANGED
@@ -57,3 +57,11 @@ export interface SubscriptionData {
57
57
  * Browser notification permission state.
58
58
  */
59
59
  export type PushPermissionState = 'granted' | 'denied' | 'default';
60
+ /**
61
+ * Result of broadcasting push notifications to multiple subscriptions.
62
+ */
63
+ export interface BroadcastResult {
64
+ sent: number;
65
+ failed: number;
66
+ invalidEndpoints: string[];
67
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markwharton/pwa-push",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "description": "Web push notifications for Azure PWA projects",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -30,11 +30,11 @@
30
30
  "clean": "rm -rf dist"
31
31
  },
32
32
  "peerDependencies": {
33
- "@markwharton/pwa-core": "^2.0.0",
33
+ "@markwharton/pwa-core": "^2.0.0 || ^3.0.0 || ^4.0.0",
34
34
  "web-push": "^3.6.0"
35
35
  },
36
36
  "devDependencies": {
37
- "@markwharton/pwa-core": "^2.0.0",
37
+ "@markwharton/pwa-core": "^4.0.0",
38
38
  "@types/node": "^20.10.0",
39
39
  "@types/web-push": "^3.6.4",
40
40
  "esbuild": "^0.27.2",