@tencentcloud/web-push 1.0.2 → 1.0.3

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 (46) hide show
  1. package/README.md +102 -175
  2. package/dist/index.d.ts +259 -0
  3. package/{index.esm.js → dist/index.esm.js} +1118 -158
  4. package/dist/index.umd.js +1 -0
  5. package/dist/src/components/message-popup.d.ts +63 -0
  6. package/{src → dist/src}/core/web-push-sdk.d.ts +23 -1
  7. package/{src → dist/src}/index.d.ts +1 -0
  8. package/{src → dist/src}/types/inner.d.ts +2 -10
  9. package/dist/src/types/outer.d.ts +120 -0
  10. package/{src → dist/src}/utils/logger.d.ts +6 -0
  11. package/{src → dist/src}/utils/validator.d.ts +0 -13
  12. package/dist/sw.js +1 -0
  13. package/package.json +47 -9
  14. package/src/__tests__/index.test.ts +120 -0
  15. package/src/__tests__/integration.test.ts +285 -0
  16. package/src/__tests__/setup.ts +210 -0
  17. package/src/__tests__/types.test.ts +303 -0
  18. package/src/__tests__/web-push-sdk.test.ts +257 -0
  19. package/src/components/message-popup.ts +1007 -0
  20. package/src/core/event-emitter.ts +61 -0
  21. package/src/core/service-worker-manager.ts +614 -0
  22. package/src/core/web-push-sdk.ts +690 -0
  23. package/src/debug/GenerateTestUserSig.js +37 -0
  24. package/src/debug/index.d.ts +6 -0
  25. package/src/debug/index.js +1 -0
  26. package/src/debug/lib-generate-test-usersig-es.min.js +2 -0
  27. package/src/index.ts +9 -0
  28. package/src/service-worker/sw.ts +494 -0
  29. package/src/types/index.ts +2 -0
  30. package/src/types/inner.ts +44 -0
  31. package/src/types/outer.ts +142 -0
  32. package/src/utils/browser-support.ts +412 -0
  33. package/src/utils/logger.ts +66 -0
  34. package/src/utils/storage.ts +51 -0
  35. package/src/utils/validator.ts +267 -0
  36. package/CHANGELOG.md +0 -55
  37. package/index.d.ts +0 -110
  38. package/index.umd.js +0 -1
  39. package/src/types/outer.d.ts +0 -66
  40. package/sw.js +0 -1
  41. /package/{src → dist/src}/core/event-emitter.d.ts +0 -0
  42. /package/{src → dist/src}/core/service-worker-manager.d.ts +0 -0
  43. /package/{src → dist/src}/service-worker/sw.d.ts +0 -0
  44. /package/{src → dist/src}/types/index.d.ts +0 -0
  45. /package/{src → dist/src}/utils/browser-support.d.ts +0 -0
  46. /package/{src → dist/src}/utils/storage.d.ts +0 -0
@@ -0,0 +1,494 @@
1
+ declare const self: ServiceWorkerGlobalScope;
2
+
3
+ type LogLevel = 0 | 1 | 2 | 3 | 4;
4
+
5
+ interface NotificationMessage {
6
+ messageID: string;
7
+ title: string;
8
+ body: string;
9
+ icon?: string;
10
+ tag?: string;
11
+ data?: any;
12
+ timestamp: number;
13
+ }
14
+
15
+ interface ServiceWorkerMessage {
16
+ type: 'MESSAGE_RECEIVED' | 'NOTIFICATION_CLICKED' | 'MESSAGE_REVOKED';
17
+ data: any;
18
+ }
19
+
20
+ interface WebPushMessageData {
21
+ id: string;
22
+ title: string;
23
+ desc?: string;
24
+ url?: string;
25
+ tag?: string;
26
+ icon?: string;
27
+ image?: string;
28
+ rptExt: string;
29
+ rptURL: string;
30
+ }
31
+
32
+ interface WebPushEvent {
33
+ id: string;
34
+ EventType: number;
35
+ EventTime: number;
36
+ rptExt: string;
37
+ }
38
+
39
+ interface ReportData {
40
+ webpushEvents: WebPushEvent[];
41
+ }
42
+
43
+ interface ReportOptions {
44
+ id: string;
45
+ rptURL: string;
46
+ rptExt: string;
47
+ eventType?: number;
48
+ }
49
+
50
+ // 日志级别控制
51
+ let currentLogLevel: LogLevel = 1; // 默认为 release 级别
52
+
53
+ function shouldLog(messageLevel: number): boolean {
54
+ // 4 = 无日志级别,不输出任何日志
55
+ if (currentLogLevel === 4) return false;
56
+
57
+ // 数字越大,级别越高,输出的日志越少
58
+ // messageLevel: 0=debug, 1=info, 2=warn, 3=error
59
+ return messageLevel >= currentLogLevel;
60
+ }
61
+
62
+ function swLog(message: string, ...args: any[]): void {
63
+ if (shouldLog(1)) { // info 级别
64
+ console.log(`[WebPush SW] ${message}`, ...args);
65
+ }
66
+ }
67
+
68
+ function swWarn(message: string, ...args: any[]): void {
69
+ if (shouldLog(2)) { // warn 级别
70
+ console.warn(`[WebPush SW] ${message}`, ...args);
71
+ }
72
+ }
73
+
74
+ function swError(message: string, ...args: any[]): void {
75
+ if (shouldLog(3)) { // error 级别
76
+ console.error(`[WebPush SW] ${message}`, ...args);
77
+ }
78
+ }
79
+
80
+ self.addEventListener('install', (_event) => {
81
+ swLog('Service Worker installing...');
82
+ self.skipWaiting();
83
+ });
84
+
85
+ self.addEventListener('activate', (event) => {
86
+ swLog('Service Worker activating...');
87
+ event.waitUntil(self.clients.claim());
88
+ });
89
+
90
+ self.addEventListener('push', (event) => {
91
+ swLog('Push message received', event);
92
+
93
+ if (!event.data) {
94
+ swWarn('Push message has no data');
95
+ return;
96
+ }
97
+
98
+ try {
99
+ const data = processWebPushData(event.data);
100
+ event.waitUntil(handleWebPushNotification(data));
101
+ } catch (error) {
102
+ swError('Failed to process push message', error);
103
+
104
+ event.waitUntil(
105
+ self.registration.showNotification('WebPush Notification', {
106
+ body: 'You have a new message',
107
+ tag: 'fallback',
108
+ })
109
+ );
110
+ }
111
+ });
112
+
113
+ /**
114
+ * 处理 WebPush 数据,提取或构造 WebPushMessageData
115
+ */
116
+ function processWebPushData(eventData?: PushMessageData): WebPushMessageData {
117
+ if (!eventData) {
118
+ throw new Error('No push data available');
119
+ }
120
+
121
+ try {
122
+ const data = eventData.json();
123
+ swLog('Push message data (JSON):', data);
124
+ return data;
125
+ } catch {
126
+ const textData = eventData.text();
127
+ swLog('Push message data (Text):', textData);
128
+
129
+ // 如果不是 JSON 格式,创建默认数据结构
130
+ return {
131
+ id: '',
132
+ title: 'WebPush Notification',
133
+ desc: textData || 'You have a new message',
134
+ url: '/',
135
+ icon: '',
136
+ tag: '',
137
+ image: '',
138
+ rptExt: '',
139
+ rptURL: '',
140
+ };
141
+ }
142
+ }
143
+
144
+ /**
145
+ * 处理 WebPush 通知显示和消息发送
146
+ * @param data WebPush 消息数据
147
+ * @param options 处理选项
148
+ */
149
+ async function handleWebPushNotification(
150
+ data: WebPushMessageData,
151
+ options: { shouldReport?: boolean; clickEventType?: number } = {}
152
+ ): Promise<void> {
153
+ const { shouldReport = true, clickEventType = 2 } = options;
154
+
155
+ const message: NotificationMessage = {
156
+ messageID: data.id || generateMessageID(),
157
+ title: data.title || 'New Message',
158
+ body: data.desc || 'You have a new message',
159
+ icon: data.icon || '',
160
+ tag: data.tag || data?.id?.slice(-100) || generateUniqueTag(),
161
+ data: {
162
+ url: data.url,
163
+ image: data.image,
164
+ rptExt: data.rptExt,
165
+ rptURL: data.rptURL,
166
+ // 添加点击时的 eventType 标记
167
+ clickEventType: clickEventType,
168
+ },
169
+ timestamp: Date.now(),
170
+ };
171
+
172
+ const notificationPromise = self.registration.showNotification(
173
+ message.title,
174
+ {
175
+ body: message.body,
176
+ icon: message.icon,
177
+ image: data.image,
178
+ tag: message.tag,
179
+ data: message,
180
+ requireInteraction: false,
181
+ } as NotificationOptions & { image?: string }
182
+ );
183
+
184
+ const clientMessage = createClientSafeMessage(message);
185
+
186
+ const messagePromise = sendMessageToClients({
187
+ type: 'MESSAGE_RECEIVED',
188
+ data: clientMessage,
189
+ });
190
+
191
+ // 根据 shouldReport 参数决定是否进行数据上报
192
+ const reportPromise =
193
+ shouldReport && data.rptURL && data.rptExt
194
+ ? reportWebPushEvent({
195
+ id: data.id,
196
+ rptURL: data.rptURL,
197
+ rptExt: data.rptExt,
198
+ eventType: 1,
199
+ })
200
+ : Promise.resolve();
201
+
202
+ await Promise.all([notificationPromise, messagePromise, reportPromise]);
203
+ }
204
+
205
+ self.addEventListener('notificationclick', (event) => {
206
+ swLog('Notification clicked', event);
207
+
208
+ const notification = event.notification;
209
+ const action = event.action;
210
+ const data = notification.data;
211
+
212
+ notification.close();
213
+
214
+ if (action === 'close') {
215
+ return;
216
+ }
217
+ const clientNotificationData = createClientSafeMessage(data);
218
+
219
+ const messagePromise = sendMessageToClients({
220
+ type: 'NOTIFICATION_CLICKED',
221
+ data: {
222
+ notification: clientNotificationData,
223
+ action: action,
224
+ },
225
+ });
226
+
227
+ // 根据消息中的 URL 打开对应页面,如果没有则打开默认页面
228
+ const targetUrl = data?.data?.url || '/';
229
+ const windowPromise = openOrFocusWindow(targetUrl);
230
+
231
+ // 点击消息时进行数据上报,使用存储在通知数据中的 clickEventType
232
+ const clickEventType = data?.data?.clickEventType || 2; // 默认为 2
233
+ const reportPromise =
234
+ data?.data?.rptURL && data?.data?.rptExt
235
+ ? reportWebPushEvent({
236
+ id: data.messageID,
237
+ rptURL: data.data.rptURL,
238
+ rptExt: data.data.rptExt,
239
+ eventType: clickEventType,
240
+ })
241
+ : Promise.resolve();
242
+
243
+ event.waitUntil(Promise.all([messagePromise, windowPromise, reportPromise]));
244
+ });
245
+
246
+ self.addEventListener('notificationclose', (event) => {
247
+ swLog('Notification closed', event);
248
+ });
249
+
250
+ self.addEventListener('message', (event) => {
251
+ swLog('Message received from main thread', event.data);
252
+
253
+ const { type, payload } = event.data;
254
+
255
+ switch (type) {
256
+ case 'SHOW_NOTIFICATION':
257
+ handleShowNotification(payload);
258
+ break;
259
+ case 'PROCESS_WEBPUSH_DATA':
260
+ handleWebPushData(payload);
261
+ break;
262
+ case 'REVOKE_MESSAGE':
263
+ handleMessageRevoke(payload.messageID);
264
+ break;
265
+ case 'SET_LOG_LEVEL':
266
+ handleLogLevelUpdate(payload.logLevel);
267
+ break;
268
+ case 'REPORT_WEBPUSH_EVENT':
269
+ reportWebPushEvent(payload);
270
+ break;
271
+ }
272
+ });
273
+
274
+ /**
275
+ * 创建客户端安全消息,移除敏感字段
276
+ * @param message 原始通知消息
277
+ * @returns 过滤后的客户端消息
278
+ */
279
+ function createClientSafeMessage(message: NotificationMessage): NotificationMessage {
280
+ return {
281
+ messageID: message.messageID,
282
+ title: message.title,
283
+ body: message.body,
284
+ icon: message.icon,
285
+ tag: message.tag,
286
+ data: {
287
+ url: message.data?.url,
288
+ image: message.data?.image,
289
+ },
290
+ timestamp: message.timestamp,
291
+ };
292
+ }
293
+
294
+ async function sendMessageToClients(
295
+ message: ServiceWorkerMessage
296
+ ): Promise<void> {
297
+ try {
298
+ const clients = await self.clients.matchAll({
299
+ includeUncontrolled: true,
300
+ type: 'window',
301
+ });
302
+
303
+ clients.forEach((client) => {
304
+ client.postMessage(message);
305
+ });
306
+ } catch (error) {
307
+ swError('Failed to send message to clients', error);
308
+ }
309
+ }
310
+
311
+ async function openOrFocusWindow(targetUrl: string = '/'): Promise<void> {
312
+ try {
313
+ swLog('Attempting to open or focus window with URL:', targetUrl);
314
+
315
+ const clients = await self.clients.matchAll({
316
+ type: 'window',
317
+ includeUncontrolled: true,
318
+ });
319
+
320
+ swLog('Found clients:', clients.length);
321
+
322
+ // 处理相对路径和绝对路径
323
+ let fullTargetUrl: string;
324
+ try {
325
+ // 如果是完整的 URL(包含协议),直接使用
326
+ if (targetUrl.startsWith('http://') || targetUrl.startsWith('https://')) {
327
+ fullTargetUrl = targetUrl;
328
+ } else {
329
+ // 如果是相对路径,构建完整 URL
330
+ fullTargetUrl = new URL(targetUrl, self.location.origin).href;
331
+ }
332
+ } catch (error) {
333
+ swWarn('Invalid URL, using origin:', targetUrl, error);
334
+ fullTargetUrl = self.location.origin;
335
+ }
336
+
337
+ swLog('Full target URL:', fullTargetUrl);
338
+
339
+ // 尝试找到已经打开的匹配窗口
340
+ for (const client of clients) {
341
+ if (client.url === fullTargetUrl && 'focus' in client) {
342
+ await client.focus();
343
+ return;
344
+ }
345
+ }
346
+
347
+ // 如果没有打开的窗口,打开新窗口
348
+ if (self.clients.openWindow) {
349
+ await self.clients.openWindow(fullTargetUrl);
350
+ }
351
+ } catch (error) {
352
+ swError('Failed to open or focus window', error);
353
+ }
354
+ }
355
+
356
+ async function handleShowNotification(payload: any): Promise<void> {
357
+ try {
358
+ const { eventType, data, options } = payload;
359
+
360
+ swLog('Handling show notification request', { eventType, data, options });
361
+
362
+ await self.registration.showNotification(options.title, {
363
+ body: options.body,
364
+ icon: options.icon,
365
+ badge: options.badge,
366
+ tag: options.tag,
367
+ requireInteraction: options.requireInteraction,
368
+ silent: options.silent,
369
+ data: options.data,
370
+ });
371
+
372
+ swLog('Notification shown successfully', options.title);
373
+ } catch (error) {
374
+ swError('Failed to handle show notification', error);
375
+ }
376
+ }
377
+
378
+ /**
379
+ * 处理来自主线程的 WebPush 数据,复用 push 事件的处理逻辑
380
+ */
381
+ async function handleWebPushData(webpushInfo: WebPushMessageData): Promise<void> {
382
+ try {
383
+ swLog('Handling webpush data from main thread', webpushInfo);
384
+
385
+ // 直接使用传入的 webpushInfo 数据,复用 push 事件的处理逻辑
386
+ // 不进行数据上报,但点击时 eventType 为 3
387
+ await handleWebPushNotification(webpushInfo, {
388
+ shouldReport: false,
389
+ clickEventType: 3
390
+ });
391
+
392
+ swLog('WebPush notification processed successfully');
393
+ } catch (error) {
394
+ swError('Failed to handle webpush data', error);
395
+
396
+ // 降级处理:显示默认通知
397
+ try {
398
+ await self.registration.showNotification('WebPush Notification', {
399
+ body: 'You have a new message',
400
+ tag: 'fallback',
401
+ });
402
+ } catch (fallbackError) {
403
+ swError('Failed to show fallback notification', fallbackError);
404
+ }
405
+ }
406
+ }
407
+
408
+ async function handleMessageRevoke(messageID: string): Promise<void> {
409
+ try {
410
+ const notifications = await self.registration.getNotifications();
411
+
412
+ notifications.forEach((notification) => {
413
+ if (notification.data && notification.data.messageID === messageID) {
414
+ notification.close();
415
+ }
416
+ });
417
+
418
+ await sendMessageToClients({
419
+ type: 'MESSAGE_REVOKED',
420
+ data: { messageID },
421
+ });
422
+ } catch (error) {
423
+ swError('Failed to handle message revocation', error);
424
+ }
425
+ }
426
+
427
+ function handleLogLevelUpdate(logLevel: LogLevel): void {
428
+ currentLogLevel = logLevel;
429
+ swLog('Log level updated to:', logLevel);
430
+ }
431
+
432
+ function generateMessageID(): string {
433
+ return Date.now().toString(36) + Math.random().toString(36).substring(2);
434
+ }
435
+
436
+ function generateUniqueTag(): string {
437
+ return 'push-' + Date.now() + '-' + Math.random().toString(36).substring(2, 7);
438
+ }
439
+
440
+ /**
441
+ * 上报 WebPush 事件
442
+ * @param options 上报选项,包含 id、rptURL、rptExt、eventType 等字段
443
+ */
444
+ async function reportWebPushEvent(options: ReportOptions): Promise<void> {
445
+ try {
446
+ if (!options.rptURL || !options.rptExt) {
447
+ swWarn('Missing rptURL or rptExt, skipping report');
448
+ return;
449
+ }
450
+
451
+ const reportData: ReportData = {
452
+ webpushEvents: [
453
+ {
454
+ id: options.id,
455
+ EventType: options.eventType || 1,
456
+ EventTime: Math.floor(Date.now() / 1000), // 转换为秒级时间戳
457
+ rptExt: options.rptExt,
458
+ },
459
+ ],
460
+ };
461
+
462
+ swLog('Reporting WebPush event', { rptURL: options.rptURL, reportData });
463
+
464
+ const response = await fetch(options.rptURL, {
465
+ method: 'POST',
466
+ headers: {
467
+ 'Content-Type': 'application/json',
468
+ },
469
+ body: JSON.stringify(reportData),
470
+ });
471
+
472
+ if (response.ok) {
473
+ swLog('WebPush event reported successfully');
474
+ } else {
475
+ swWarn(
476
+ 'Failed to report WebPush event',
477
+ response.status,
478
+ response.statusText
479
+ );
480
+ }
481
+ } catch (error) {
482
+ swError('Error reporting WebPush event', error);
483
+ }
484
+ }
485
+
486
+ self.addEventListener('error', (event) => {
487
+ swError('Service Worker error', event.error);
488
+ });
489
+
490
+ self.addEventListener('unhandledrejection', (event) => {
491
+ swError('Service Worker unhandled promise rejection', event.reason);
492
+ });
493
+
494
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './inner';
2
+ export * from './outer';
@@ -0,0 +1,44 @@
1
+ import { NotificationMessage } from "./outer";
2
+
3
+ export interface NotificationClickData {
4
+ notification: NotificationMessage;
5
+ action?: string;
6
+ }
7
+
8
+ export interface StatisticsData {
9
+ messageID: string;
10
+ type: 'reach' | 'click';
11
+ timestamp: number;
12
+ SDKAppID: number;
13
+ registrationID: string;
14
+ }
15
+
16
+ export interface ServiceWorkerMessage {
17
+ type: 'MESSAGE_RECEIVED' | 'NOTIFICATION_CLICKED' | 'MESSAGE_REVOKED';
18
+ data: any;
19
+ }
20
+
21
+ export interface SubscriptionInfo {
22
+ subscription: PushSubscription;
23
+ token: string;
24
+ auth: string;
25
+ p256dh: string;
26
+ endpoint: string;
27
+ }
28
+
29
+ export interface WebPushCompatibilityInfo {
30
+ isSupported: boolean;
31
+ browserInfo: {
32
+ name: string;
33
+ version: string;
34
+ platform: string;
35
+ majorVersion: number;
36
+ };
37
+ features: {
38
+ serviceWorker: boolean;
39
+ pushManager: boolean;
40
+ notification: boolean;
41
+ };
42
+ warnings: string[];
43
+ recommendations: string[];
44
+ }
@@ -0,0 +1,142 @@
1
+ export type LogLevel = 0 | 1 | 2 | 3 | 4;
2
+
3
+ export enum Placement {
4
+ CENTER = 0, // 中间
5
+ TOP_LEFT = 1, // 左上
6
+ TOP_CENTER = 2, // 上中
7
+ TOP_RIGHT = 3, // 右上
8
+ MIDDLE_RIGHT = 4, // 右中
9
+ BOTTOM_RIGHT = 5, // 右下
10
+ BOTTOM_CENTER = 6, // 下中
11
+ BOTTOM_LEFT = 7, // 左下
12
+ MIDDLE_LEFT = 8, // 左中
13
+ }
14
+
15
+ export interface WebPushSDK {
16
+ registerPush(options?: RegisterPushOptions): Promise<any>;
17
+ unRegisterPush(): Promise<any>;
18
+ addPushListener(eventName: EVENT, listener: (data: EventResult) => void): any;
19
+ removePushListener(
20
+ eventName: EVENT,
21
+ listener: (data: EventResult) => void
22
+ ): any;
23
+ }
24
+
25
+ export interface RegisterPushOptions {
26
+ SDKAppID: number;
27
+ appKey: string;
28
+ userID: string;
29
+ serviceWorkerPath?: string;
30
+ chat?: any;
31
+ /**
32
+ * 日志级别:
33
+ * 0 - 普通级别,日志量较多,接入时建议使用
34
+ * 1 - release级别,SDK 输出关键信息,生产环境时建议使用(默认)
35
+ * 2 - 告警级别,SDK 只输出告警和错误级别的日志
36
+ * 3 - 错误级别,SDK 只输出错误级别的日志
37
+ * 4 - 无日志级别,SDK 将不打印任何日志
38
+ */
39
+ logLevel?: LogLevel;
40
+ }
41
+
42
+ export enum EVENT {
43
+ MESSAGE_RECEIVED = 'message_received',
44
+ MESSAGE_REVOKED = 'message_revoked',
45
+ NOTIFICATION_CLICKED = 'notification_clicked',
46
+ CUSTOM_MESSAGE_RECEIVED = 'custom_message_received',
47
+ }
48
+
49
+ export interface NotificationMessage {
50
+ messageID: string;
51
+ title: string;
52
+ body: string;
53
+ icon?: string;
54
+ tag?: string;
55
+ data?: any;
56
+ timestamp: number;
57
+ }
58
+
59
+ export interface StandardMessage {
60
+ id: string;
61
+ MsgType: 'standard';
62
+ MsgContent: {
63
+ Text: {
64
+ Title: string;
65
+ Desc: string;
66
+ };
67
+ Image?: {
68
+ URL: string;
69
+ LinkURL: string;
70
+ };
71
+ Close: 0 | 1;
72
+ Placement?: Placement;
73
+ Duration?: number;
74
+ Button?: Array<{
75
+ Text: string;
76
+ Icon?: string;
77
+ Url: string;
78
+ }>;
79
+ };
80
+ Ext?: string;
81
+ }
82
+
83
+ export interface HtmlMessage {
84
+ id: string;
85
+ MsgType: 'html';
86
+ MsgContent: {
87
+ Placement?: Placement;
88
+ Duration?: number;
89
+ Html: string; // base64 encoded HTML
90
+ };
91
+ Ext?: string;
92
+ }
93
+
94
+ export interface CustomMessage {
95
+ id: string;
96
+ MsgType: 'custom';
97
+ MsgContent: {
98
+ Data: string | object;
99
+ };
100
+ Ext?: string;
101
+ }
102
+
103
+ export interface WebPushInfo {
104
+ Title: string;
105
+ Desc: string;
106
+ Icon: string;
107
+ Image: string;
108
+ URL: string;
109
+ }
110
+
111
+ export interface WebPushExt {
112
+ WebpushReportUrl: string;
113
+ OnlineClickExt: string;
114
+ TaskId: string;
115
+ }
116
+
117
+ export type PushMessage = StandardMessage | HtmlMessage | CustomMessage;
118
+
119
+ export interface MessageReceivedData {
120
+ content: string;
121
+ info: WebPushInfo;
122
+ extension: WebPushExt;
123
+ }
124
+
125
+ export interface MessageReceivedResult {
126
+ message: PushMessage | NotificationMessage;
127
+ }
128
+
129
+ export interface MessageRevokedResult {
130
+ messageID: String;
131
+ }
132
+
133
+ export interface MessageNotificationClickedResult {
134
+ ext: String;
135
+ }
136
+
137
+ export interface EventResult {
138
+ data:
139
+ | MessageReceivedResult
140
+ | MessageRevokedResult
141
+ | MessageNotificationClickedResult;
142
+ }