@serve.zone/dcrouter 17.7.1 → 17.8.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.
Files changed (77) hide show
  1. package/deno.json +1 -1
  2. package/dist_serve/bundle.js +410 -410
  3. package/dist_ts/00_commitinfo_data.js +1 -1
  4. package/dist_ts/classes.dcrouter.d.ts +2 -0
  5. package/dist_ts/classes.dcrouter.js +23 -1
  6. package/dist_ts/config/classes.gateway-client-manager.js +3 -1
  7. package/dist_ts/db/documents/classes.cached.email.d.ts +7 -0
  8. package/dist_ts/db/documents/classes.cached.email.js +52 -2
  9. package/dist_ts/db/documents/classes.webpush-admission.doc.d.ts +19 -0
  10. package/dist_ts/db/documents/classes.webpush-admission.doc.js +124 -0
  11. package/dist_ts/db/documents/classes.webpush-binding.doc.d.ts +65 -0
  12. package/dist_ts/db/documents/classes.webpush-binding.doc.js +205 -0
  13. package/dist_ts/db/documents/classes.webpush-spool.doc.d.ts +44 -0
  14. package/dist_ts/db/documents/classes.webpush-spool.doc.js +277 -0
  15. package/dist_ts/db/documents/index.d.ts +3 -0
  16. package/dist_ts/db/documents/index.js +5 -1
  17. package/dist_ts/email/classes.accepted-email-spool.d.ts +5 -0
  18. package/dist_ts/email/classes.accepted-email-spool.js +28 -3
  19. package/dist_ts/email/classes.workapp-mail-manager.d.ts +5 -1
  20. package/dist_ts/email/classes.workapp-mail-manager.js +87 -12
  21. package/dist_ts/index.d.ts +1 -0
  22. package/dist_ts/index.js +3 -1
  23. package/dist_ts/opsserver/classes.opsserver.d.ts +2 -0
  24. package/dist_ts/opsserver/classes.opsserver.js +5 -1
  25. package/dist_ts/opsserver/handlers/gatewayclient.handler.js +11 -5
  26. package/dist_ts/opsserver/handlers/index.d.ts +2 -0
  27. package/dist_ts/opsserver/handlers/index.js +3 -1
  28. package/dist_ts/opsserver/handlers/webpush-app.handler.d.ts +9 -0
  29. package/dist_ts/opsserver/handlers/webpush-app.handler.js +66 -0
  30. package/dist_ts/opsserver/handlers/webpush-control.handler.d.ts +14 -0
  31. package/dist_ts/opsserver/handlers/webpush-control.handler.js +163 -0
  32. package/dist_ts/plugins.d.ts +5 -2
  33. package/dist_ts/plugins.js +6 -3
  34. package/dist_ts/webpush/classes.webpush-crypto.d.ts +38 -0
  35. package/dist_ts/webpush/classes.webpush-crypto.js +231 -0
  36. package/dist_ts/webpush/classes.webpush-manager.d.ts +153 -0
  37. package/dist_ts/webpush/classes.webpush-manager.js +2374 -0
  38. package/dist_ts/webpush/classes.webpush-transport.d.ts +45 -0
  39. package/dist_ts/webpush/classes.webpush-transport.js +161 -0
  40. package/dist_ts/webpush/helpers.webpush-endpoint.d.ts +21 -0
  41. package/dist_ts/webpush/helpers.webpush-endpoint.js +111 -0
  42. package/dist_ts/webpush/index.d.ts +4 -0
  43. package/dist_ts/webpush/index.js +5 -0
  44. package/dist_ts/webpush/webpush-indexes.d.ts +11 -0
  45. package/dist_ts/webpush/webpush-indexes.js +123 -0
  46. package/dist_ts_interfaces/data/route-management.d.ts +2 -0
  47. package/dist_ts_interfaces/data/route-management.js +1 -1
  48. package/dist_ts_migrations/index.js +221 -11
  49. package/dist_ts_web/00_commitinfo_data.js +1 -1
  50. package/package.json +12 -8
  51. package/readme.md +27 -0
  52. package/third-party-notices.md +37 -0
  53. package/ts/00_commitinfo_data.ts +1 -1
  54. package/ts/classes.dcrouter.ts +29 -0
  55. package/ts/config/classes.gateway-client-manager.ts +2 -0
  56. package/ts/db/documents/classes.cached.email.ts +47 -0
  57. package/ts/db/documents/classes.webpush-admission.doc.ts +48 -0
  58. package/ts/db/documents/classes.webpush-binding.doc.ts +147 -0
  59. package/ts/db/documents/classes.webpush-spool.doc.ts +136 -0
  60. package/ts/db/documents/index.ts +5 -0
  61. package/ts/email/classes.accepted-email-spool.ts +41 -2
  62. package/ts/email/classes.workapp-mail-manager.ts +97 -10
  63. package/ts/index.ts +3 -0
  64. package/ts/opsserver/classes.opsserver.ts +4 -0
  65. package/ts/opsserver/handlers/gatewayclient.handler.ts +10 -3
  66. package/ts/opsserver/handlers/index.ts +2 -0
  67. package/ts/opsserver/handlers/webpush-app.handler.ts +105 -0
  68. package/ts/opsserver/handlers/webpush-control.handler.ts +257 -0
  69. package/ts/plugins.ts +6 -0
  70. package/ts/webpush/classes.webpush-crypto.ts +306 -0
  71. package/ts/webpush/classes.webpush-manager.ts +3173 -0
  72. package/ts/webpush/classes.webpush-transport.ts +241 -0
  73. package/ts/webpush/helpers.webpush-endpoint.ts +150 -0
  74. package/ts/webpush/index.ts +4 -0
  75. package/ts/webpush/webpush-indexes.ts +141 -0
  76. package/ts_web/00_commitinfo_data.ts +1 -1
  77. package/readme.plan.md +0 -22
@@ -0,0 +1,2374 @@
1
+ import * as plugins from '../plugins.js';
2
+ import { logger } from '../logger.js';
3
+ import { DcRouterDb, WebPushAdmissionDoc, WebPushBindingDoc, WebPushSpoolDoc, } from '../db/index.js';
4
+ import { WebPushCrypto, canonicalJson, parseWebPushKeyRing, } from './classes.webpush-crypto.js';
5
+ import { WebPushHttpTransport, WebPushTransportError, } from './classes.webpush-transport.js';
6
+ import { WebPushEndpointPolicyError } from './helpers.webpush-endpoint.js';
7
+ import { getWebPushIndexSpecifications, } from './webpush-indexes.js';
8
+ const MAX_PAYLOAD_BYTES = 3500;
9
+ const MAX_TTL_SECONDS = 86_400;
10
+ const DEFAULT_TTL_SECONDS = 86_400;
11
+ const MAX_ID_LENGTH = 256;
12
+ const MAX_IDEMPOTENCY_KEY_LENGTH = 256;
13
+ const MAX_COLLAPSE_KEY_LENGTH = 256;
14
+ const MAX_ROUTE_LENGTH = 2048;
15
+ const MAX_EVENT_ID_LENGTH = 256;
16
+ const MAX_NONTERMINAL_ITEMS_PER_BINDING = 10_000;
17
+ const DEFAULT_ADMISSION_POLICY = {
18
+ shortWindowMs: 60_000,
19
+ shortLimit: 120,
20
+ longWindowMs: 60 * 60_000,
21
+ longLimit: 5_000,
22
+ };
23
+ const MAX_ADMISSION_CAS_ATTEMPTS = 512;
24
+ const DELIVERY_BATCH_SIZE = 25;
25
+ const DELIVERY_LEASE_MS = 60_000;
26
+ const DELIVERY_WORKER_INTERVAL_MS = 1_000;
27
+ const DELIVERY_MAX_ATTEMPTS = 8;
28
+ const TERMINAL_RETENTION_MS = 7 * 24 * 60 * 60 * 1000;
29
+ const CREDENTIAL_OVERLAP_MS = 15 * 60 * 1000;
30
+ const VAPID_RETIREMENT_MS = 90 * 24 * 60 * 60 * 1000;
31
+ const VAPID_KEY_RING_LIMIT = 4;
32
+ const LIFECYCLE_DRAIN_TIMEOUT_MS = DELIVERY_LEASE_MS + 5_000;
33
+ const LIFECYCLE_DRAIN_POLL_MS = 250;
34
+ const MAINTENANCE_BATCH_SIZE = 100;
35
+ const OPAQUE_ID_PATTERN = /^[A-Za-z0-9._:-]+$/;
36
+ const BASE64URL_PATTERN = /^[A-Za-z0-9_-]+$/;
37
+ const TERMINAL_STATES = [
38
+ 'pushServiceAccepted',
39
+ 'invalidSubscription',
40
+ 'failed',
41
+ 'expired',
42
+ 'cancelled',
43
+ ];
44
+ const NONTERMINAL_STATES = [
45
+ 'accepted',
46
+ 'queued',
47
+ 'sending',
48
+ 'deferred',
49
+ ];
50
+ function requireNonEmptyString(valueArg, labelArg, maxLengthArg = MAX_ID_LENGTH) {
51
+ if (typeof valueArg !== 'string'
52
+ || valueArg.trim().length === 0
53
+ || valueArg.length > maxLengthArg) {
54
+ throw new plugins.typedrequest.TypedResponseError(`${labelArg} is missing or malformed`);
55
+ }
56
+ return valueArg.trim();
57
+ }
58
+ function requireOpaqueId(valueArg, labelArg) {
59
+ const value = requireNonEmptyString(valueArg, labelArg);
60
+ if (!OPAQUE_ID_PATTERN.test(value) || value.includes('://')) {
61
+ throw new plugins.typedrequest.TypedResponseError(`${labelArg} is malformed`);
62
+ }
63
+ return value;
64
+ }
65
+ function requireBase64Url(valueArg, labelArg, expectedLengthArg) {
66
+ const value = requireNonEmptyString(valueArg, labelArg, 512);
67
+ if (!BASE64URL_PATTERN.test(value)) {
68
+ throw new plugins.typedrequest.TypedResponseError(`${labelArg} is malformed`);
69
+ }
70
+ const decoded = Buffer.from(value, 'base64url');
71
+ if (decoded.length !== expectedLengthArg
72
+ || decoded.toString('base64url') !== value) {
73
+ throw new plugins.typedrequest.TypedResponseError(`${labelArg} is malformed`);
74
+ }
75
+ return value;
76
+ }
77
+ function normalizeOwner(ownerArg) {
78
+ if (!['onebox', 'cloudly', 'custom'].includes(ownerArg?.gatewayClientType)) {
79
+ throw new plugins.typedrequest.TypedResponseError('Web Push owner gatewayClientType is malformed');
80
+ }
81
+ return {
82
+ gatewayClientType: ownerArg.gatewayClientType,
83
+ gatewayClientId: requireOpaqueId(ownerArg.gatewayClientId, 'Web Push owner gatewayClientId'),
84
+ appInstanceId: requireOpaqueId(ownerArg.appInstanceId, 'Web Push owner appInstanceId'),
85
+ };
86
+ }
87
+ function normalizeSubscription(subscriptionArg) {
88
+ if (!subscriptionArg || typeof subscriptionArg !== 'object') {
89
+ throw new plugins.typedrequest.TypedResponseError('Web Push subscription is malformed');
90
+ }
91
+ const endpoint = requireNonEmptyString(subscriptionArg.endpoint, 'Web Push subscription endpoint', 4096);
92
+ const expirationTime = subscriptionArg.expirationTime;
93
+ if (expirationTime !== null
94
+ && (!Number.isSafeInteger(expirationTime) || expirationTime < 0)) {
95
+ throw new plugins.typedrequest.TypedResponseError('Web Push subscription expirationTime is malformed');
96
+ }
97
+ return {
98
+ endpoint,
99
+ expirationTime,
100
+ keys: {
101
+ p256dh: requireBase64Url(subscriptionArg.keys?.p256dh, 'Web Push subscription p256dh key', 65),
102
+ auth: requireBase64Url(subscriptionArg.keys?.auth, 'Web Push subscription auth key', 16),
103
+ },
104
+ };
105
+ }
106
+ function normalizePayload(payloadArg) {
107
+ if (!payloadArg || typeof payloadArg !== 'object' || Array.isArray(payloadArg)) {
108
+ throw new plugins.typedrequest.TypedResponseError('Web Push payload is malformed');
109
+ }
110
+ const keys = Object.keys(payloadArg).sort();
111
+ if (keys.join(',') !== 'event,eventId,route,schemaVersion') {
112
+ throw new plugins.typedrequest.TypedResponseError('Web Push payload contains unsupported fields');
113
+ }
114
+ if (payloadArg.schemaVersion !== 1 || payloadArg.event !== 'notificationAvailable') {
115
+ throw new plugins.typedrequest.TypedResponseError('Web Push payload schema is unsupported');
116
+ }
117
+ const eventId = requireOpaqueId(payloadArg.eventId, 'Web Push payload eventId');
118
+ if (eventId.length > MAX_EVENT_ID_LENGTH) {
119
+ throw new plugins.typedrequest.TypedResponseError('Web Push payload eventId is too long');
120
+ }
121
+ const route = requireNonEmptyString(payloadArg.route, 'Web Push payload route', MAX_ROUTE_LENGTH);
122
+ if (!route.startsWith('/') || route.startsWith('//') || route.includes('\\')) {
123
+ throw new plugins.typedrequest.TypedResponseError('Web Push payload route must be same-origin');
124
+ }
125
+ let parsedRoute;
126
+ try {
127
+ parsedRoute = new URL(route, 'https://webpush.invalid');
128
+ }
129
+ catch {
130
+ throw new plugins.typedrequest.TypedResponseError('Web Push payload route is malformed');
131
+ }
132
+ if (parsedRoute.origin !== 'https://webpush.invalid') {
133
+ throw new plugins.typedrequest.TypedResponseError('Web Push payload route must be same-origin');
134
+ }
135
+ const normalized = {
136
+ schemaVersion: 1,
137
+ event: 'notificationAvailable',
138
+ eventId,
139
+ route,
140
+ };
141
+ if (Buffer.byteLength(canonicalJson(normalized), 'utf8') > MAX_PAYLOAD_BYTES) {
142
+ throw new plugins.typedrequest.TypedResponseError('Web Push payload exceeds the maximum size');
143
+ }
144
+ return normalized;
145
+ }
146
+ function normalizeTtl(ttlArg) {
147
+ const ttl = ttlArg ?? DEFAULT_TTL_SECONDS;
148
+ if (!Number.isSafeInteger(ttl) || ttl <= 0 || ttl > MAX_TTL_SECONDS) {
149
+ throw new plugins.typedrequest.TypedResponseError('Web Push ttlSeconds is malformed');
150
+ }
151
+ return ttl;
152
+ }
153
+ function normalizeUrgency(urgencyArg) {
154
+ const urgency = urgencyArg ?? 'normal';
155
+ if (!['very-low', 'low', 'normal', 'high'].includes(urgency)) {
156
+ throw new plugins.typedrequest.TypedResponseError('Web Push urgency is malformed');
157
+ }
158
+ return urgency;
159
+ }
160
+ function normalizeFeatureFlag(valueArg) {
161
+ if (valueArg === undefined || !valueArg.trim())
162
+ return false;
163
+ const value = valueArg.trim().toLowerCase();
164
+ if (['false', '0', 'off', 'no'].includes(value))
165
+ return false;
166
+ if (['true', '1', 'on', 'yes'].includes(value))
167
+ return true;
168
+ throw new Error('DCROUTER_WEB_PUSH_ENABLED must be an explicit boolean');
169
+ }
170
+ function normalizeAdmissionPolicy(policyArg) {
171
+ const policy = {
172
+ ...DEFAULT_ADMISSION_POLICY,
173
+ ...(policyArg || {}),
174
+ };
175
+ for (const [name, value] of Object.entries(policy)) {
176
+ if (!Number.isSafeInteger(value) || value <= 0) {
177
+ throw new Error(`Web Push admission policy ${name} must be a positive integer`);
178
+ }
179
+ }
180
+ if (policy.shortWindowMs > policy.longWindowMs
181
+ || policy.shortLimit > policy.longLimit) {
182
+ throw new Error('Web Push admission policy short window must fit inside the long window');
183
+ }
184
+ return policy;
185
+ }
186
+ function requireLifecycleGeneration(valueArg) {
187
+ if (!Number.isSafeInteger(valueArg) || valueArg < 1) {
188
+ throw new Error('Web Push binding lifecycle generation is malformed');
189
+ }
190
+ return valueArg;
191
+ }
192
+ function normalizeControllerMutation(controllerArg, expectedIntentArg) {
193
+ if (!controllerArg || typeof controllerArg !== 'object') {
194
+ throw new plugins.typedrequest.TypedResponseError('Web Push controller mutation is missing or malformed');
195
+ }
196
+ if (!Number.isSafeInteger(controllerArg.generation)
197
+ || controllerArg.generation < 1) {
198
+ throw new plugins.typedrequest.TypedResponseError('Web Push controller generation is malformed');
199
+ }
200
+ if (controllerArg.intent !== expectedIntentArg) {
201
+ throw new plugins.typedrequest.TypedResponseError('Web Push controller intent does not match the requested mutation');
202
+ }
203
+ return {
204
+ id: requireOpaqueId(controllerArg.id, 'Web Push controller id'),
205
+ epoch: requireOpaqueId(controllerArg.epoch, 'Web Push controller epoch'),
206
+ generation: controllerArg.generation,
207
+ operationId: requireOpaqueId(controllerArg.operationId, 'Web Push controller operation id'),
208
+ intent: expectedIntentArg,
209
+ };
210
+ }
211
+ function normalizeDeleteControllerMutation(controllerArg) {
212
+ if (!controllerArg || !['disabled', 'deleted'].includes(controllerArg.intent)) {
213
+ throw new plugins.typedrequest.TypedResponseError('Web Push delete controller intent must be disabled or deleted');
214
+ }
215
+ return normalizeControllerMutation(controllerArg, controllerArg.intent);
216
+ }
217
+ function controllerRequestDigest(valueArg) {
218
+ return plugins.crypto
219
+ .createHash('sha256')
220
+ .update('dcrouter:webpush:controller:v1\0', 'utf8')
221
+ .update(canonicalJson(valueArg), 'utf8')
222
+ .digest('base64url');
223
+ }
224
+ function assertStoredControllerFence(fenceArg) {
225
+ const hasValidOpaqueId = (valueArg) => (typeof valueArg === 'string'
226
+ && valueArg.length > 0
227
+ && valueArg.length <= MAX_ID_LENGTH
228
+ && valueArg === valueArg.trim()
229
+ && OPAQUE_ID_PATTERN.test(valueArg)
230
+ && !valueArg.includes('://'));
231
+ const digest = typeof fenceArg?.requestDigest === 'string'
232
+ ? fenceArg.requestDigest
233
+ : '';
234
+ const decodedDigest = BASE64URL_PATTERN.test(digest)
235
+ ? Buffer.from(digest, 'base64url')
236
+ : Buffer.alloc(0);
237
+ if (!fenceArg
238
+ || typeof fenceArg !== 'object'
239
+ || !hasValidOpaqueId(fenceArg.id)
240
+ || !hasValidOpaqueId(fenceArg.epoch)
241
+ || !Number.isSafeInteger(fenceArg.generation)
242
+ || fenceArg.generation < 1
243
+ || !hasValidOpaqueId(fenceArg.operationId)
244
+ || !['enabled', 'disabled', 'deleted'].includes(fenceArg.intent)
245
+ || decodedDigest.length !== 32
246
+ || decodedDigest.toString('base64url') !== digest
247
+ || !Number.isSafeInteger(fenceArg.appliedAt)
248
+ || fenceArg.appliedAt < 0) {
249
+ throw new Error('Stored Web Push controller fence is malformed');
250
+ }
251
+ }
252
+ function controllerFenceDecision(fenceArg, controllerArg, requestDigestArg) {
253
+ if (fenceArg === undefined)
254
+ return 'apply';
255
+ assertStoredControllerFence(fenceArg);
256
+ if (fenceArg.id !== controllerArg.id || fenceArg.epoch !== controllerArg.epoch) {
257
+ throw new plugins.typedrequest.TypedResponseError('Web Push binding is owned by a different controller epoch');
258
+ }
259
+ if (controllerArg.generation < fenceArg.generation) {
260
+ throw new plugins.typedrequest.TypedResponseError('Web Push controller generation is stale');
261
+ }
262
+ if (controllerArg.generation > fenceArg.generation)
263
+ return 'apply';
264
+ if (fenceArg.operationId !== controllerArg.operationId
265
+ || fenceArg.intent !== controllerArg.intent
266
+ || fenceArg.requestDigest !== requestDigestArg) {
267
+ throw new plugins.typedrequest.TypedResponseError('Web Push controller generation conflicts with an applied mutation');
268
+ }
269
+ return 'replay';
270
+ }
271
+ function createControllerFence(controllerArg, requestDigestArg, nowArg) {
272
+ return {
273
+ ...controllerArg,
274
+ requestDigest: requestDigestArg,
275
+ appliedAt: nowArg,
276
+ };
277
+ }
278
+ function validateVapidSubject(subjectArg) {
279
+ const subject = requireNonEmptyString(subjectArg, 'Web Push VAPID subject', 2048);
280
+ let parsed;
281
+ try {
282
+ parsed = new URL(subject);
283
+ }
284
+ catch {
285
+ throw new Error('DCROUTER_WEB_PUSH_VAPID_SUBJECT must be an https: or mailto: URI');
286
+ }
287
+ if (!['https:', 'mailto:'].includes(parsed.protocol)) {
288
+ throw new Error('DCROUTER_WEB_PUSH_VAPID_SUBJECT must be an https: or mailto: URI');
289
+ }
290
+ if (parsed.protocol === 'https:' && parsed.hostname.toLowerCase() === 'localhost') {
291
+ throw new Error('DCROUTER_WEB_PUSH_VAPID_SUBJECT must not use localhost');
292
+ }
293
+ return subject;
294
+ }
295
+ function constantTimeDigestEqual(leftArg, rightArg) {
296
+ if (!BASE64URL_PATTERN.test(leftArg) || !BASE64URL_PATTERN.test(rightArg))
297
+ return false;
298
+ const left = Buffer.from(leftArg, 'base64url');
299
+ const right = Buffer.from(rightArg, 'base64url');
300
+ return left.length === right.length && plugins.crypto.timingSafeEqual(left, right);
301
+ }
302
+ function isDuplicateKeyError(errorArg) {
303
+ return errorArg?.code === 11000;
304
+ }
305
+ function asBindingDoc(rawArg) {
306
+ return rawArg;
307
+ }
308
+ function asAdmissionDoc(rawArg) {
309
+ return rawArg;
310
+ }
311
+ function asSpoolDoc(rawArg) {
312
+ return rawArg;
313
+ }
314
+ function toCredentialPublic(credentialArg) {
315
+ return {
316
+ id: credentialArg.id,
317
+ status: credentialArg.status,
318
+ createdAt: credentialArg.createdAt,
319
+ updatedAt: credentialArg.updatedAt,
320
+ ...(credentialArg.lastRotatedAt !== null
321
+ ? { lastRotatedAt: credentialArg.lastRotatedAt }
322
+ : {}),
323
+ };
324
+ }
325
+ function toVapidKeyPublic(keyArg) {
326
+ return {
327
+ id: keyArg.id,
328
+ publicKey: keyArg.publicKey,
329
+ status: keyArg.status,
330
+ createdAt: keyArg.createdAt,
331
+ ...(keyArg.activatedAt !== null ? { activatedAt: keyArg.activatedAt } : {}),
332
+ ...(keyArg.retireAfter !== null ? { retireAfter: keyArg.retireAfter } : {}),
333
+ ...(keyArg.retiredAt !== null ? { retiredAt: keyArg.retiredAt } : {}),
334
+ };
335
+ }
336
+ export function toPublicWebPushBinding(bindingArg) {
337
+ return {
338
+ id: bindingArg.id,
339
+ owner: {
340
+ gatewayClientType: bindingArg.ownerGatewayClientType,
341
+ gatewayClientId: bindingArg.ownerGatewayClientId,
342
+ appInstanceId: bindingArg.ownerAppInstanceId,
343
+ },
344
+ enabled: bindingArg.enabled,
345
+ status: bindingArg.status,
346
+ credential: toCredentialPublic(bindingArg.credential),
347
+ vapidKeys: (bindingArg.vapidKeys || []).map((keyArg) => toVapidKeyPublic(keyArg)),
348
+ createdAt: bindingArg.createdAt,
349
+ updatedAt: bindingArg.updatedAt,
350
+ createdBy: bindingArg.createdBy,
351
+ };
352
+ }
353
+ export function toPublicWebPushDelivery(spoolArg) {
354
+ return {
355
+ spoolItemId: spoolArg.id,
356
+ state: spoolArg.state,
357
+ attempts: spoolArg.attempts,
358
+ acceptedAt: spoolArg.acceptedAt,
359
+ updatedAt: spoolArg.updatedAt,
360
+ ...(!TERMINAL_STATES.includes(spoolArg.state)
361
+ ? { nextAttemptAt: spoolArg.nextAttemptAt }
362
+ : {}),
363
+ ...(spoolArg.terminalAt !== undefined ? { terminalAt: spoolArg.terminalAt } : {}),
364
+ ...(spoolArg.pushServiceStatusCode !== null
365
+ ? { pushServiceStatusCode: spoolArg.pushServiceStatusCode }
366
+ : {}),
367
+ ...(spoolArg.errorCode ? { errorCode: spoolArg.errorCode } : {}),
368
+ };
369
+ }
370
+ export function buildWebPushTerminalUpdate(optionsArg) {
371
+ return {
372
+ $set: {
373
+ state: optionsArg.state,
374
+ updatedAt: optionsArg.now,
375
+ terminalAt: optionsArg.now,
376
+ purgeAt: new Date(optionsArg.now + TERMINAL_RETENTION_MS),
377
+ pushServiceStatusCode: optionsArg.pushServiceStatusCode ?? null,
378
+ errorCode: optionsArg.errorCode ?? null,
379
+ _updatedAt: new Date(optionsArg.now).toISOString(),
380
+ },
381
+ $unset: {
382
+ subscriptionEnvelope: '',
383
+ payloadEnvelope: '',
384
+ leaseToken: '',
385
+ leaseExpiresAt: '',
386
+ cancelRequestedAt: '',
387
+ cancelErrorCode: '',
388
+ },
389
+ };
390
+ }
391
+ function canonicalIndexValue(valueArg) {
392
+ if (valueArg === undefined)
393
+ return 'undefined';
394
+ return canonicalJson(valueArg);
395
+ }
396
+ function assertWebPushIndexMatches(collectionArg, actualArg, expectedArg) {
397
+ const malformed = () => {
398
+ throw new Error(`Web Push persistence index ${collectionArg}.${expectedArg.name} is missing or malformed`);
399
+ };
400
+ if (!actualArg) {
401
+ throw new Error(`Web Push persistence index ${collectionArg}.${expectedArg.name} is missing or malformed`);
402
+ }
403
+ if (actualArg.name !== expectedArg.name)
404
+ malformed();
405
+ if (JSON.stringify(actualArg.key) !== JSON.stringify(expectedArg.key))
406
+ malformed();
407
+ if (Boolean(actualArg.unique) !== Boolean(expectedArg.unique))
408
+ malformed();
409
+ if (actualArg.expireAfterSeconds !== expectedArg.expireAfterSeconds)
410
+ malformed();
411
+ if (canonicalIndexValue(actualArg.partialFilterExpression)
412
+ !== canonicalIndexValue(expectedArg.partialFilterExpression)) {
413
+ malformed();
414
+ }
415
+ if (actualArg.sparse === true
416
+ || actualArg.collation !== undefined
417
+ || actualArg.hidden === true) {
418
+ malformed();
419
+ }
420
+ }
421
+ function assertWebPushIndexes(collectionArg, actualIndexesArg) {
422
+ const byName = new Map(actualIndexesArg.map((indexArg) => [indexArg.name, indexArg]));
423
+ for (const expected of getWebPushIndexSpecifications(collectionArg)) {
424
+ assertWebPushIndexMatches(collectionArg, byName.get(expected.name), expected);
425
+ }
426
+ }
427
+ export class WebPushManager {
428
+ qenv;
429
+ transport;
430
+ startWorker;
431
+ now;
432
+ admissionPolicy;
433
+ enabled = false;
434
+ started = false;
435
+ ready = false;
436
+ crypto;
437
+ vapidSubject;
438
+ workerTimer;
439
+ activeWorkerCycle;
440
+ expiredCredentialOverlapCursor;
441
+ expiredCredentialRecoveryCursor;
442
+ retiredVapidCursor;
443
+ inactiveLifecycleCursor;
444
+ constructor(optionsArg = {}) {
445
+ this.qenv = optionsArg.qenv ?? new plugins.qenv.Qenv('./', '.nogit/', false);
446
+ this.transport = optionsArg.transport ?? new WebPushHttpTransport();
447
+ this.startWorker = optionsArg.startWorker !== false;
448
+ this.now = optionsArg.now ?? (() => Date.now());
449
+ this.admissionPolicy = normalizeAdmissionPolicy(optionsArg.admissionPolicy);
450
+ }
451
+ get isEnabled() {
452
+ return this.enabled;
453
+ }
454
+ get isReady() {
455
+ return this.ready;
456
+ }
457
+ async start() {
458
+ if (this.started)
459
+ return;
460
+ const enabledValue = await this.qenv.getEnvVarOnDemand('DCROUTER_WEB_PUSH_ENABLED');
461
+ this.enabled = normalizeFeatureFlag(enabledValue);
462
+ if (!this.enabled) {
463
+ this.started = true;
464
+ this.ready = false;
465
+ logger.log('info', 'Web Push provider is disabled');
466
+ return;
467
+ }
468
+ if (!DcRouterDb.getInstance().isReady()) {
469
+ throw new Error('Web Push persistence is unavailable');
470
+ }
471
+ const encryptionKeyRingRaw = await this.qenv.getEnvVarOnDemand('DCROUTER_WEB_PUSH_MASTER_KEY_RING');
472
+ const hmacKeyRingRaw = await this.qenv.getEnvVarOnDemand('DCROUTER_WEB_PUSH_HMAC_KEY_RING');
473
+ const vapidSubjectRaw = await this.qenv.getEnvVarOnDemand('DCROUTER_WEB_PUSH_VAPID_SUBJECT');
474
+ if (!encryptionKeyRingRaw || !hmacKeyRingRaw || !vapidSubjectRaw) {
475
+ throw new Error('Enabled Web Push requires master key ring, HMAC key ring, and VAPID subject');
476
+ }
477
+ this.crypto = new WebPushCrypto(parseWebPushKeyRing(encryptionKeyRingRaw, 'DCROUTER_WEB_PUSH_MASTER_KEY_RING'), parseWebPushKeyRing(hmacKeyRingRaw, 'DCROUTER_WEB_PUSH_HMAC_KEY_RING'));
478
+ this.vapidSubject = validateVapidSubject(vapidSubjectRaw);
479
+ const bindingCollection = WebPushBindingDoc.getNativeCollection();
480
+ const admissionCollection = WebPushAdmissionDoc.getNativeCollection();
481
+ const spoolCollection = WebPushSpoolDoc.getNativeCollection();
482
+ await bindingCollection.findOne({}, { projection: { _id: 1 } });
483
+ await admissionCollection.findOne({}, { projection: { _id: 1 } });
484
+ await spoolCollection.findOne({}, { projection: { _id: 1 } });
485
+ assertWebPushIndexes('WebPushBindingDoc', await bindingCollection.listIndexes().toArray());
486
+ assertWebPushIndexes('WebPushAdmissionDoc', await admissionCollection.listIndexes().toArray());
487
+ assertWebPushIndexes('WebPushSpoolDoc', await spoolCollection.listIndexes().toArray());
488
+ await this.runMaintenanceOnce();
489
+ this.started = true;
490
+ this.ready = true;
491
+ logger.log('info', 'Web Push provider is ready');
492
+ if (this.startWorker)
493
+ this.scheduleWorker(0);
494
+ }
495
+ async stop() {
496
+ this.ready = false;
497
+ if (this.workerTimer) {
498
+ clearTimeout(this.workerTimer);
499
+ this.workerTimer = undefined;
500
+ }
501
+ await this.activeWorkerCycle;
502
+ this.started = false;
503
+ }
504
+ getUnavailableServiceStatus() {
505
+ return {
506
+ ready: false,
507
+ bindingId: 'unavailable',
508
+ bindingStatus: 'disabled',
509
+ retiringVapidKeys: [],
510
+ maxPayloadBytes: MAX_PAYLOAD_BYTES,
511
+ maxTtlSeconds: MAX_TTL_SECONDS,
512
+ contentEncoding: 'aes128gcm',
513
+ message: this.enabled
514
+ ? 'Web Push provider is not ready'
515
+ : 'Web Push provider is disabled',
516
+ };
517
+ }
518
+ async listBindings(ownerFilterArg = {}) {
519
+ this.requirePersistenceReady();
520
+ const selector = {};
521
+ if (ownerFilterArg.gatewayClientType !== undefined) {
522
+ if (!['onebox', 'cloudly', 'custom'].includes(ownerFilterArg.gatewayClientType)) {
523
+ throw new plugins.typedrequest.TypedResponseError('Web Push owner filter is malformed');
524
+ }
525
+ selector.ownerGatewayClientType = ownerFilterArg.gatewayClientType;
526
+ }
527
+ if (ownerFilterArg.gatewayClientId !== undefined) {
528
+ selector.ownerGatewayClientId = requireOpaqueId(ownerFilterArg.gatewayClientId, 'Web Push owner gatewayClientId');
529
+ }
530
+ if (ownerFilterArg.appInstanceId !== undefined) {
531
+ selector.ownerAppInstanceId = requireOpaqueId(ownerFilterArg.appInstanceId, 'Web Push owner appInstanceId');
532
+ }
533
+ const rows = await WebPushBindingDoc.getNativeCollection()
534
+ .find(selector)
535
+ .sort({ createdAt: 1, id: 1 })
536
+ .limit(1000)
537
+ .toArray();
538
+ return rows.map((rowArg) => toPublicWebPushBinding(asBindingDoc(rowArg)));
539
+ }
540
+ async getBindingById(idArg) {
541
+ this.requirePersistenceReady();
542
+ const id = requireOpaqueId(idArg, 'Web Push binding id');
543
+ const row = await WebPushBindingDoc.getNativeCollection().findOne({ id });
544
+ return row ? asBindingDoc(row) : null;
545
+ }
546
+ async getBindingByCredentialId(credentialIdArg) {
547
+ this.requirePersistenceReady();
548
+ const credentialId = requireOpaqueId(credentialIdArg, 'Web Push credential id');
549
+ const row = await WebPushBindingDoc.getNativeCollection().findOne({
550
+ $or: [
551
+ { 'credential.id': credentialId },
552
+ { 'previousCredentials.id': credentialId },
553
+ ],
554
+ });
555
+ return row ? asBindingDoc(row) : null;
556
+ }
557
+ async syncBinding(bindingArg, controllerArg, createdByArg) {
558
+ this.requireReady();
559
+ const owner = normalizeOwner(bindingArg.owner);
560
+ const createdBy = requireNonEmptyString(createdByArg, 'Web Push binding creator');
561
+ if (bindingArg.enabled !== true) {
562
+ throw new plugins.typedrequest.TypedResponseError('Web Push binding synchronization only accepts enabled bindings');
563
+ }
564
+ const controller = normalizeControllerMutation(controllerArg, 'enabled');
565
+ const requestedId = bindingArg.id !== undefined
566
+ ? requireOpaqueId(bindingArg.id, 'Web Push binding id')
567
+ : undefined;
568
+ const requestDigest = controllerRequestDigest({
569
+ action: 'sync',
570
+ id: requestedId ?? null,
571
+ owner,
572
+ enabled: bindingArg.enabled,
573
+ });
574
+ const collection = WebPushBindingDoc.getNativeCollection();
575
+ const byId = requestedId ? await collection.findOne({ id: requestedId }) : null;
576
+ const byOwner = await collection.findOne({
577
+ ownerGatewayClientType: owner.gatewayClientType,
578
+ ownerGatewayClientId: owner.gatewayClientId,
579
+ ownerAppInstanceId: owner.appInstanceId,
580
+ });
581
+ if (byId && byOwner && String(byId.id) !== String(byOwner.id)) {
582
+ throw new plugins.typedrequest.TypedResponseError('Web Push binding identity conflicts with owner');
583
+ }
584
+ if (requestedId && byOwner && String(byOwner.id) !== requestedId) {
585
+ throw new plugins.typedrequest.TypedResponseError('Web Push binding identity conflicts with owner');
586
+ }
587
+ const existingRaw = byId || byOwner;
588
+ if (existingRaw) {
589
+ const existing = asBindingDoc(existingRaw);
590
+ this.assertBindingOwner(existing, owner);
591
+ if (controllerFenceDecision(existing.controllerFence, controller, requestDigest)
592
+ === 'replay') {
593
+ return await this.resumeControllerSyncReplay(existing, controller, requestDigest);
594
+ }
595
+ const lifecycleGeneration = requireLifecycleGeneration(existing.lifecycleGeneration);
596
+ if (typeof existing.deletedAt === 'number') {
597
+ await this.scrubDeletedBindingLifecycle(existing);
598
+ const scrubbedRaw = await collection.findOne({
599
+ id: existing.id,
600
+ lifecycleGeneration,
601
+ deletedAt: existing.deletedAt,
602
+ });
603
+ if (!scrubbedRaw) {
604
+ throw new plugins.typedrequest.TypedResponseError('Web Push binding changed concurrently; retry synchronization');
605
+ }
606
+ const scrubbed = asBindingDoc(scrubbedRaw);
607
+ if (controllerFenceDecision(scrubbed.controllerFence, controller, requestDigest)
608
+ === 'replay') {
609
+ return await this.resumeControllerSyncReplay(scrubbed, controller, requestDigest);
610
+ }
611
+ const now = this.now();
612
+ const createdCredential = this.createCredential(scrubbed.id, now);
613
+ const nextLifecycleGeneration = lifecycleGeneration + 1;
614
+ const reactivated = await collection.updateOne({
615
+ id: scrubbed.id,
616
+ mutationRevision: scrubbed.mutationRevision,
617
+ deletedAt: scrubbed.deletedAt,
618
+ lifecycleGeneration,
619
+ }, {
620
+ $set: {
621
+ enabled: true,
622
+ status: 'active',
623
+ credential: createdCredential.stored,
624
+ previousCredentials: [],
625
+ vapidKeys: [this.createVapidKey(owner, scrubbed.id, now)],
626
+ updatedAt: now,
627
+ lifecycleGeneration: nextLifecycleGeneration,
628
+ controllerFence: createControllerFence(controller, requestDigest, now),
629
+ mutationRevision: scrubbed.mutationRevision + 1,
630
+ _updatedAt: new Date(now).toISOString(),
631
+ },
632
+ $unset: {
633
+ deletedAt: '',
634
+ credentialRotationRecovery: '',
635
+ },
636
+ });
637
+ if (reactivated.matchedCount !== 1) {
638
+ throw new plugins.typedrequest.TypedResponseError('Web Push binding changed concurrently; retry synchronization');
639
+ }
640
+ await WebPushAdmissionDoc.getNativeCollection().deleteMany({
641
+ bindingId: scrubbed.id,
642
+ lifecycleGeneration: { $lt: nextLifecycleGeneration },
643
+ });
644
+ const refreshed = await collection.findOne({
645
+ id: scrubbed.id,
646
+ lifecycleGeneration: nextLifecycleGeneration,
647
+ deletedAt: { $exists: false },
648
+ });
649
+ if (!refreshed)
650
+ throw new Error('Reactivated Web Push binding disappeared');
651
+ return {
652
+ binding: toPublicWebPushBinding(asBindingDoc(refreshed)),
653
+ credential: createdCredential.oneTime,
654
+ };
655
+ }
656
+ if (bindingArg.enabled && !existing.enabled) {
657
+ await this.drainBindingLifecyclesBefore(existing.id, lifecycleGeneration, 'BINDING_DISABLED');
658
+ const stillDisabled = await collection.findOne({
659
+ id: existing.id,
660
+ mutationRevision: existing.mutationRevision,
661
+ lifecycleGeneration,
662
+ enabled: false,
663
+ deletedAt: { $exists: false },
664
+ }, { projection: { _id: 1 } });
665
+ if (!stillDisabled) {
666
+ throw new plugins.typedrequest.TypedResponseError('Web Push binding changed concurrently; retry synchronization');
667
+ }
668
+ }
669
+ let credential;
670
+ const now = this.now();
671
+ const lifecycleChanged = existing.enabled !== bindingArg.enabled;
672
+ const nextLifecycleGeneration = lifecycleChanged
673
+ ? lifecycleGeneration + 1
674
+ : lifecycleGeneration;
675
+ const nextCredential = { ...existing.credential };
676
+ if (bindingArg.enabled && nextCredential.status === 'revoked') {
677
+ const created = this.createCredential(existing.id, now);
678
+ Object.assign(nextCredential, created.stored);
679
+ credential = created.oneTime;
680
+ }
681
+ else {
682
+ nextCredential.status = bindingArg.enabled ? 'active' : 'disabled';
683
+ nextCredential.updatedAt = now;
684
+ }
685
+ const update = {
686
+ $set: {
687
+ enabled: bindingArg.enabled,
688
+ status: bindingArg.enabled ? 'active' : 'disabled',
689
+ credential: nextCredential,
690
+ updatedAt: now,
691
+ lifecycleGeneration: nextLifecycleGeneration,
692
+ controllerFence: createControllerFence(controller, requestDigest, now),
693
+ mutationRevision: existing.mutationRevision + 1,
694
+ _updatedAt: new Date(now).toISOString(),
695
+ ...(lifecycleChanged ? { previousCredentials: [] } : {}),
696
+ },
697
+ };
698
+ if (lifecycleChanged) {
699
+ update.$unset = {
700
+ credentialRotationRecovery: '',
701
+ };
702
+ }
703
+ const updated = await collection.updateOne({
704
+ id: existing.id,
705
+ mutationRevision: existing.mutationRevision,
706
+ lifecycleGeneration,
707
+ enabled: existing.enabled,
708
+ deletedAt: { $exists: false },
709
+ }, update);
710
+ if (updated.matchedCount !== 1) {
711
+ throw new plugins.typedrequest.TypedResponseError('Web Push binding changed concurrently; retry synchronization');
712
+ }
713
+ if (lifecycleChanged) {
714
+ await WebPushAdmissionDoc.getNativeCollection().deleteMany({
715
+ bindingId: existing.id,
716
+ lifecycleGeneration: { $lt: nextLifecycleGeneration },
717
+ });
718
+ }
719
+ if (!bindingArg.enabled || lifecycleChanged) {
720
+ await this.drainBindingLifecyclesBefore(existing.id, nextLifecycleGeneration, bindingArg.enabled ? 'BINDING_LIFECYCLE_CHANGED' : 'BINDING_DISABLED');
721
+ }
722
+ const refreshed = await collection.findOne({ id: existing.id });
723
+ if (!refreshed)
724
+ throw new Error('Synchronized Web Push binding disappeared');
725
+ return {
726
+ binding: toPublicWebPushBinding(asBindingDoc(refreshed)),
727
+ credential,
728
+ };
729
+ }
730
+ const now = this.now();
731
+ const id = requestedId ?? plugins.uuid.v4();
732
+ const createdCredential = this.createCredential(id, now);
733
+ const vapidKey = this.createVapidKey(owner, id, now);
734
+ const doc = new WebPushBindingDoc();
735
+ doc.id = id;
736
+ doc.ownerGatewayClientType = owner.gatewayClientType;
737
+ doc.ownerGatewayClientId = owner.gatewayClientId;
738
+ doc.ownerAppInstanceId = owner.appInstanceId;
739
+ doc.enabled = bindingArg.enabled;
740
+ doc.status = bindingArg.enabled ? 'active' : 'disabled';
741
+ doc.credential = {
742
+ ...createdCredential.stored,
743
+ status: bindingArg.enabled ? 'active' : 'disabled',
744
+ };
745
+ doc.previousCredentials = [];
746
+ doc.vapidKeys = [vapidKey];
747
+ doc.createdAt = now;
748
+ doc.updatedAt = now;
749
+ doc.createdBy = createdBy;
750
+ doc.mutationRevision = 1;
751
+ doc.lifecycleGeneration = 1;
752
+ doc.controllerFence = createControllerFence(controller, requestDigest, now);
753
+ try {
754
+ await doc.save();
755
+ }
756
+ catch (error) {
757
+ if (!isDuplicateKeyError(error))
758
+ throw error;
759
+ const raced = await collection.findOne({
760
+ ownerGatewayClientType: owner.gatewayClientType,
761
+ ownerGatewayClientId: owner.gatewayClientId,
762
+ ownerAppInstanceId: owner.appInstanceId,
763
+ });
764
+ if (!raced)
765
+ throw error;
766
+ const racedBinding = asBindingDoc(raced);
767
+ this.assertBindingOwner(racedBinding, owner);
768
+ if (controllerFenceDecision(racedBinding.controllerFence, controller, requestDigest)
769
+ === 'replay') {
770
+ return await this.resumeControllerSyncReplay(racedBinding, controller, requestDigest);
771
+ }
772
+ throw new plugins.typedrequest.TypedResponseError('Web Push binding changed concurrently; retry synchronization');
773
+ }
774
+ return {
775
+ binding: toPublicWebPushBinding(doc),
776
+ credential: createdCredential.oneTime,
777
+ };
778
+ }
779
+ async resumeControllerSyncReplay(bindingArg, controllerArg, requestDigestArg) {
780
+ const lifecycleGeneration = requireLifecycleGeneration(bindingArg.lifecycleGeneration);
781
+ if (controllerArg.intent === 'enabled') {
782
+ if (!bindingArg.enabled
783
+ || bindingArg.status !== 'active'
784
+ || typeof bindingArg.deletedAt === 'number') {
785
+ throw new Error('Applied Web Push enable controller mutation is inconsistent');
786
+ }
787
+ await this.drainBindingLifecyclesBefore(bindingArg.id, lifecycleGeneration, 'BINDING_LIFECYCLE_CHANGED');
788
+ }
789
+ else if (controllerArg.intent === 'disabled') {
790
+ if (bindingArg.enabled) {
791
+ throw new Error('Applied Web Push disable controller mutation is inconsistent');
792
+ }
793
+ if (typeof bindingArg.deletedAt === 'number') {
794
+ await this.scrubDeletedBindingLifecycle(bindingArg);
795
+ }
796
+ else {
797
+ await this.drainBindingLifecyclesBefore(bindingArg.id, lifecycleGeneration, 'BINDING_DISABLED');
798
+ }
799
+ }
800
+ else {
801
+ throw new Error('Delete controller mutation cannot be replayed as synchronization');
802
+ }
803
+ const refreshedRaw = await WebPushBindingDoc.getNativeCollection().findOne({
804
+ id: bindingArg.id,
805
+ });
806
+ if (!refreshedRaw)
807
+ throw new Error('Synchronized Web Push binding disappeared');
808
+ const refreshed = asBindingDoc(refreshedRaw);
809
+ controllerFenceDecision(refreshed.controllerFence, controllerArg, requestDigestArg);
810
+ return {
811
+ binding: toPublicWebPushBinding(refreshed),
812
+ };
813
+ }
814
+ async deleteBinding(deleteArg, deletedByArg) {
815
+ this.requireReady();
816
+ const owner = normalizeOwner(deleteArg?.owner);
817
+ const deletedBy = requireNonEmptyString(deletedByArg, 'Web Push binding deletion actor');
818
+ const requestedId = deleteArg.id !== undefined
819
+ ? requireOpaqueId(deleteArg.id, 'Web Push binding id')
820
+ : undefined;
821
+ const controller = normalizeDeleteControllerMutation(deleteArg.controller);
822
+ const requestDigest = controllerRequestDigest({
823
+ action: 'delete',
824
+ id: requestedId ?? null,
825
+ owner,
826
+ });
827
+ const collection = WebPushBindingDoc.getNativeCollection();
828
+ const byId = requestedId ? await collection.findOne({ id: requestedId }) : null;
829
+ const byOwner = await collection.findOne({
830
+ ownerGatewayClientType: owner.gatewayClientType,
831
+ ownerGatewayClientId: owner.gatewayClientId,
832
+ ownerAppInstanceId: owner.appInstanceId,
833
+ });
834
+ if (byId && byOwner && String(byId.id) !== String(byOwner.id)) {
835
+ throw new plugins.typedrequest.TypedResponseError('Web Push binding identity conflicts with owner');
836
+ }
837
+ if (requestedId && byOwner && String(byOwner.id) !== requestedId) {
838
+ throw new plugins.typedrequest.TypedResponseError('Web Push binding identity conflicts with owner');
839
+ }
840
+ const existingRaw = byId || byOwner;
841
+ if (!existingRaw) {
842
+ const now = this.now();
843
+ const id = requestedId ?? plugins.uuid.v4();
844
+ const tombstone = new WebPushBindingDoc();
845
+ tombstone.id = id;
846
+ tombstone.ownerGatewayClientType = owner.gatewayClientType;
847
+ tombstone.ownerGatewayClientId = owner.gatewayClientId;
848
+ tombstone.ownerAppInstanceId = owner.appInstanceId;
849
+ tombstone.enabled = false;
850
+ tombstone.status = 'disabled';
851
+ tombstone.credential = {
852
+ id: plugins.uuid.v4(),
853
+ status: 'revoked',
854
+ hmacKeyId: this.crypto.currentHmacKeyId,
855
+ createdAt: now,
856
+ updatedAt: now,
857
+ lastRotatedAt: null,
858
+ validUntil: null,
859
+ };
860
+ tombstone.previousCredentials = [];
861
+ tombstone.vapidKeys = [];
862
+ tombstone.createdAt = now;
863
+ tombstone.updatedAt = now;
864
+ tombstone.createdBy = deletedBy;
865
+ tombstone.mutationRevision = 1;
866
+ tombstone.lifecycleGeneration = 1;
867
+ tombstone.controllerFence = createControllerFence(controller, requestDigest, now);
868
+ tombstone.deletedAt = now;
869
+ try {
870
+ await tombstone.save();
871
+ }
872
+ catch (error) {
873
+ if (!isDuplicateKeyError(error))
874
+ throw error;
875
+ return await this.deleteBinding(deleteArg, deletedBy);
876
+ }
877
+ await this.scrubDeletedBindingLifecycle(tombstone);
878
+ return true;
879
+ }
880
+ const binding = asBindingDoc(existingRaw);
881
+ this.assertBindingOwner(binding, owner);
882
+ if (controllerFenceDecision(binding.controllerFence, controller, requestDigest)
883
+ === 'replay') {
884
+ return await this.resumeControllerDeleteReplay(binding, controller, requestDigest);
885
+ }
886
+ const lifecycleGeneration = requireLifecycleGeneration(binding.lifecycleGeneration);
887
+ if (typeof binding.deletedAt === 'number') {
888
+ await this.scrubDeletedBindingLifecycle(binding);
889
+ const scrubbedRaw = await collection.findOne({
890
+ id: binding.id,
891
+ lifecycleGeneration,
892
+ deletedAt: binding.deletedAt,
893
+ enabled: false,
894
+ });
895
+ if (!scrubbedRaw) {
896
+ throw new plugins.typedrequest.TypedResponseError('Web Push binding changed concurrently; retry deletion');
897
+ }
898
+ const scrubbed = asBindingDoc(scrubbedRaw);
899
+ if (controllerFenceDecision(scrubbed.controllerFence, controller, requestDigest)
900
+ === 'replay') {
901
+ return await this.resumeControllerDeleteReplay(scrubbed, controller, requestDigest);
902
+ }
903
+ const now = this.now();
904
+ const recorded = await collection.updateOne({
905
+ id: scrubbed.id,
906
+ mutationRevision: scrubbed.mutationRevision,
907
+ lifecycleGeneration,
908
+ deletedAt: scrubbed.deletedAt,
909
+ }, {
910
+ $set: {
911
+ controllerFence: createControllerFence(controller, requestDigest, now),
912
+ updatedAt: now,
913
+ mutationRevision: scrubbed.mutationRevision + 1,
914
+ _updatedAt: new Date(now).toISOString(),
915
+ },
916
+ });
917
+ if (recorded.matchedCount !== 1) {
918
+ throw new plugins.typedrequest.TypedResponseError('Web Push binding changed concurrently; retry deletion');
919
+ }
920
+ const refreshedRaw = await collection.findOne({ id: scrubbed.id });
921
+ if (!refreshedRaw)
922
+ throw new Error('Deleted Web Push binding tombstone disappeared');
923
+ return await this.resumeControllerDeleteReplay(asBindingDoc(refreshedRaw), controller, requestDigest);
924
+ }
925
+ const now = this.now();
926
+ const revokedCredential = {
927
+ ...binding.credential,
928
+ status: 'revoked',
929
+ updatedAt: now,
930
+ validUntil: null,
931
+ };
932
+ delete revokedCredential.secretHash;
933
+ const scrubbedVapidKeys = (binding.vapidKeys || []).map((keyArg) => {
934
+ const scrubbed = {
935
+ ...keyArg,
936
+ status: 'retired',
937
+ retireAfter: null,
938
+ retiredAt: now,
939
+ };
940
+ delete scrubbed.privateKeyEnvelope;
941
+ return scrubbed;
942
+ });
943
+ const deletedLifecycleGeneration = lifecycleGeneration + 1;
944
+ const result = await WebPushBindingDoc.getNativeCollection().updateOne({
945
+ id: binding.id,
946
+ mutationRevision: binding.mutationRevision,
947
+ lifecycleGeneration,
948
+ deletedAt: { $exists: false },
949
+ }, {
950
+ $set: {
951
+ enabled: false,
952
+ status: 'disabled',
953
+ credential: revokedCredential,
954
+ previousCredentials: [],
955
+ vapidKeys: scrubbedVapidKeys,
956
+ deletedAt: now,
957
+ lifecycleGeneration: deletedLifecycleGeneration,
958
+ controllerFence: createControllerFence(controller, requestDigest, now),
959
+ updatedAt: now,
960
+ mutationRevision: binding.mutationRevision + 1,
961
+ _updatedAt: new Date(now).toISOString(),
962
+ },
963
+ $unset: {
964
+ credentialRotationRecovery: '',
965
+ },
966
+ });
967
+ if (result.matchedCount !== 1) {
968
+ throw new plugins.typedrequest.TypedResponseError('Web Push binding changed concurrently; retry deletion');
969
+ }
970
+ const tombstone = await WebPushBindingDoc.getNativeCollection().findOne({
971
+ id: binding.id,
972
+ lifecycleGeneration: deletedLifecycleGeneration,
973
+ deletedAt: now,
974
+ });
975
+ if (!tombstone) {
976
+ throw new Error('Deleted Web Push binding tombstone disappeared');
977
+ }
978
+ await this.scrubDeletedBindingLifecycle(asBindingDoc(tombstone));
979
+ return true;
980
+ }
981
+ async resumeControllerDeleteReplay(bindingArg, controllerArg, requestDigestArg) {
982
+ if (bindingArg.enabled || typeof bindingArg.deletedAt !== 'number') {
983
+ throw new Error('Applied Web Push delete controller mutation is inconsistent');
984
+ }
985
+ await this.scrubDeletedBindingLifecycle(bindingArg);
986
+ const refreshedRaw = await WebPushBindingDoc.getNativeCollection().findOne({
987
+ id: bindingArg.id,
988
+ });
989
+ if (!refreshedRaw)
990
+ throw new Error('Deleted Web Push binding tombstone disappeared');
991
+ const refreshed = asBindingDoc(refreshedRaw);
992
+ controllerFenceDecision(refreshed.controllerFence, controllerArg, requestDigestArg);
993
+ if (refreshed.enabled || typeof refreshed.deletedAt !== 'number') {
994
+ throw new Error('Applied Web Push delete controller mutation is inconsistent');
995
+ }
996
+ return true;
997
+ }
998
+ async rotateCredential(credentialIdArg) {
999
+ this.requireReady();
1000
+ const requestedCredentialId = requireOpaqueId(credentialIdArg, 'Web Push credential id');
1001
+ for (let attempt = 0; attempt < 4; attempt++) {
1002
+ const binding = await this.getBindingByCredentialId(requestedCredentialId);
1003
+ if (!binding
1004
+ || !binding.enabled
1005
+ || binding.status !== 'active'
1006
+ || typeof binding.deletedAt === 'number') {
1007
+ throw new plugins.typedrequest.TypedResponseError('Active Web Push credential not found');
1008
+ }
1009
+ const now = this.now();
1010
+ const replay = this.replayCredentialRotation(binding, requestedCredentialId, now);
1011
+ if (replay)
1012
+ return replay;
1013
+ if (binding.credential.id !== requestedCredentialId) {
1014
+ throw new plugins.typedrequest.TypedResponseError('Active Web Push credential not found');
1015
+ }
1016
+ const unexpiredPrevious = (binding.previousCredentials || []).filter((credentialArg) => (credentialArg.secretHash
1017
+ && credentialArg.validUntil !== null
1018
+ && credentialArg.validUntil > now));
1019
+ if (unexpiredPrevious.length > 0) {
1020
+ throw new plugins.typedrequest.TypedResponseError('Web Push credential rotation overlap is still active');
1021
+ }
1022
+ const lifecycleGeneration = requireLifecycleGeneration(binding.lifecycleGeneration);
1023
+ const created = this.createCredential(binding.id, now);
1024
+ const previous = {
1025
+ ...binding.credential,
1026
+ status: 'rotated',
1027
+ updatedAt: now,
1028
+ lastRotatedAt: now,
1029
+ validUntil: now + CREDENTIAL_OVERLAP_MS,
1030
+ };
1031
+ const recoveryIdentity = {
1032
+ requestedCredentialId,
1033
+ resultingCredentialId: created.stored.id,
1034
+ lifecycleGeneration,
1035
+ };
1036
+ const recovery = {
1037
+ ...recoveryIdentity,
1038
+ secretEnvelope: this.crypto.encryptJson({ secret: created.oneTime.secret }, this.credentialRotationRecoveryAad(binding, recoveryIdentity)),
1039
+ createdAt: now,
1040
+ expiresAt: now + CREDENTIAL_OVERLAP_MS,
1041
+ };
1042
+ const result = await WebPushBindingDoc.getNativeCollection().updateOne({
1043
+ id: binding.id,
1044
+ mutationRevision: binding.mutationRevision,
1045
+ lifecycleGeneration,
1046
+ enabled: true,
1047
+ status: 'active',
1048
+ 'credential.id': requestedCredentialId,
1049
+ deletedAt: { $exists: false },
1050
+ }, {
1051
+ $set: {
1052
+ credential: created.stored,
1053
+ previousCredentials: [previous],
1054
+ credentialRotationRecovery: recovery,
1055
+ updatedAt: now,
1056
+ mutationRevision: binding.mutationRevision + 1,
1057
+ _updatedAt: new Date(now).toISOString(),
1058
+ },
1059
+ });
1060
+ if (result.matchedCount === 1)
1061
+ return created.oneTime;
1062
+ const raced = await this.getBindingByCredentialId(requestedCredentialId);
1063
+ if (raced) {
1064
+ const racedReplay = this.replayCredentialRotation(raced, requestedCredentialId, this.now());
1065
+ if (racedReplay)
1066
+ return racedReplay;
1067
+ }
1068
+ }
1069
+ throw new plugins.typedrequest.TypedResponseError('Web Push binding changed concurrently; retry credential rotation');
1070
+ }
1071
+ async rotateVapidKey(bindingIdArg) {
1072
+ this.requireReady();
1073
+ await this.cleanupRetiredVapidKeys(bindingIdArg);
1074
+ const binding = await this.getBindingById(bindingIdArg);
1075
+ if (!binding
1076
+ || !binding.enabled
1077
+ || binding.status !== 'active'
1078
+ || typeof binding.deletedAt === 'number') {
1079
+ throw new plugins.typedrequest.TypedResponseError('Active Web Push binding not found');
1080
+ }
1081
+ if ((binding.vapidKeys || []).length >= VAPID_KEY_RING_LIMIT) {
1082
+ throw new plugins.typedrequest.TypedResponseError('Web Push VAPID key ring is full; retiring keys are still in use');
1083
+ }
1084
+ const now = this.now();
1085
+ const owner = this.bindingOwner(binding);
1086
+ const nextKeys = (binding.vapidKeys || []).map((keyArg) => (keyArg.status === 'active'
1087
+ ? {
1088
+ ...keyArg,
1089
+ status: 'retiring',
1090
+ retireAfter: now + VAPID_RETIREMENT_MS,
1091
+ }
1092
+ : keyArg));
1093
+ nextKeys.push(this.createVapidKey(owner, binding.id, now));
1094
+ const result = await WebPushBindingDoc.getNativeCollection().updateOne({ id: binding.id, mutationRevision: binding.mutationRevision }, {
1095
+ $set: {
1096
+ vapidKeys: nextKeys,
1097
+ updatedAt: now,
1098
+ mutationRevision: binding.mutationRevision + 1,
1099
+ _updatedAt: new Date(now).toISOString(),
1100
+ },
1101
+ });
1102
+ if (result.matchedCount !== 1) {
1103
+ throw new plugins.typedrequest.TypedResponseError('Web Push binding changed concurrently; retry VAPID rotation');
1104
+ }
1105
+ const refreshed = await this.getBindingById(binding.id);
1106
+ if (!refreshed)
1107
+ throw new Error('Rotated Web Push binding disappeared');
1108
+ return toPublicWebPushBinding(refreshed);
1109
+ }
1110
+ async authenticateAppCredential(authArg) {
1111
+ this.requireReady();
1112
+ const credentialId = requireOpaqueId(authArg?.credentialId, 'Web Push credential id');
1113
+ const credentialSecret = requireNonEmptyString(authArg?.credentialSecret, 'Web Push credential secret', 512);
1114
+ const binding = await this.getBindingByCredentialId(credentialId);
1115
+ if (!binding
1116
+ || !binding.enabled
1117
+ || binding.status !== 'active'
1118
+ || typeof binding.deletedAt === 'number') {
1119
+ throw new plugins.typedrequest.TypedResponseError('Web Push credential is invalid');
1120
+ }
1121
+ requireLifecycleGeneration(binding.lifecycleGeneration);
1122
+ const now = this.now();
1123
+ const credential = binding.credential.id === credentialId
1124
+ ? binding.credential
1125
+ : (binding.previousCredentials || []).find((entryArg) => entryArg.id === credentialId);
1126
+ const credentialUsable = credential
1127
+ && typeof credential.secretHash === 'string'
1128
+ && (credential.status === 'active'
1129
+ || (credential.status === 'rotated'
1130
+ && credential.validUntil !== null
1131
+ && credential.validUntil > now));
1132
+ if (!credentialUsable
1133
+ || !this.crypto.verifyHmac('credential', this.credentialHmacValue(binding.id, credentialId, credentialSecret), credential.hmacKeyId, credential.secretHash)) {
1134
+ throw new plugins.typedrequest.TypedResponseError('Web Push credential is invalid');
1135
+ }
1136
+ return {
1137
+ binding,
1138
+ credential,
1139
+ };
1140
+ }
1141
+ async getServiceStatus(authArg) {
1142
+ const context = await this.authenticateAppCredential(authArg);
1143
+ const activeVapidKey = context.binding.vapidKeys.find((keyArg) => keyArg.status === 'active');
1144
+ return {
1145
+ ready: Boolean(activeVapidKey?.privateKeyEnvelope),
1146
+ bindingId: context.binding.id,
1147
+ bindingStatus: context.binding.status,
1148
+ ...(activeVapidKey ? { activeVapidKey: toVapidKeyPublic(activeVapidKey) } : {}),
1149
+ retiringVapidKeys: context.binding.vapidKeys
1150
+ .filter((keyArg) => keyArg.status === 'retiring')
1151
+ .map((keyArg) => toVapidKeyPublic(keyArg)),
1152
+ maxPayloadBytes: MAX_PAYLOAD_BYTES,
1153
+ maxTtlSeconds: MAX_TTL_SECONDS,
1154
+ contentEncoding: 'aes128gcm',
1155
+ ...(!activeVapidKey ? { message: 'Web Push binding has no active VAPID key' } : {}),
1156
+ };
1157
+ }
1158
+ async enqueue(authArg, requestArg) {
1159
+ const context = await this.authenticateAppCredential(authArg);
1160
+ const idempotencyKey = requireNonEmptyString(requestArg.idempotencyKey, 'Web Push idempotencyKey', MAX_IDEMPOTENCY_KEY_LENGTH);
1161
+ const subscriptionId = requireOpaqueId(requestArg.subscriptionId, 'Web Push subscriptionId');
1162
+ const subscription = normalizeSubscription(requestArg.subscription);
1163
+ const vapidKeyId = requireOpaqueId(requestArg.vapidKeyId, 'Web Push vapidKeyId');
1164
+ const payload = normalizePayload(requestArg.payload);
1165
+ const ttlSeconds = normalizeTtl(requestArg.ttlSeconds);
1166
+ const urgency = normalizeUrgency(requestArg.urgency);
1167
+ const collapseKey = requestArg.collapseKey === undefined
1168
+ ? undefined
1169
+ : requireNonEmptyString(requestArg.collapseKey, 'Web Push collapseKey', MAX_COLLAPSE_KEY_LENGTH);
1170
+ const now = this.now();
1171
+ const lifecycleGeneration = requireLifecycleGeneration(context.binding.lifecycleGeneration);
1172
+ const vapidKey = context.binding.vapidKeys.find((keyArg) => (keyArg.id === vapidKeyId
1173
+ && Boolean(keyArg.privateKeyEnvelope)
1174
+ && (keyArg.status === 'active'
1175
+ || (keyArg.status === 'retiring'
1176
+ && keyArg.retireAfter !== null
1177
+ && keyArg.retireAfter > now))));
1178
+ if (!vapidKey) {
1179
+ throw new plugins.typedrequest.TypedResponseError('Web Push VAPID key is not active for new delivery');
1180
+ }
1181
+ const hmacKeyId = context.credential.hmacKeyId;
1182
+ const idempotencyKeyDigest = this.crypto.hmac('idempotency-key', `${context.credential.id}\0${idempotencyKey}`, hmacKeyId).digest;
1183
+ const canonicalRequest = canonicalJson({
1184
+ subscriptionId,
1185
+ subscription,
1186
+ vapidKeyId,
1187
+ payload,
1188
+ ttlSeconds,
1189
+ urgency,
1190
+ collapseKey: collapseKey ?? null,
1191
+ });
1192
+ const requestDigest = this.crypto.hmac('request', canonicalRequest, hmacKeyId).digest;
1193
+ const collection = WebPushSpoolDoc.getNativeCollection();
1194
+ const existing = await collection.findOne({
1195
+ bindingId: context.binding.id,
1196
+ lifecycleGeneration,
1197
+ credentialId: context.credential.id,
1198
+ idempotencyKeyDigest,
1199
+ });
1200
+ if (existing) {
1201
+ await this.assertBindingLifecycleActive(context.binding);
1202
+ const spool = asSpoolDoc(existing);
1203
+ if (!constantTimeDigestEqual(spool.requestDigest, requestDigest)) {
1204
+ throw new plugins.typedrequest.TypedResponseError('Web Push idempotency key conflicts with a different request');
1205
+ }
1206
+ return {
1207
+ accepted: true,
1208
+ spoolItemId: spool.id,
1209
+ };
1210
+ }
1211
+ await this.assertBindingLifecycleActive(context.binding);
1212
+ await this.reserveAdmission(context.binding);
1213
+ const nonterminalCount = await collection.countDocuments({
1214
+ bindingId: context.binding.id,
1215
+ lifecycleGeneration,
1216
+ state: { $in: NONTERMINAL_STATES },
1217
+ });
1218
+ if (nonterminalCount >= MAX_NONTERMINAL_ITEMS_PER_BINDING) {
1219
+ throw new plugins.typedrequest.TypedResponseError('Web Push binding queue quota exceeded');
1220
+ }
1221
+ const spoolId = plugins.uuid.v4();
1222
+ const aadBase = this.spoolAadBase(context.binding, spoolId);
1223
+ const payloadText = canonicalJson(payload);
1224
+ const endpointDigest = this.crypto.hmac('endpoint', `${context.binding.id}\0${subscription.endpoint}`, hmacKeyId).digest;
1225
+ const topic = collapseKey
1226
+ ? Buffer.from(this.crypto.hmac('topic', `${context.binding.id}\0${collapseKey}`, hmacKeyId).digest, 'base64url').subarray(0, 24).toString('base64url')
1227
+ : null;
1228
+ const spool = new WebPushSpoolDoc();
1229
+ spool.id = spoolId;
1230
+ spool.bindingId = context.binding.id;
1231
+ spool.lifecycleGeneration = lifecycleGeneration;
1232
+ spool.credentialId = context.credential.id;
1233
+ spool.hmacKeyId = hmacKeyId;
1234
+ spool.idempotencyKeyDigest = idempotencyKeyDigest;
1235
+ spool.requestDigest = requestDigest;
1236
+ spool.subscriptionId = subscriptionId;
1237
+ spool.endpointDigest = endpointDigest;
1238
+ spool.vapidKeyId = vapidKeyId;
1239
+ spool.subscriptionEnvelope = this.crypto.encryptJson(subscription, {
1240
+ ...aadBase,
1241
+ documentType: 'spool-subscription',
1242
+ });
1243
+ spool.payloadEnvelope = this.crypto.encryptJson(payload, {
1244
+ ...aadBase,
1245
+ documentType: 'spool-payload',
1246
+ });
1247
+ spool.payloadBytes = Buffer.byteLength(payloadText, 'utf8');
1248
+ spool.ttlSeconds = ttlSeconds;
1249
+ spool.urgency = urgency;
1250
+ spool.topic = topic;
1251
+ spool.state = 'accepted';
1252
+ spool.attempts = 0;
1253
+ spool.acceptedAt = now;
1254
+ spool.updatedAt = now;
1255
+ spool.nextAttemptAt = now;
1256
+ spool.expiresAt = now + ttlSeconds * 1000;
1257
+ spool.pushServiceStatusCode = null;
1258
+ spool.errorCode = null;
1259
+ try {
1260
+ await spool.save();
1261
+ }
1262
+ catch (error) {
1263
+ if (!isDuplicateKeyError(error))
1264
+ throw error;
1265
+ const raced = await collection.findOne({
1266
+ bindingId: context.binding.id,
1267
+ lifecycleGeneration,
1268
+ credentialId: context.credential.id,
1269
+ idempotencyKeyDigest,
1270
+ });
1271
+ if (!raced)
1272
+ throw error;
1273
+ const racedSpool = asSpoolDoc(raced);
1274
+ if (!constantTimeDigestEqual(racedSpool.requestDigest, requestDigest)) {
1275
+ throw new plugins.typedrequest.TypedResponseError('Web Push idempotency key conflicts with a different request');
1276
+ }
1277
+ await this.cancelSpoolIfLifecycleChanged(racedSpool.id, context.binding.id, lifecycleGeneration);
1278
+ return {
1279
+ accepted: true,
1280
+ spoolItemId: racedSpool.id,
1281
+ };
1282
+ }
1283
+ await this.cancelSpoolIfLifecycleChanged(spool.id, context.binding.id, lifecycleGeneration);
1284
+ return {
1285
+ accepted: true,
1286
+ spoolItemId: spool.id,
1287
+ };
1288
+ }
1289
+ async getDeliveryStatus(authArg, spoolItemIdArg) {
1290
+ const context = await this.authenticateAppCredential(authArg);
1291
+ const spoolItemId = requireOpaqueId(spoolItemIdArg, 'Web Push spoolItemId');
1292
+ const lifecycleGeneration = requireLifecycleGeneration(context.binding.lifecycleGeneration);
1293
+ const row = await WebPushSpoolDoc.getNativeCollection().findOne({
1294
+ id: spoolItemId,
1295
+ bindingId: context.binding.id,
1296
+ lifecycleGeneration,
1297
+ });
1298
+ return row ? toPublicWebPushDelivery(asSpoolDoc(row)) : undefined;
1299
+ }
1300
+ async cancel(authArg, targetArg) {
1301
+ const context = await this.authenticateAppCredential(authArg);
1302
+ return await this.cancelWithinBinding(context.binding.id, targetArg, false, context.binding.lifecycleGeneration);
1303
+ }
1304
+ async processDueDeliveriesOnce(limitArg = DELIVERY_BATCH_SIZE) {
1305
+ this.requireReady();
1306
+ const limit = Math.min(Math.max(Math.floor(limitArg), 1), 100);
1307
+ await this.runMaintenanceOnce();
1308
+ await this.expireDueItems(limit);
1309
+ let processed = 0;
1310
+ for (let index = 0; index < limit; index++) {
1311
+ // stop() flips readiness before waiting for the active cycle. Check the
1312
+ // boundary between deliveries so shutdown waits for at most one send.
1313
+ if (!this.ready)
1314
+ break;
1315
+ const claimed = await this.claimNextItem();
1316
+ if (!claimed)
1317
+ break;
1318
+ await this.processClaimedItem(claimed);
1319
+ processed++;
1320
+ }
1321
+ return processed;
1322
+ }
1323
+ requirePersistenceReady() {
1324
+ if (!this.started || !this.enabled || !this.crypto) {
1325
+ throw new plugins.typedrequest.TypedResponseError('Web Push provider is unavailable');
1326
+ }
1327
+ }
1328
+ requireReady() {
1329
+ if (!this.ready || !this.crypto || !this.vapidSubject) {
1330
+ throw new plugins.typedrequest.TypedResponseError('Web Push provider is unavailable');
1331
+ }
1332
+ }
1333
+ bindingOwner(bindingArg) {
1334
+ return {
1335
+ gatewayClientType: bindingArg.ownerGatewayClientType,
1336
+ gatewayClientId: bindingArg.ownerGatewayClientId,
1337
+ appInstanceId: bindingArg.ownerAppInstanceId,
1338
+ };
1339
+ }
1340
+ assertBindingOwner(bindingArg, ownerArg) {
1341
+ if (bindingArg.ownerGatewayClientType !== ownerArg.gatewayClientType
1342
+ || bindingArg.ownerGatewayClientId !== ownerArg.gatewayClientId
1343
+ || bindingArg.ownerAppInstanceId !== ownerArg.appInstanceId) {
1344
+ throw new plugins.typedrequest.TypedResponseError('Web Push binding owner cannot be changed');
1345
+ }
1346
+ }
1347
+ credentialHmacValue(bindingIdArg, credentialIdArg, secretArg) {
1348
+ return `${bindingIdArg}\0${credentialIdArg}\0${secretArg}`;
1349
+ }
1350
+ createCredential(bindingIdArg, nowArg) {
1351
+ const id = plugins.uuid.v4();
1352
+ const secret = plugins.crypto.randomBytes(32).toString('base64url');
1353
+ const hmac = this.crypto.hmac('credential', this.credentialHmacValue(bindingIdArg, id, secret));
1354
+ const stored = {
1355
+ id,
1356
+ status: 'active',
1357
+ hmacKeyId: hmac.keyId,
1358
+ secretHash: hmac.digest,
1359
+ createdAt: nowArg,
1360
+ updatedAt: nowArg,
1361
+ lastRotatedAt: null,
1362
+ validUntil: null,
1363
+ };
1364
+ return {
1365
+ stored,
1366
+ oneTime: {
1367
+ credential: toCredentialPublic(stored),
1368
+ secret,
1369
+ secretShownOnce: true,
1370
+ },
1371
+ };
1372
+ }
1373
+ credentialRotationRecoveryAad(bindingArg, identityArg) {
1374
+ return {
1375
+ gatewayClientId: bindingArg.ownerGatewayClientId,
1376
+ appInstanceId: bindingArg.ownerAppInstanceId,
1377
+ bindingId: bindingArg.id,
1378
+ documentType: 'credential-rotation-recovery',
1379
+ documentId: canonicalJson({
1380
+ lifecycleGeneration: identityArg.lifecycleGeneration,
1381
+ requestedCredentialId: identityArg.requestedCredentialId,
1382
+ resultingCredentialId: identityArg.resultingCredentialId,
1383
+ }),
1384
+ };
1385
+ }
1386
+ replayCredentialRotation(bindingArg, requestedCredentialIdArg, nowArg) {
1387
+ const recovery = bindingArg.credentialRotationRecovery;
1388
+ if (!recovery
1389
+ || recovery.expiresAt <= nowArg
1390
+ || (recovery.requestedCredentialId !== requestedCredentialIdArg
1391
+ && recovery.resultingCredentialId !== requestedCredentialIdArg)) {
1392
+ return undefined;
1393
+ }
1394
+ const lifecycleGeneration = requireLifecycleGeneration(bindingArg.lifecycleGeneration);
1395
+ if (!bindingArg.enabled
1396
+ || bindingArg.status !== 'active'
1397
+ || typeof bindingArg.deletedAt === 'number'
1398
+ || recovery.lifecycleGeneration !== lifecycleGeneration
1399
+ || recovery.resultingCredentialId !== bindingArg.credential.id
1400
+ || bindingArg.credential.status !== 'active'
1401
+ || typeof bindingArg.credential.secretHash !== 'string') {
1402
+ throw new Error('Web Push credential rotation recovery state is inconsistent');
1403
+ }
1404
+ let secret;
1405
+ try {
1406
+ secret = this.crypto.decryptJson(recovery.secretEnvelope, this.credentialRotationRecoveryAad(bindingArg, recovery)).secret;
1407
+ secret = requireNonEmptyString(secret, 'Web Push credential rotation recovery secret', 512);
1408
+ }
1409
+ catch (error) {
1410
+ throw new Error('Web Push credential rotation recovery is unreadable', {
1411
+ cause: error,
1412
+ });
1413
+ }
1414
+ if (!this.crypto.verifyHmac('credential', this.credentialHmacValue(bindingArg.id, bindingArg.credential.id, secret), bindingArg.credential.hmacKeyId, bindingArg.credential.secretHash)) {
1415
+ throw new Error('Web Push credential rotation recovery failed verification');
1416
+ }
1417
+ return {
1418
+ credential: toCredentialPublic(bindingArg.credential),
1419
+ secret,
1420
+ secretShownOnce: true,
1421
+ };
1422
+ }
1423
+ createVapidKey(ownerArg, bindingIdArg, nowArg) {
1424
+ const id = plugins.uuid.v4();
1425
+ const keyPair = plugins.webpush.generateVAPIDKeys();
1426
+ const aad = {
1427
+ gatewayClientId: ownerArg.gatewayClientId,
1428
+ appInstanceId: ownerArg.appInstanceId,
1429
+ bindingId: bindingIdArg,
1430
+ documentType: 'vapid-private-key',
1431
+ documentId: id,
1432
+ };
1433
+ return {
1434
+ id,
1435
+ publicKey: keyPair.publicKey,
1436
+ status: 'active',
1437
+ createdAt: nowArg,
1438
+ activatedAt: nowArg,
1439
+ retireAfter: null,
1440
+ retiredAt: null,
1441
+ privateKeyEnvelope: this.crypto.encryptJson({ privateKey: keyPair.privateKey }, aad),
1442
+ };
1443
+ }
1444
+ spoolAadBase(bindingArg, spoolIdArg) {
1445
+ return {
1446
+ gatewayClientId: bindingArg.ownerGatewayClientId,
1447
+ appInstanceId: bindingArg.ownerAppInstanceId,
1448
+ bindingId: bindingArg.id,
1449
+ documentId: spoolIdArg,
1450
+ };
1451
+ }
1452
+ async assertBindingLifecycleActive(bindingArg) {
1453
+ const lifecycleGeneration = requireLifecycleGeneration(bindingArg.lifecycleGeneration);
1454
+ const active = await WebPushBindingDoc.getNativeCollection().findOne({
1455
+ id: bindingArg.id,
1456
+ lifecycleGeneration,
1457
+ enabled: true,
1458
+ status: 'active',
1459
+ deletedAt: { $exists: false },
1460
+ }, { projection: { _id: 1 } });
1461
+ if (!active) {
1462
+ throw new plugins.typedrequest.TypedResponseError('Web Push binding lifecycle changed; retry with current credentials');
1463
+ }
1464
+ }
1465
+ async reserveAdmission(bindingArg) {
1466
+ const bindingId = requireOpaqueId(bindingArg.id, 'Web Push binding id');
1467
+ const lifecycleGeneration = requireLifecycleGeneration(bindingArg.lifecycleGeneration);
1468
+ await this.assertBindingLifecycleActive(bindingArg);
1469
+ const collection = WebPushAdmissionDoc.getNativeCollection();
1470
+ const policy = this.admissionPolicy;
1471
+ for (let attempt = 0; attempt < MAX_ADMISSION_CAS_ATTEMPTS; attempt++) {
1472
+ const now = this.now();
1473
+ const purgeAt = new Date(now + policy.longWindowMs * 2);
1474
+ const raw = await collection.findOne({
1475
+ bindingId,
1476
+ lifecycleGeneration,
1477
+ });
1478
+ if (!raw) {
1479
+ const admission = new WebPushAdmissionDoc();
1480
+ admission.bindingId = bindingId;
1481
+ admission.lifecycleGeneration = lifecycleGeneration;
1482
+ admission.shortWindowStartedAt = now;
1483
+ admission.shortWindowCount = 1;
1484
+ admission.longWindowStartedAt = now;
1485
+ admission.longWindowCount = 1;
1486
+ admission.revision = 1;
1487
+ admission.updatedAt = now;
1488
+ admission.purgeAt = purgeAt;
1489
+ try {
1490
+ await admission.save();
1491
+ return;
1492
+ }
1493
+ catch (error) {
1494
+ if (isDuplicateKeyError(error))
1495
+ continue;
1496
+ throw error;
1497
+ }
1498
+ }
1499
+ const admission = asAdmissionDoc(raw);
1500
+ const admissionGeneration = requireLifecycleGeneration(admission.lifecycleGeneration);
1501
+ if (admissionGeneration !== lifecycleGeneration) {
1502
+ throw new Error('Web Push admission lifecycle generation is inconsistent');
1503
+ }
1504
+ for (const [name, value] of Object.entries({
1505
+ shortWindowStartedAt: admission.shortWindowStartedAt,
1506
+ shortWindowCount: admission.shortWindowCount,
1507
+ longWindowStartedAt: admission.longWindowStartedAt,
1508
+ longWindowCount: admission.longWindowCount,
1509
+ revision: admission.revision,
1510
+ })) {
1511
+ if (!Number.isSafeInteger(value) || value < 0 || (name === 'revision' && value < 1)) {
1512
+ throw new Error(`Web Push admission document ${name} is malformed`);
1513
+ }
1514
+ }
1515
+ const shortWindowExpired = now - admission.shortWindowStartedAt >= policy.shortWindowMs;
1516
+ const longWindowExpired = now - admission.longWindowStartedAt >= policy.longWindowMs;
1517
+ const shortWindowStartedAt = shortWindowExpired
1518
+ ? now
1519
+ : admission.shortWindowStartedAt;
1520
+ const longWindowStartedAt = longWindowExpired
1521
+ ? now
1522
+ : admission.longWindowStartedAt;
1523
+ const shortWindowCount = shortWindowExpired ? 0 : admission.shortWindowCount;
1524
+ const longWindowCount = longWindowExpired ? 0 : admission.longWindowCount;
1525
+ if (shortWindowCount >= policy.shortLimit || longWindowCount >= policy.longLimit) {
1526
+ throw new plugins.typedrequest.TypedResponseError('Web Push request rate limit exceeded');
1527
+ }
1528
+ const updated = await collection.updateOne({
1529
+ bindingId,
1530
+ lifecycleGeneration,
1531
+ revision: admission.revision,
1532
+ }, {
1533
+ $set: {
1534
+ shortWindowStartedAt,
1535
+ shortWindowCount: shortWindowCount + 1,
1536
+ longWindowStartedAt,
1537
+ longWindowCount: longWindowCount + 1,
1538
+ revision: admission.revision + 1,
1539
+ updatedAt: now,
1540
+ purgeAt,
1541
+ _updatedAt: new Date(now).toISOString(),
1542
+ },
1543
+ });
1544
+ if (updated.matchedCount === 1)
1545
+ return;
1546
+ }
1547
+ throw new plugins.typedrequest.TypedResponseError('Web Push admission changed concurrently; retry request');
1548
+ }
1549
+ async cancelSpoolIfLifecycleChanged(spoolItemIdArg, bindingIdArg, lifecycleGenerationArg) {
1550
+ const lifecycleGeneration = requireLifecycleGeneration(lifecycleGenerationArg);
1551
+ const active = await WebPushBindingDoc.getNativeCollection().findOne({
1552
+ id: bindingIdArg,
1553
+ lifecycleGeneration,
1554
+ enabled: true,
1555
+ status: 'active',
1556
+ deletedAt: { $exists: false },
1557
+ }, { projection: { _id: 1 } });
1558
+ if (active)
1559
+ return;
1560
+ await this.cancelWithinBinding(bindingIdArg, {
1561
+ type: 'spoolItem',
1562
+ spoolItemId: spoolItemIdArg,
1563
+ }, false, lifecycleGeneration, 'BINDING_LIFECYCLE_CHANGED');
1564
+ await WebPushAdmissionDoc.getNativeCollection().deleteOne({
1565
+ bindingId: bindingIdArg,
1566
+ lifecycleGeneration,
1567
+ });
1568
+ }
1569
+ async scrubDeletedBindingLifecycle(bindingArg, waitForDrainArg = true) {
1570
+ const tombstoneGeneration = requireLifecycleGeneration(bindingArg.lifecycleGeneration);
1571
+ if (typeof bindingArg.deletedAt !== 'number')
1572
+ return;
1573
+ const cancellationErrorCode = bindingArg.controllerFence?.intent === 'disabled'
1574
+ ? 'BINDING_DISABLED'
1575
+ : 'BINDING_DELETED';
1576
+ await this.requestBindingLifecyclesBeforeCancellation(bindingArg.id, tombstoneGeneration, cancellationErrorCode);
1577
+ const collection = WebPushBindingDoc.getNativeCollection();
1578
+ let scrubbed = false;
1579
+ for (let attempt = 0; attempt < 4; attempt++) {
1580
+ const currentRaw = await collection.findOne({
1581
+ id: bindingArg.id,
1582
+ lifecycleGeneration: tombstoneGeneration,
1583
+ deletedAt: bindingArg.deletedAt,
1584
+ enabled: false,
1585
+ });
1586
+ if (!currentRaw)
1587
+ return;
1588
+ const current = asBindingDoc(currentRaw);
1589
+ const needsScrub = (typeof current.credential?.secretHash === 'string'
1590
+ || (current.previousCredentials || []).length > 0
1591
+ || current.credentialRotationRecovery !== undefined
1592
+ || (current.vapidKeys || []).some((keyArg) => (keyArg.privateKeyEnvelope !== undefined
1593
+ || keyArg.status !== 'retired'
1594
+ || keyArg.retireAfter !== null)));
1595
+ if (!needsScrub) {
1596
+ scrubbed = true;
1597
+ break;
1598
+ }
1599
+ const now = this.now();
1600
+ const credential = {
1601
+ ...current.credential,
1602
+ status: 'revoked',
1603
+ updatedAt: now,
1604
+ validUntil: null,
1605
+ };
1606
+ delete credential.secretHash;
1607
+ const vapidKeys = (current.vapidKeys || []).map((keyArg) => {
1608
+ const scrubbedKey = {
1609
+ ...keyArg,
1610
+ status: 'retired',
1611
+ retireAfter: null,
1612
+ retiredAt: keyArg.retiredAt ?? now,
1613
+ };
1614
+ delete scrubbedKey.privateKeyEnvelope;
1615
+ return scrubbedKey;
1616
+ });
1617
+ const result = await collection.updateOne({
1618
+ id: current.id,
1619
+ mutationRevision: current.mutationRevision,
1620
+ lifecycleGeneration: tombstoneGeneration,
1621
+ deletedAt: bindingArg.deletedAt,
1622
+ enabled: false,
1623
+ }, {
1624
+ $set: {
1625
+ credential,
1626
+ previousCredentials: [],
1627
+ vapidKeys,
1628
+ updatedAt: now,
1629
+ mutationRevision: current.mutationRevision + 1,
1630
+ _updatedAt: new Date(now).toISOString(),
1631
+ },
1632
+ $unset: {
1633
+ credentialRotationRecovery: '',
1634
+ },
1635
+ });
1636
+ if (result.matchedCount === 1) {
1637
+ scrubbed = true;
1638
+ break;
1639
+ }
1640
+ }
1641
+ if (!scrubbed) {
1642
+ throw new plugins.typedrequest.TypedResponseError('Web Push binding cleanup changed concurrently; retry deletion');
1643
+ }
1644
+ await WebPushAdmissionDoc.getNativeCollection().deleteMany({
1645
+ bindingId: bindingArg.id,
1646
+ lifecycleGeneration: { $lte: tombstoneGeneration },
1647
+ });
1648
+ await this.finishStaleCancelledSendingBefore(bindingArg.id, tombstoneGeneration, cancellationErrorCode);
1649
+ if (waitForDrainArg) {
1650
+ await this.waitForBindingLifecyclesBeforeDrain(bindingArg.id, tombstoneGeneration, cancellationErrorCode);
1651
+ }
1652
+ }
1653
+ async cleanupExpiredCredentialOverlaps(limitArg = MAINTENANCE_BATCH_SIZE) {
1654
+ const now = this.now();
1655
+ const collection = WebPushBindingDoc.getNativeCollection();
1656
+ const batch = await this.selectBindingMaintenanceBatch({ 'previousCredentials.validUntil': { $lte: now } }, this.expiredCredentialOverlapCursor, limitArg);
1657
+ this.expiredCredentialOverlapCursor = batch.nextCursor;
1658
+ for (const binding of batch.rows) {
1659
+ const remaining = (binding.previousCredentials || []).filter((credentialArg) => (typeof credentialArg.secretHash === 'string'
1660
+ && credentialArg.validUntil !== null
1661
+ && credentialArg.validUntil > now));
1662
+ if (remaining.length === (binding.previousCredentials || []).length)
1663
+ continue;
1664
+ await collection.updateOne({
1665
+ id: binding.id,
1666
+ mutationRevision: binding.mutationRevision,
1667
+ lifecycleGeneration: binding.lifecycleGeneration,
1668
+ }, {
1669
+ $set: {
1670
+ previousCredentials: remaining,
1671
+ updatedAt: now,
1672
+ mutationRevision: binding.mutationRevision + 1,
1673
+ _updatedAt: new Date(now).toISOString(),
1674
+ },
1675
+ });
1676
+ }
1677
+ }
1678
+ async cleanupExpiredCredentialRotationRecoveries(limitArg = MAINTENANCE_BATCH_SIZE) {
1679
+ const now = this.now();
1680
+ const collection = WebPushBindingDoc.getNativeCollection();
1681
+ const batch = await this.selectBindingMaintenanceBatch({ 'credentialRotationRecovery.expiresAt': { $lte: now } }, this.expiredCredentialRecoveryCursor, limitArg);
1682
+ this.expiredCredentialRecoveryCursor = batch.nextCursor;
1683
+ for (const binding of batch.rows) {
1684
+ const recovery = binding.credentialRotationRecovery;
1685
+ if (!recovery || recovery.expiresAt > now)
1686
+ continue;
1687
+ await collection.updateOne({
1688
+ id: binding.id,
1689
+ mutationRevision: binding.mutationRevision,
1690
+ lifecycleGeneration: binding.lifecycleGeneration,
1691
+ 'credentialRotationRecovery.requestedCredentialId': recovery.requestedCredentialId,
1692
+ 'credentialRotationRecovery.resultingCredentialId': recovery.resultingCredentialId,
1693
+ 'credentialRotationRecovery.expiresAt': recovery.expiresAt,
1694
+ }, {
1695
+ $set: {
1696
+ updatedAt: now,
1697
+ mutationRevision: binding.mutationRevision + 1,
1698
+ _updatedAt: new Date(now).toISOString(),
1699
+ },
1700
+ $unset: {
1701
+ credentialRotationRecovery: '',
1702
+ },
1703
+ });
1704
+ }
1705
+ }
1706
+ async cleanupRetiredVapidKeys(bindingIdArg, limitArg = MAINTENANCE_BATCH_SIZE) {
1707
+ const now = this.now();
1708
+ const bindingCollection = WebPushBindingDoc.getNativeCollection();
1709
+ const spoolCollection = WebPushSpoolDoc.getNativeCollection();
1710
+ const selector = bindingIdArg
1711
+ ? { id: requireOpaqueId(bindingIdArg, 'Web Push binding id') }
1712
+ : {
1713
+ $or: [
1714
+ { 'vapidKeys.status': 'retired' },
1715
+ { 'vapidKeys.retireAfter': { $lte: now } },
1716
+ ],
1717
+ };
1718
+ const rows = bindingIdArg
1719
+ ? (await bindingCollection
1720
+ .find(selector)
1721
+ .limit(1)
1722
+ .toArray())
1723
+ .map((rawArg) => asBindingDoc(rawArg))
1724
+ : await (async () => {
1725
+ const batch = await this.selectBindingMaintenanceBatch(selector, this.retiredVapidCursor, limitArg);
1726
+ this.retiredVapidCursor = batch.nextCursor;
1727
+ return batch.rows;
1728
+ })();
1729
+ for (const binding of rows) {
1730
+ const retained = [];
1731
+ for (const key of binding.vapidKeys || []) {
1732
+ if (key.status === 'active') {
1733
+ retained.push(key);
1734
+ continue;
1735
+ }
1736
+ if (key.status === 'retiring'
1737
+ && (key.retireAfter === null || key.retireAfter > now)) {
1738
+ retained.push(key);
1739
+ continue;
1740
+ }
1741
+ if (key.status === 'retired')
1742
+ continue;
1743
+ const pending = await spoolCollection.countDocuments({
1744
+ bindingId: binding.id,
1745
+ lifecycleGeneration: requireLifecycleGeneration(binding.lifecycleGeneration),
1746
+ vapidKeyId: key.id,
1747
+ state: { $in: NONTERMINAL_STATES },
1748
+ }, { limit: 1 });
1749
+ if (pending > 0) {
1750
+ retained.push(key);
1751
+ }
1752
+ }
1753
+ if (retained.length === binding.vapidKeys.length)
1754
+ continue;
1755
+ await bindingCollection.updateOne({
1756
+ id: binding.id,
1757
+ mutationRevision: binding.mutationRevision,
1758
+ lifecycleGeneration: binding.lifecycleGeneration,
1759
+ }, {
1760
+ $set: {
1761
+ vapidKeys: retained,
1762
+ updatedAt: now,
1763
+ mutationRevision: binding.mutationRevision + 1,
1764
+ _updatedAt: new Date(now).toISOString(),
1765
+ },
1766
+ });
1767
+ }
1768
+ }
1769
+ async runMaintenanceOnce() {
1770
+ await this.cleanupExpiredCredentialOverlaps();
1771
+ await this.cleanupExpiredCredentialRotationRecoveries();
1772
+ await this.cleanupRetiredVapidKeys();
1773
+ await this.finishStaleCancelledSending();
1774
+ await this.cleanupInactiveBindingLifecycles();
1775
+ }
1776
+ async cleanupInactiveBindingLifecycles(limitArg = Math.min(MAINTENANCE_BATCH_SIZE, 20)) {
1777
+ const batch = await this.selectBindingMaintenanceBatch({
1778
+ $or: [
1779
+ { deletedAt: { $type: 'number' } },
1780
+ { enabled: false },
1781
+ ],
1782
+ }, this.inactiveLifecycleCursor, limitArg);
1783
+ this.inactiveLifecycleCursor = batch.nextCursor;
1784
+ for (const binding of batch.rows) {
1785
+ try {
1786
+ const lifecycleGeneration = requireLifecycleGeneration(binding.lifecycleGeneration);
1787
+ if (typeof binding.deletedAt === 'number') {
1788
+ await this.scrubDeletedBindingLifecycle(binding, false);
1789
+ }
1790
+ else {
1791
+ await this.requestBindingLifecyclesBeforeCancellation(binding.id, lifecycleGeneration, 'BINDING_DISABLED');
1792
+ await WebPushAdmissionDoc.getNativeCollection().deleteMany({
1793
+ bindingId: binding.id,
1794
+ lifecycleGeneration: { $lt: lifecycleGeneration },
1795
+ });
1796
+ await this.finishStaleCancelledSendingBefore(binding.id, lifecycleGeneration, 'BINDING_DISABLED');
1797
+ }
1798
+ }
1799
+ catch (error) {
1800
+ logger.log('warn', `Web Push lifecycle maintenance will retry binding ${binding.id}: ${error.name}`);
1801
+ }
1802
+ }
1803
+ }
1804
+ async selectBindingMaintenanceBatch(selectorArg, cursorArg, limitArg) {
1805
+ const selector = cursorArg === undefined
1806
+ ? selectorArg
1807
+ : {
1808
+ $and: [
1809
+ selectorArg,
1810
+ { id: { $gt: cursorArg } },
1811
+ ],
1812
+ };
1813
+ const rows = (await WebPushBindingDoc.getNativeCollection()
1814
+ .find(selector)
1815
+ .sort({ id: 1 })
1816
+ .limit(Math.min(Math.max(Math.floor(limitArg), 1), MAINTENANCE_BATCH_SIZE))
1817
+ .toArray())
1818
+ .map((rawArg) => asBindingDoc(rawArg));
1819
+ return {
1820
+ rows,
1821
+ ...(rows.length > 0 ? { nextCursor: rows[rows.length - 1].id } : {}),
1822
+ };
1823
+ }
1824
+ async requestBindingLifecyclesBeforeCancellation(bindingIdArg, beforeLifecycleGenerationArg, errorCodeArg) {
1825
+ const beforeLifecycleGeneration = requireLifecycleGeneration(beforeLifecycleGenerationArg);
1826
+ await this.cancelWithinBinding(bindingIdArg, {
1827
+ type: 'subscription',
1828
+ subscriptionId: '*',
1829
+ }, true, { $lt: beforeLifecycleGeneration }, errorCodeArg);
1830
+ }
1831
+ async drainBindingLifecyclesBefore(bindingIdArg, beforeLifecycleGenerationArg, errorCodeArg) {
1832
+ const beforeLifecycleGeneration = requireLifecycleGeneration(beforeLifecycleGenerationArg);
1833
+ await this.requestBindingLifecyclesBeforeCancellation(bindingIdArg, beforeLifecycleGeneration, errorCodeArg);
1834
+ await WebPushAdmissionDoc.getNativeCollection().deleteMany({
1835
+ bindingId: bindingIdArg,
1836
+ lifecycleGeneration: { $lt: beforeLifecycleGeneration },
1837
+ });
1838
+ await this.waitForBindingLifecyclesBeforeDrain(bindingIdArg, beforeLifecycleGeneration, errorCodeArg);
1839
+ }
1840
+ async waitForBindingLifecyclesBeforeDrain(bindingIdArg, beforeLifecycleGenerationArg, errorCodeArg) {
1841
+ const bindingId = requireOpaqueId(bindingIdArg, 'Web Push binding id');
1842
+ const beforeLifecycleGeneration = requireLifecycleGeneration(beforeLifecycleGenerationArg);
1843
+ const deadline = Date.now() + LIFECYCLE_DRAIN_TIMEOUT_MS;
1844
+ const collection = WebPushSpoolDoc.getNativeCollection();
1845
+ while (true) {
1846
+ await this.requestBindingLifecyclesBeforeCancellation(bindingId, beforeLifecycleGeneration, errorCodeArg);
1847
+ while (await this.finishStaleCancelledSendingBefore(bindingId, beforeLifecycleGeneration, errorCodeArg) > 0) {
1848
+ // Drain every bounded stale-lease batch before checking completion.
1849
+ }
1850
+ const remaining = await collection.countDocuments({
1851
+ bindingId,
1852
+ lifecycleGeneration: { $lt: beforeLifecycleGeneration },
1853
+ state: { $in: NONTERMINAL_STATES },
1854
+ }, { limit: 1 });
1855
+ if (remaining === 0)
1856
+ return;
1857
+ if (Date.now() >= deadline) {
1858
+ throw new plugins.typedrequest.TypedResponseError('Web Push binding cleanup is still draining in-flight delivery; retry');
1859
+ }
1860
+ await new Promise((resolveArg) => {
1861
+ setTimeout(resolveArg, LIFECYCLE_DRAIN_POLL_MS);
1862
+ });
1863
+ }
1864
+ }
1865
+ async finishStaleCancelledSending(limitArg = MAINTENANCE_BATCH_SIZE) {
1866
+ const now = this.now();
1867
+ const collection = WebPushSpoolDoc.getNativeCollection();
1868
+ const rows = await collection.find({
1869
+ state: 'sending',
1870
+ cancelRequestedAt: { $exists: true },
1871
+ $or: [
1872
+ { leaseToken: { $exists: false } },
1873
+ { leaseExpiresAt: { $exists: false } },
1874
+ { leaseExpiresAt: { $lte: now } },
1875
+ ],
1876
+ }, {
1877
+ projection: {
1878
+ id: 1,
1879
+ leaseToken: 1,
1880
+ leaseExpiresAt: 1,
1881
+ cancelRequestedAt: 1,
1882
+ },
1883
+ })
1884
+ .sort({ cancelRequestedAt: 1, id: 1 })
1885
+ .limit(Math.min(Math.max(Math.floor(limitArg), 1), MAINTENANCE_BATCH_SIZE))
1886
+ .toArray();
1887
+ let finished = 0;
1888
+ for (const raw of rows) {
1889
+ const spool = asSpoolDoc(raw);
1890
+ const result = await collection.updateOne({
1891
+ id: spool.id,
1892
+ state: 'sending',
1893
+ cancelRequestedAt: spool.cancelRequestedAt,
1894
+ ...(spool.leaseToken === undefined
1895
+ ? { leaseToken: { $exists: false } }
1896
+ : { leaseToken: spool.leaseToken }),
1897
+ ...(spool.leaseExpiresAt === undefined
1898
+ ? { leaseExpiresAt: { $exists: false } }
1899
+ : { leaseExpiresAt: spool.leaseExpiresAt }),
1900
+ }, buildWebPushTerminalUpdate({
1901
+ state: 'failed',
1902
+ now,
1903
+ errorCode: 'DELIVERY_OUTCOME_UNKNOWN_AFTER_CANCELLATION',
1904
+ }));
1905
+ finished += result.modifiedCount;
1906
+ }
1907
+ return finished;
1908
+ }
1909
+ async finishStaleCancelledSendingBefore(bindingIdArg, beforeLifecycleGenerationArg, _fallbackErrorCodeArg) {
1910
+ const bindingId = requireOpaqueId(bindingIdArg, 'Web Push binding id');
1911
+ const beforeLifecycleGeneration = requireLifecycleGeneration(beforeLifecycleGenerationArg);
1912
+ const now = this.now();
1913
+ const collection = WebPushSpoolDoc.getNativeCollection();
1914
+ const rows = await collection.find({
1915
+ bindingId,
1916
+ lifecycleGeneration: { $lt: beforeLifecycleGeneration },
1917
+ state: 'sending',
1918
+ cancelRequestedAt: { $exists: true },
1919
+ $or: [
1920
+ { leaseToken: { $exists: false } },
1921
+ { leaseExpiresAt: { $exists: false } },
1922
+ { leaseExpiresAt: { $lte: now } },
1923
+ ],
1924
+ }, {
1925
+ projection: {
1926
+ id: 1,
1927
+ leaseToken: 1,
1928
+ leaseExpiresAt: 1,
1929
+ cancelRequestedAt: 1,
1930
+ cancelErrorCode: 1,
1931
+ },
1932
+ }).limit(MAINTENANCE_BATCH_SIZE).toArray();
1933
+ let finished = 0;
1934
+ for (const raw of rows) {
1935
+ const spool = asSpoolDoc(raw);
1936
+ const result = await collection.updateOne({
1937
+ id: spool.id,
1938
+ bindingId,
1939
+ state: 'sending',
1940
+ cancelRequestedAt: spool.cancelRequestedAt,
1941
+ ...(spool.leaseToken === undefined
1942
+ ? { leaseToken: { $exists: false } }
1943
+ : { leaseToken: spool.leaseToken }),
1944
+ ...(spool.leaseExpiresAt === undefined
1945
+ ? { leaseExpiresAt: { $exists: false } }
1946
+ : { leaseExpiresAt: spool.leaseExpiresAt }),
1947
+ }, buildWebPushTerminalUpdate({
1948
+ state: 'failed',
1949
+ now,
1950
+ errorCode: 'DELIVERY_OUTCOME_UNKNOWN_AFTER_CANCELLATION',
1951
+ }));
1952
+ finished += result.modifiedCount;
1953
+ }
1954
+ return finished;
1955
+ }
1956
+ async cancelWithinBinding(bindingIdArg, targetArg, allSubscriptionsArg = false, lifecycleGenerationArg, errorCodeArg = 'CANCELLED_BY_APPLICATION') {
1957
+ const bindingId = requireOpaqueId(bindingIdArg, 'Web Push binding id');
1958
+ const targetSelector = {};
1959
+ if (targetArg.type === 'spoolItem') {
1960
+ targetSelector.id = requireOpaqueId(targetArg.spoolItemId, 'Web Push spoolItemId');
1961
+ }
1962
+ else if (allSubscriptionsArg) {
1963
+ targetSelector.subscriptionId = { $type: 'string' };
1964
+ }
1965
+ else {
1966
+ targetSelector.subscriptionId = requireOpaqueId(targetArg.subscriptionId, 'Web Push subscriptionId');
1967
+ }
1968
+ const collection = WebPushSpoolDoc.getNativeCollection();
1969
+ const lifecycleGenerationSelector = typeof lifecycleGenerationArg === 'number'
1970
+ ? requireLifecycleGeneration(lifecycleGenerationArg)
1971
+ : lifecycleGenerationArg === undefined
1972
+ ? undefined
1973
+ : { $lt: requireLifecycleGeneration(lifecycleGenerationArg.$lt) };
1974
+ const selector = {
1975
+ bindingId,
1976
+ ...(lifecycleGenerationSelector === undefined
1977
+ ? {}
1978
+ : { lifecycleGeneration: lifecycleGenerationSelector }),
1979
+ ...targetSelector,
1980
+ };
1981
+ const alreadyTerminalCount = await collection.countDocuments({
1982
+ ...selector,
1983
+ state: { $in: TERMINAL_STATES },
1984
+ });
1985
+ let cancelledCount = 0;
1986
+ for (let attempt = 0; attempt < 16; attempt++) {
1987
+ const now = this.now();
1988
+ const terminalized = await collection.updateMany({
1989
+ ...selector,
1990
+ state: { $in: ['accepted', 'queued', 'deferred'] },
1991
+ }, buildWebPushTerminalUpdate({
1992
+ state: 'cancelled',
1993
+ now,
1994
+ errorCode: errorCodeArg,
1995
+ }));
1996
+ const markedSending = await collection.updateMany({
1997
+ ...selector,
1998
+ state: 'sending',
1999
+ cancelRequestedAt: { $exists: false },
2000
+ }, {
2001
+ $set: {
2002
+ cancelRequestedAt: now,
2003
+ cancelErrorCode: errorCodeArg,
2004
+ updatedAt: now,
2005
+ _updatedAt: new Date(now).toISOString(),
2006
+ },
2007
+ });
2008
+ const modified = terminalized.modifiedCount + markedSending.modifiedCount;
2009
+ cancelledCount += modified;
2010
+ if (modified === 0)
2011
+ break;
2012
+ }
2013
+ return {
2014
+ cancelledCount,
2015
+ alreadyTerminalCount,
2016
+ };
2017
+ }
2018
+ async expireDueItems(limitArg) {
2019
+ const now = this.now();
2020
+ const collection = WebPushSpoolDoc.getNativeCollection();
2021
+ const rows = await collection
2022
+ .find({
2023
+ state: { $in: NONTERMINAL_STATES },
2024
+ expiresAt: { $lte: now },
2025
+ }, {
2026
+ projection: { id: 1, state: 1, leaseToken: 1, leaseExpiresAt: 1 },
2027
+ })
2028
+ .limit(limitArg)
2029
+ .toArray();
2030
+ for (const raw of rows) {
2031
+ const spool = asSpoolDoc(raw);
2032
+ if (spool.state === 'sending'
2033
+ && typeof spool.leaseExpiresAt === 'number'
2034
+ && spool.leaseExpiresAt > now) {
2035
+ continue;
2036
+ }
2037
+ const leaseSelector = spool.state === 'sending'
2038
+ ? {
2039
+ ...(spool.leaseToken === undefined
2040
+ ? { leaseToken: { $exists: false } }
2041
+ : { leaseToken: spool.leaseToken }),
2042
+ ...(spool.leaseExpiresAt === undefined
2043
+ ? { leaseExpiresAt: { $exists: false } }
2044
+ : { leaseExpiresAt: spool.leaseExpiresAt }),
2045
+ }
2046
+ : {};
2047
+ await collection.updateOne({
2048
+ id: spool.id,
2049
+ state: spool.state,
2050
+ ...leaseSelector,
2051
+ }, buildWebPushTerminalUpdate({
2052
+ state: 'expired',
2053
+ now,
2054
+ errorCode: 'DELIVERY_TTL_EXPIRED',
2055
+ }));
2056
+ }
2057
+ }
2058
+ async claimNextItem() {
2059
+ const now = this.now();
2060
+ const leaseToken = plugins.uuid.v4();
2061
+ const row = await WebPushSpoolDoc.getNativeCollection().findOneAndUpdate({
2062
+ expiresAt: { $gt: now },
2063
+ $or: [
2064
+ {
2065
+ state: { $in: ['accepted', 'queued', 'deferred'] },
2066
+ nextAttemptAt: { $lte: now },
2067
+ cancelRequestedAt: { $exists: false },
2068
+ $or: [
2069
+ { leaseToken: { $exists: false } },
2070
+ { leaseExpiresAt: { $lte: now } },
2071
+ ],
2072
+ },
2073
+ {
2074
+ state: 'sending',
2075
+ leaseExpiresAt: { $lte: now },
2076
+ cancelRequestedAt: { $exists: false },
2077
+ },
2078
+ ],
2079
+ }, {
2080
+ $set: {
2081
+ state: 'sending',
2082
+ leaseToken,
2083
+ leaseExpiresAt: now + DELIVERY_LEASE_MS,
2084
+ updatedAt: now,
2085
+ _updatedAt: new Date(now).toISOString(),
2086
+ },
2087
+ $inc: { attempts: 1 },
2088
+ }, {
2089
+ sort: { nextAttemptAt: 1, acceptedAt: 1, id: 1 },
2090
+ returnDocument: 'after',
2091
+ });
2092
+ return row ? asSpoolDoc(row) : null;
2093
+ }
2094
+ async processClaimedItem(spoolArg) {
2095
+ const collection = WebPushSpoolDoc.getNativeCollection();
2096
+ const leaseToken = spoolArg.leaseToken;
2097
+ if (!leaseToken)
2098
+ return;
2099
+ const now = this.now();
2100
+ const current = await collection.findOne({
2101
+ id: spoolArg.id,
2102
+ state: 'sending',
2103
+ leaseToken,
2104
+ });
2105
+ if (!current)
2106
+ return;
2107
+ const currentSpool = asSpoolDoc(current);
2108
+ if (currentSpool.cancelRequestedAt !== undefined) {
2109
+ await this.finishTerminal(currentSpool, 'cancelled', {
2110
+ errorCode: currentSpool.cancelErrorCode || 'CANCELLED_BY_APPLICATION',
2111
+ });
2112
+ return;
2113
+ }
2114
+ if (currentSpool.expiresAt <= now) {
2115
+ await this.finishTerminal(currentSpool, 'expired', {
2116
+ errorCode: 'DELIVERY_TTL_EXPIRED',
2117
+ });
2118
+ return;
2119
+ }
2120
+ let lifecycleGeneration;
2121
+ try {
2122
+ lifecycleGeneration = requireLifecycleGeneration(currentSpool.lifecycleGeneration);
2123
+ }
2124
+ catch {
2125
+ await this.finishTerminal(currentSpool, 'failed', {
2126
+ errorCode: 'DELIVERY_CONFIGURATION_UNAVAILABLE',
2127
+ });
2128
+ return;
2129
+ }
2130
+ const bindingRaw = await WebPushBindingDoc.getNativeCollection().findOne({
2131
+ id: currentSpool.bindingId,
2132
+ lifecycleGeneration,
2133
+ enabled: true,
2134
+ status: 'active',
2135
+ deletedAt: { $exists: false },
2136
+ });
2137
+ if (!bindingRaw) {
2138
+ await this.finishTerminal(currentSpool, 'cancelled', {
2139
+ errorCode: 'BINDING_LIFECYCLE_CHANGED',
2140
+ });
2141
+ return;
2142
+ }
2143
+ const binding = asBindingDoc(bindingRaw);
2144
+ const vapidKey = binding.vapidKeys.find((keyArg) => (keyArg.id === currentSpool.vapidKeyId
2145
+ && Boolean(keyArg.privateKeyEnvelope)
2146
+ && (keyArg.status === 'active' || keyArg.status === 'retiring')));
2147
+ if (!vapidKey
2148
+ || !vapidKey.privateKeyEnvelope
2149
+ || !currentSpool.subscriptionEnvelope
2150
+ || !currentSpool.payloadEnvelope) {
2151
+ await this.finishTerminal(currentSpool, 'failed', {
2152
+ errorCode: 'DELIVERY_CONFIGURATION_UNAVAILABLE',
2153
+ });
2154
+ return;
2155
+ }
2156
+ const aadBase = this.spoolAadBase(binding, currentSpool.id);
2157
+ let subscription;
2158
+ let payload;
2159
+ let privateKey;
2160
+ try {
2161
+ subscription = this.crypto.decryptJson(currentSpool.subscriptionEnvelope, { ...aadBase, documentType: 'spool-subscription' });
2162
+ payload = this.crypto.decryptJson(currentSpool.payloadEnvelope, { ...aadBase, documentType: 'spool-payload' });
2163
+ privateKey = this.crypto.decryptJson(vapidKey.privateKeyEnvelope, {
2164
+ gatewayClientId: binding.ownerGatewayClientId,
2165
+ appInstanceId: binding.ownerAppInstanceId,
2166
+ bindingId: binding.id,
2167
+ documentType: 'vapid-private-key',
2168
+ documentId: vapidKey.id,
2169
+ }).privateKey;
2170
+ subscription = normalizeSubscription(subscription);
2171
+ payload = normalizePayload(payload);
2172
+ requireBase64Url(privateKey, 'Web Push VAPID private key', 32);
2173
+ }
2174
+ catch {
2175
+ await this.finishTerminal(currentSpool, 'failed', {
2176
+ errorCode: 'ENCRYPTED_DELIVERY_DATA_INVALID',
2177
+ });
2178
+ return;
2179
+ }
2180
+ const immediatelyBeforeSend = await collection.findOne({
2181
+ id: currentSpool.id,
2182
+ state: 'sending',
2183
+ leaseToken,
2184
+ });
2185
+ if (!immediatelyBeforeSend)
2186
+ return;
2187
+ const immediatelyBeforeSendSpool = asSpoolDoc(immediatelyBeforeSend);
2188
+ if (immediatelyBeforeSendSpool.cancelRequestedAt !== undefined) {
2189
+ await this.finishTerminal(immediatelyBeforeSendSpool, 'cancelled', {
2190
+ errorCode: immediatelyBeforeSendSpool.cancelErrorCode || 'CANCELLED_BY_APPLICATION',
2191
+ });
2192
+ return;
2193
+ }
2194
+ const bindingImmediatelyBeforeSend = await WebPushBindingDoc.getNativeCollection().findOne({
2195
+ id: currentSpool.bindingId,
2196
+ lifecycleGeneration,
2197
+ enabled: true,
2198
+ status: 'active',
2199
+ deletedAt: { $exists: false },
2200
+ }, { projection: { _id: 1 } });
2201
+ if (!bindingImmediatelyBeforeSend) {
2202
+ await this.finishTerminal(currentSpool, 'cancelled', {
2203
+ errorCode: 'BINDING_LIFECYCLE_CHANGED',
2204
+ });
2205
+ return;
2206
+ }
2207
+ const sendStartedAt = this.now();
2208
+ if (currentSpool.expiresAt <= sendStartedAt) {
2209
+ await this.finishTerminal(currentSpool, 'expired', {
2210
+ errorCode: 'DELIVERY_TTL_EXPIRED',
2211
+ });
2212
+ return;
2213
+ }
2214
+ const remainingTtlSeconds = Math.max(0, Math.floor((currentSpool.expiresAt - sendStartedAt) / 1000));
2215
+ try {
2216
+ const response = await this.transport.send({
2217
+ subscription,
2218
+ payload: canonicalJson(payload),
2219
+ ttlSeconds: remainingTtlSeconds,
2220
+ urgency: currentSpool.urgency,
2221
+ ...(currentSpool.topic ? { topic: currentSpool.topic } : {}),
2222
+ vapid: {
2223
+ subject: this.vapidSubject,
2224
+ publicKey: vapidKey.publicKey,
2225
+ privateKey,
2226
+ },
2227
+ });
2228
+ if (response.statusCode >= 200 && response.statusCode <= 299) {
2229
+ await this.finishTerminal(currentSpool, 'pushServiceAccepted', {
2230
+ pushServiceStatusCode: response.statusCode,
2231
+ });
2232
+ return;
2233
+ }
2234
+ if (response.statusCode === 404 || response.statusCode === 410) {
2235
+ await this.finishTerminal(currentSpool, 'invalidSubscription', {
2236
+ pushServiceStatusCode: response.statusCode,
2237
+ errorCode: 'PUSH_SUBSCRIPTION_INVALID',
2238
+ });
2239
+ return;
2240
+ }
2241
+ if (response.statusCode === 429) {
2242
+ await this.deferOrFinish(currentSpool, {
2243
+ pushServiceStatusCode: response.statusCode,
2244
+ errorCode: 'PUSH_SERVICE_RATE_LIMITED',
2245
+ retryAfter: response.retryAfter,
2246
+ });
2247
+ return;
2248
+ }
2249
+ if (response.statusCode >= 500 && response.statusCode <= 599) {
2250
+ await this.deferOrFinish(currentSpool, {
2251
+ pushServiceStatusCode: response.statusCode,
2252
+ errorCode: 'PUSH_SERVICE_UNAVAILABLE',
2253
+ });
2254
+ return;
2255
+ }
2256
+ await this.finishTerminal(currentSpool, 'failed', {
2257
+ pushServiceStatusCode: response.statusCode,
2258
+ errorCode: 'PUSH_SERVICE_REJECTED',
2259
+ });
2260
+ }
2261
+ catch (error) {
2262
+ if (error instanceof WebPushEndpointPolicyError) {
2263
+ await this.finishTerminal(currentSpool, 'invalidSubscription', {
2264
+ errorCode: error.code,
2265
+ });
2266
+ return;
2267
+ }
2268
+ if (error instanceof WebPushTransportError) {
2269
+ await this.deferOrFinish(currentSpool, {
2270
+ errorCode: error.code,
2271
+ });
2272
+ return;
2273
+ }
2274
+ await this.finishTerminal(currentSpool, 'failed', {
2275
+ errorCode: 'VAPID_OR_PAYLOAD_CONFIGURATION_ERROR',
2276
+ });
2277
+ }
2278
+ }
2279
+ async finishTerminal(spoolArg, stateArg, metadataArg = {}) {
2280
+ if (!spoolArg.leaseToken)
2281
+ return;
2282
+ const now = this.now();
2283
+ await WebPushSpoolDoc.getNativeCollection().updateOne({
2284
+ id: spoolArg.id,
2285
+ state: 'sending',
2286
+ leaseToken: spoolArg.leaseToken,
2287
+ }, buildWebPushTerminalUpdate({
2288
+ state: stateArg,
2289
+ now,
2290
+ ...metadataArg,
2291
+ }));
2292
+ }
2293
+ async deferOrFinish(spoolArg, metadataArg) {
2294
+ if (!spoolArg.leaseToken)
2295
+ return;
2296
+ const collection = WebPushSpoolDoc.getNativeCollection();
2297
+ const currentRaw = await collection.findOne({
2298
+ id: spoolArg.id,
2299
+ state: 'sending',
2300
+ leaseToken: spoolArg.leaseToken,
2301
+ });
2302
+ if (!currentRaw)
2303
+ return;
2304
+ const current = asSpoolDoc(currentRaw);
2305
+ if (current.cancelRequestedAt !== undefined) {
2306
+ await this.finishTerminal(current, 'cancelled', {
2307
+ errorCode: current.cancelErrorCode || 'CANCELLED_BY_APPLICATION',
2308
+ });
2309
+ return;
2310
+ }
2311
+ const now = this.now();
2312
+ const retryDelay = this.retryDelayMs(current.attempts, metadataArg.retryAfter, now);
2313
+ const nextAttemptAt = now + retryDelay;
2314
+ if (current.attempts >= DELIVERY_MAX_ATTEMPTS || nextAttemptAt >= current.expiresAt) {
2315
+ await this.finishTerminal(current, nextAttemptAt >= current.expiresAt ? 'expired' : 'failed', {
2316
+ pushServiceStatusCode: metadataArg.pushServiceStatusCode,
2317
+ errorCode: nextAttemptAt >= current.expiresAt
2318
+ ? 'DELIVERY_TTL_EXPIRED'
2319
+ : 'DELIVERY_ATTEMPTS_EXHAUSTED',
2320
+ });
2321
+ return;
2322
+ }
2323
+ await collection.updateOne({
2324
+ id: current.id,
2325
+ state: 'sending',
2326
+ leaseToken: current.leaseToken,
2327
+ cancelRequestedAt: { $exists: false },
2328
+ }, {
2329
+ $set: {
2330
+ state: 'deferred',
2331
+ nextAttemptAt,
2332
+ updatedAt: now,
2333
+ pushServiceStatusCode: metadataArg.pushServiceStatusCode ?? null,
2334
+ errorCode: metadataArg.errorCode,
2335
+ _updatedAt: new Date(now).toISOString(),
2336
+ },
2337
+ $unset: {
2338
+ leaseToken: '',
2339
+ leaseExpiresAt: '',
2340
+ },
2341
+ });
2342
+ }
2343
+ retryDelayMs(attemptsArg, retryAfterArg, nowArg) {
2344
+ if (retryAfterArg) {
2345
+ const seconds = Number.parseInt(retryAfterArg, 10);
2346
+ if (Number.isSafeInteger(seconds) && seconds >= 0) {
2347
+ return Math.min(Math.max(seconds * 1000, 1000), 60 * 60 * 1000);
2348
+ }
2349
+ const date = Date.parse(retryAfterArg);
2350
+ if (Number.isFinite(date) && date > nowArg) {
2351
+ return Math.min(Math.max(date - nowArg, 1000), 60 * 60 * 1000);
2352
+ }
2353
+ }
2354
+ return Math.min(30_000 * 2 ** Math.max(0, attemptsArg - 1), 60 * 60 * 1000);
2355
+ }
2356
+ scheduleWorker(delayArg) {
2357
+ if (!this.ready || !this.startWorker)
2358
+ return;
2359
+ this.workerTimer = setTimeout(() => {
2360
+ this.workerTimer = undefined;
2361
+ this.activeWorkerCycle = this.processDueDeliveriesOnce()
2362
+ .then(() => undefined)
2363
+ .catch((error) => {
2364
+ logger.log('error', `Web Push delivery cycle failed: ${error.name}`);
2365
+ })
2366
+ .finally(() => {
2367
+ this.activeWorkerCycle = undefined;
2368
+ this.scheduleWorker(DELIVERY_WORKER_INTERVAL_MS);
2369
+ });
2370
+ }, delayArg);
2371
+ this.workerTimer.unref();
2372
+ }
2373
+ }
2374
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy53ZWJwdXNoLW1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy93ZWJwdXNoL2NsYXNzZXMud2VicHVzaC1tYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDdEMsT0FBTyxFQUNMLFVBQVUsRUFDVixtQkFBbUIsRUFDbkIsaUJBQWlCLEVBQ2pCLGVBQWUsR0FNaEIsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QixPQUFPLEVBQ0wsYUFBYSxFQUNiLGFBQWEsRUFDYixtQkFBbUIsR0FFcEIsTUFBTSw2QkFBNkIsQ0FBQztBQUNyQyxPQUFPLEVBQ0wsb0JBQW9CLEVBQ3BCLHFCQUFxQixHQUV0QixNQUFNLGdDQUFnQyxDQUFDO0FBQ3hDLE9BQU8sRUFBRSwwQkFBMEIsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQzNFLE9BQU8sRUFDTCw2QkFBNkIsR0FHOUIsTUFBTSxzQkFBc0IsQ0FBQztBQStFOUIsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLENBQUM7QUFDL0IsTUFBTSxlQUFlLEdBQUcsTUFBTSxDQUFDO0FBQy9CLE1BQU0sbUJBQW1CLEdBQUcsTUFBTSxDQUFDO0FBQ25DLE1BQU0sYUFBYSxHQUFHLEdBQUcsQ0FBQztBQUMxQixNQUFNLDBCQUEwQixHQUFHLEdBQUcsQ0FBQztBQUN2QyxNQUFNLHVCQUF1QixHQUFHLEdBQUcsQ0FBQztBQUNwQyxNQUFNLGdCQUFnQixHQUFHLElBQUksQ0FBQztBQUM5QixNQUFNLG1CQUFtQixHQUFHLEdBQUcsQ0FBQztBQUNoQyxNQUFNLGlDQUFpQyxHQUFHLE1BQU0sQ0FBQztBQUNqRCxNQUFNLHdCQUF3QixHQUE0QjtJQUN4RCxhQUFhLEVBQUUsTUFBTTtJQUNyQixVQUFVLEVBQUUsR0FBRztJQUNmLFlBQVksRUFBRSxFQUFF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