@markwharton/pwa-push 2.0.1 → 3.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.
@@ -31,9 +31,9 @@ var PwaPush = (() => {
31
31
  ));
32
32
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
33
33
 
34
- // node_modules/@markwharton/pwa-core/dist/shared.js
34
+ // ../core/dist/shared.js
35
35
  var require_shared = __commonJS({
36
- "node_modules/@markwharton/pwa-core/dist/shared.js"(exports) {
36
+ "../core/dist/shared.js"(exports) {
37
37
  "use strict";
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.HTTP_STATUS = void 0;
@@ -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
@@ -44,47 +44,49 @@ export declare function initPushFromEnv(): void;
44
44
  export declare function getVapidPublicKey(): string;
45
45
  /**
46
46
  * Sends a push notification to a single subscription.
47
- * @param subscription - The push subscription to send to
48
- * @param payload - The notification payload (title, body, etc.)
49
- * @returns Result with ok=true on success, or error message and statusCode on failure
50
- * @example
51
- * const result = await sendPushNotification(subscription, {
52
- * title: 'New Message',
53
- * body: 'You have a new message'
54
- * });
55
- */
56
- export declare function sendPushNotification(subscription: PushSubscription, payload: NotificationPayload): Promise<Result<void>>;
57
- /**
58
- * Sends a push notification to multiple subscriptions in parallel.
59
- * @param subscriptions - Array of push subscriptions
60
- * @param payload - The notification payload (title, body, etc.)
61
- * @returns Array of Results, one per subscription (in same order)
62
- * @example
63
- * const results = await sendPushToAll(subscriptions, { title: 'Alert', body: 'System update' });
64
- * const failed = results.filter(r => !r.ok);
65
- */
66
- export declare function sendPushToAll(subscriptions: PushSubscription[], payload: NotificationPayload): Promise<Result<void>[]>;
67
- /**
68
- * Sends a push notification with detailed error information.
69
47
  * Automatically injects basePath from subscription if not set in payload.
70
48
  * @param subscription - The push subscription to send to
71
49
  * @param payload - The notification payload
72
- * @returns Result with ok=true on success, or error with statusCode on failure
50
+ * @returns Result with ok=true on success, or error with status on failure
73
51
  * @example
74
- * const result = await sendPushWithDetails(subscription, { title: 'Alert' });
75
- * if (!result.ok && isSubscriptionExpired(result.statusCode)) {
52
+ * const result = await sendPush(subscription, { title: 'Alert', body: 'Update' });
53
+ * if (!result.ok && isSubscriptionExpired(result.status)) {
76
54
  * await deleteSubscription(subscription);
77
55
  * }
78
56
  */
79
- export declare function sendPushWithDetails(subscription: PushSubscription, payload: NotificationPayload): Promise<Result<void>>;
57
+ export declare function sendPush(subscription: PushSubscription, payload: NotificationPayload): Promise<Result<void>>;
58
+ /**
59
+ * Broadcasts a push notification to multiple subscriptions in parallel.
60
+ * Returns structured results with counts and invalid endpoint tracking.
61
+ * Generic `<TSub>` lets the payload callback receive app-extended subscription types.
62
+ * @typeParam TSub - Push subscription type (extends PushSubscription)
63
+ * @param subscriptions - Array of push subscriptions
64
+ * @param payload - Static payload or per-subscription callback
65
+ * @returns BroadcastResult with sent/failed counts and invalid endpoints
66
+ * @example
67
+ * const result = await broadcastPush(subscriptions, { title: 'Alert', body: 'Update' });
68
+ * await cleanupInvalid(result.invalidEndpoints);
69
+ *
70
+ * // Per-subscription payload:
71
+ * const result = await broadcastPush(subscriptions, (sub) => ({
72
+ * title: 'Alert', body: 'Update', basePath: sub.basePath
73
+ * }));
74
+ */
75
+ export declare function broadcastPush<TSub extends PushSubscription>(subscriptions: TSub[], payload: NotificationPayload | ((subscription: TSub) => NotificationPayload)): Promise<BroadcastResult>;
80
76
  /**
81
77
  * Checks if a status code indicates an expired subscription (410 Gone).
82
78
  * Use this to clean up stale subscriptions from your database.
83
- * @param statusCode - The HTTP status code from a failed push attempt
79
+ * @param status - The HTTP status code from a failed push attempt
84
80
  * @returns True if the subscription should be deleted
85
81
  * @example
86
- * if (!result.ok && isSubscriptionExpired(result.statusCode)) {
82
+ * if (!result.ok && isSubscriptionExpired(result.status)) {
87
83
  * await db.deleteSubscription(subscription.endpoint);
88
84
  * }
89
85
  */
90
- export declare function isSubscriptionExpired(statusCode: number | undefined): boolean;
86
+ export declare function isSubscriptionExpired(status: number | undefined): boolean;
87
+ /** @deprecated Use `sendPush` instead */
88
+ export declare const sendPushNotification: typeof sendPush;
89
+ /** @deprecated Use `sendPush` instead */
90
+ export declare const sendPushWithDetails: typeof sendPush;
91
+ /** @deprecated Use `broadcastPush` instead */
92
+ export declare function sendPushToAll(subscriptions: PushSubscription[], payload: NotificationPayload): Promise<Result<void>[]>;
package/dist/server.js CHANGED
@@ -8,13 +8,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
8
8
  return (mod && mod.__esModule) ? mod : { "default": mod };
9
9
  };
10
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.sendPushWithDetails = exports.sendPushNotification = void 0;
11
12
  exports.initPush = initPush;
12
13
  exports.initPushFromEnv = initPushFromEnv;
13
14
  exports.getVapidPublicKey = getVapidPublicKey;
14
- exports.sendPushNotification = sendPushNotification;
15
- exports.sendPushToAll = sendPushToAll;
16
- exports.sendPushWithDetails = sendPushWithDetails;
15
+ exports.sendPush = sendPush;
16
+ exports.broadcastPush = broadcastPush;
17
17
  exports.isSubscriptionExpired = isSubscriptionExpired;
18
+ exports.sendPushToAll = sendPushToAll;
18
19
  const web_push_1 = __importDefault(require("web-push"));
19
20
  const shared_1 = require("./shared");
20
21
  let vapidConfig = null;
@@ -75,44 +76,17 @@ function getVapidPublicKey() {
75
76
  }
76
77
  /**
77
78
  * Sends a push notification to a single subscription.
78
- * @param subscription - The push subscription to send to
79
- * @param payload - The notification payload (title, body, etc.)
80
- * @returns Result with ok=true on success, or error message and statusCode on failure
81
- * @example
82
- * const result = await sendPushNotification(subscription, {
83
- * title: 'New Message',
84
- * body: 'You have a new message'
85
- * });
86
- */
87
- async function sendPushNotification(subscription, payload) {
88
- return sendPushWithDetails(subscription, payload);
89
- }
90
- /**
91
- * Sends a push notification to multiple subscriptions in parallel.
92
- * @param subscriptions - Array of push subscriptions
93
- * @param payload - The notification payload (title, body, etc.)
94
- * @returns Array of Results, one per subscription (in same order)
95
- * @example
96
- * const results = await sendPushToAll(subscriptions, { title: 'Alert', body: 'System update' });
97
- * const failed = results.filter(r => !r.ok);
98
- */
99
- async function sendPushToAll(subscriptions, payload) {
100
- const results = await Promise.all(subscriptions.map(sub => sendPushWithDetails(sub, payload)));
101
- return results;
102
- }
103
- /**
104
- * Sends a push notification with detailed error information.
105
79
  * Automatically injects basePath from subscription if not set in payload.
106
80
  * @param subscription - The push subscription to send to
107
81
  * @param payload - The notification payload
108
- * @returns Result with ok=true on success, or error with statusCode on failure
82
+ * @returns Result with ok=true on success, or error with status on failure
109
83
  * @example
110
- * const result = await sendPushWithDetails(subscription, { title: 'Alert' });
111
- * if (!result.ok && isSubscriptionExpired(result.statusCode)) {
84
+ * const result = await sendPush(subscription, { title: 'Alert', body: 'Update' });
85
+ * if (!result.ok && isSubscriptionExpired(result.status)) {
112
86
  * await deleteSubscription(subscription);
113
87
  * }
114
88
  */
115
- async function sendPushWithDetails(subscription, payload) {
89
+ async function sendPush(subscription, payload) {
116
90
  if (!vapidConfig) {
117
91
  return (0, shared_1.err)('Push not initialized');
118
92
  }
@@ -130,16 +104,65 @@ async function sendPushWithDetails(subscription, payload) {
130
104
  return (0, shared_1.err)(webPushError.message || 'Unknown error', webPushError.statusCode);
131
105
  }
132
106
  }
107
+ /**
108
+ * Broadcasts a push notification to multiple subscriptions in parallel.
109
+ * Returns structured results with counts and invalid endpoint tracking.
110
+ * Generic `<TSub>` lets the payload callback receive app-extended subscription types.
111
+ * @typeParam TSub - Push subscription type (extends PushSubscription)
112
+ * @param subscriptions - Array of push subscriptions
113
+ * @param payload - Static payload or per-subscription callback
114
+ * @returns BroadcastResult with sent/failed counts and invalid endpoints
115
+ * @example
116
+ * const result = await broadcastPush(subscriptions, { title: 'Alert', body: 'Update' });
117
+ * await cleanupInvalid(result.invalidEndpoints);
118
+ *
119
+ * // Per-subscription payload:
120
+ * const result = await broadcastPush(subscriptions, (sub) => ({
121
+ * title: 'Alert', body: 'Update', basePath: sub.basePath
122
+ * }));
123
+ */
124
+ async function broadcastPush(subscriptions, payload) {
125
+ let sent = 0;
126
+ let failed = 0;
127
+ const invalidEndpoints = [];
128
+ await Promise.all(subscriptions.map(async (subscription) => {
129
+ const actualPayload = typeof payload === 'function'
130
+ ? payload(subscription) : payload;
131
+ const result = await sendPush(subscription, actualPayload);
132
+ if (result.ok) {
133
+ sent++;
134
+ }
135
+ else {
136
+ failed++;
137
+ if (isSubscriptionExpired(result.status)) {
138
+ invalidEndpoints.push(subscription.endpoint);
139
+ }
140
+ }
141
+ }));
142
+ return { sent, failed, invalidEndpoints };
143
+ }
133
144
  /**
134
145
  * Checks if a status code indicates an expired subscription (410 Gone).
135
146
  * Use this to clean up stale subscriptions from your database.
136
- * @param statusCode - The HTTP status code from a failed push attempt
147
+ * @param status - The HTTP status code from a failed push attempt
137
148
  * @returns True if the subscription should be deleted
138
149
  * @example
139
- * if (!result.ok && isSubscriptionExpired(result.statusCode)) {
150
+ * if (!result.ok && isSubscriptionExpired(result.status)) {
140
151
  * await db.deleteSubscription(subscription.endpoint);
141
152
  * }
142
153
  */
143
- function isSubscriptionExpired(statusCode) {
144
- return statusCode === 410;
154
+ function isSubscriptionExpired(status) {
155
+ return status === 410;
156
+ }
157
+ // =============================================================================
158
+ // Deprecated aliases (remove in next major)
159
+ // =============================================================================
160
+ /** @deprecated Use `sendPush` instead */
161
+ exports.sendPushNotification = sendPush;
162
+ /** @deprecated Use `sendPush` instead */
163
+ exports.sendPushWithDetails = sendPush;
164
+ /** @deprecated Use `broadcastPush` instead */
165
+ async function sendPushToAll(subscriptions, payload) {
166
+ const results = await Promise.all(subscriptions.map(sub => sendPush(sub, payload)));
167
+ return results;
145
168
  }
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.1",
3
+ "version": "3.1.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 || ^3.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": "^3.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",