web-push-notifications 3.40.1 → 3.44.1

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 (149) hide show
  1. package/.editorconfig +11 -0
  2. package/.gitlab-ci.yml +190 -0
  3. package/babel.config.js +7 -0
  4. package/ci/cdn/Dockerfile +12 -0
  5. package/ci/dev/Dockerfile +30 -0
  6. package/ci/dev/rootfs/entrypoint.sh +18 -0
  7. package/ci/dev/rootfs/entrypoint.sh.d/nginx.sh +6 -0
  8. package/ci/dev/rootfs/entrypoint.sh.d/supervisor.sh +5 -0
  9. package/ci/dev/rootfs/etc/nginx/_real_ip.conf +2 -0
  10. package/ci/dev/rootfs/etc/nginx/conf.d/default.conf +20 -0
  11. package/ci/dev/rootfs/etc/supervisor.d/nginx.ini +11 -0
  12. package/ci/github/Dockerfile +59 -0
  13. package/ci/github/release-zip.js +61 -0
  14. package/ci/npm/Dockerfile +19 -0
  15. package/config/config.js +24 -0
  16. package/config/configBuilder.js +126 -0
  17. package/config/helpers.js +9 -0
  18. package/config/index.js +1 -0
  19. package/develop/README.md +42 -0
  20. package/develop/favicon.png +0 -0
  21. package/develop/index.html +511 -0
  22. package/eslint.config.mjs +114 -0
  23. package/package.json +4 -34
  24. package/{lib → public}/index.d.ts +10 -10
  25. package/scripts/zip.js +26 -0
  26. package/src/core/Pushwoosh.ts +768 -0
  27. package/src/core/Pushwoosh.types.ts +254 -0
  28. package/src/core/Safari.types.ts +26 -0
  29. package/src/core/constants.ts +58 -0
  30. package/src/core/events.types.ts +46 -0
  31. package/src/core/functions.ts +33 -0
  32. package/src/core/legacyEventsMap.ts +64 -0
  33. package/src/core/logger.ts +64 -0
  34. package/src/core/modules/EventBus/EventBus.ts +66 -0
  35. package/src/core/modules/EventBus/index.ts +1 -0
  36. package/src/core/storage.ts +254 -0
  37. package/src/helpers/logger.ts +81 -0
  38. package/src/helpers/pwlogger/Logger.constants.ts +31 -0
  39. package/src/helpers/pwlogger/Logger.ts +218 -0
  40. package/src/helpers/pwlogger/Logger.types.ts +66 -0
  41. package/src/helpers/pwlogger/handlers/handler-console/handler-console.ts +40 -0
  42. package/src/helpers/pwlogger/index.ts +2 -0
  43. package/src/helpers/unescape.ts +36 -0
  44. package/src/models/InboxMessages.ts +202 -0
  45. package/src/models/InboxMessages.types.ts +111 -0
  46. package/src/models/NotificationPayload.ts +216 -0
  47. package/src/models/NotificationPayload.types.ts +65 -0
  48. package/src/modules/Api/Api.ts +386 -0
  49. package/src/modules/Api/Api.types.ts +7 -0
  50. package/src/modules/ApiClient/ApiClient.ts +153 -0
  51. package/src/modules/ApiClient/ApiClient.types.ts +222 -0
  52. package/src/modules/Data/Data.ts +345 -0
  53. package/src/modules/DateModule.ts +53 -0
  54. package/src/modules/InboxMessagesPublic.ts +222 -0
  55. package/src/modules/PlatformChecker/PlatformChecker.ts +170 -0
  56. package/src/modules/PlatformChecker/PlatformChecker.types.ts +5 -0
  57. package/src/modules/PlatformChecker/index.ts +1 -0
  58. package/src/modules/storage/Storage.ts +164 -0
  59. package/src/modules/storage/Storage.types.ts +54 -0
  60. package/src/modules/storage/Store.ts +104 -0
  61. package/src/modules/storage/migrations/26-11-2018.ts +25 -0
  62. package/src/modules/storage/migrations/MigrationExecutor.ts +31 -0
  63. package/src/modules/storage/migrations/Migrations.ts +41 -0
  64. package/src/modules/storage/migrations/constants.ts +8 -0
  65. package/src/modules/storage/migrations/helpers.ts +16 -0
  66. package/src/modules/storage/migrations/initial.ts +47 -0
  67. package/src/modules/storage/version.ts +2 -0
  68. package/src/npm.ts +1 -0
  69. package/src/pushwoosh-web-notifications.ts +47 -0
  70. package/src/pushwoosh-widget-inbox.ts +8 -0
  71. package/src/pushwoosh-widget-subscribe-popup.ts +9 -0
  72. package/src/pushwoosh-widget-subscription-button.ts +8 -0
  73. package/src/pushwoosh-widget-subscription-prompt.ts +6 -0
  74. package/src/service-worker.ts +455 -0
  75. package/src/services/PushService/PushService.ts +2 -0
  76. package/src/services/PushService/PushService.types.ts +74 -0
  77. package/src/services/PushService/drivers/PushServiceDefault/PushServiceDefault.ts +235 -0
  78. package/src/services/PushService/drivers/PushServiceDefault/PushServiceDefault.types.ts +3 -0
  79. package/src/services/PushService/drivers/PushServiceSafari/PushServiceSafari.ts +125 -0
  80. package/src/services/PushService/drivers/PushServiceSafari/PushServiceSafari.types.ts +4 -0
  81. package/src/widget-inbox.ts +1 -0
  82. package/src/widget-subscribe-popup.ts +1 -0
  83. package/src/widget-subscription-button.ts +1 -0
  84. package/src/widget-subscription-prompt.ts +33 -0
  85. package/src/widgets/Inbox/InboxWidget.ts +564 -0
  86. package/src/widgets/Inbox/constants.ts +49 -0
  87. package/src/widgets/Inbox/css/inboxWidgetStyle.css +274 -0
  88. package/src/widgets/Inbox/helpers.ts +63 -0
  89. package/src/widgets/Inbox/inbox.d.ts +9 -0
  90. package/src/widgets/Inbox/inbox_widget.types.ts +41 -0
  91. package/src/widgets/Inbox/index.ts +1 -0
  92. package/src/widgets/Inbox/widgetTemplates.ts +55 -0
  93. package/src/widgets/SubscribePopup/SubscribePopup.ts +241 -0
  94. package/src/widgets/SubscribePopup/constants.ts +66 -0
  95. package/src/widgets/SubscribePopup/helpers.ts +11 -0
  96. package/src/widgets/SubscribePopup/index.ts +1 -0
  97. package/src/widgets/SubscribePopup/popupTemplates.ts +24 -0
  98. package/src/widgets/SubscribePopup/styles/popup.css +226 -0
  99. package/src/widgets/SubscribePopup/types/subscribe-popup.ts +68 -0
  100. package/src/widgets/SubscriptionButton/assets/css/main.css +205 -0
  101. package/src/widgets/SubscriptionButton/bell.ts +67 -0
  102. package/src/widgets/SubscriptionButton/constants.ts +28 -0
  103. package/src/widgets/SubscriptionButton/index.ts +377 -0
  104. package/src/widgets/SubscriptionButton/positioning.ts +165 -0
  105. package/src/widgets/SubscriptionButton/subscribe_widget.types.ts +53 -0
  106. package/src/widgets/SubscriptionPrompt/SubscriptionPromptWidget.constants.ts +1 -0
  107. package/src/widgets/SubscriptionPrompt/SubscriptionPromptWidget.helpers.ts +110 -0
  108. package/src/widgets/SubscriptionPrompt/SubscriptionPromptWidget.ts +102 -0
  109. package/src/widgets/SubscriptionPrompt/SubscriptionPromptWidget.types.ts +23 -0
  110. package/src/widgets/SubscriptionPrompt/constants.ts +22 -0
  111. package/src/widgets/SubscriptionPrompt/helpers.ts +42 -0
  112. package/src/widgets/widgets.d.ts +4 -0
  113. package/src/worker/global.ts +36 -0
  114. package/src/worker/notification.ts +34 -0
  115. package/src/worker/worker.types.ts +4 -0
  116. package/test/__helpers__/apiHelpers.ts +22 -0
  117. package/test/__helpers__/keyValueHelpers.ts +15 -0
  118. package/test/__helpers__/platformHelpers.ts +54 -0
  119. package/test/__helpers__/sinonHelpers.ts +7 -0
  120. package/test/__helpers__/storageHelpers.ts +56 -0
  121. package/test/__mocks__/apiRequests.ts +26 -0
  122. package/test/__mocks__/idbMock.ts +12 -0
  123. package/test/__mocks__/idbObjectStoreMock.ts +38 -0
  124. package/test/__mocks__/inboxMessages.ts +292 -0
  125. package/test/__mocks__/models/inboxModel.ts +71 -0
  126. package/test/__mocks__/modules/apiClientModule.ts +18 -0
  127. package/test/__mocks__/modules/dateModule.ts +34 -0
  128. package/test/__mocks__/modules/inboxParamsModule.ts +21 -0
  129. package/test/__mocks__/modules/paramsBuilder.ts +12 -0
  130. package/test/__mocks__/modules/paramsModule.ts +35 -0
  131. package/test/__mocks__/modules/payloadBuilderModule.ts +15 -0
  132. package/test/__mocks__/modules/storageModule.ts +58 -0
  133. package/test/__mocks__/navigator.ts +38 -0
  134. package/test/__mocks__/notification.ts +84 -0
  135. package/test/__mocks__/pushwoosh.ts +12 -0
  136. package/test/__mocks__/userAgents +8 -0
  137. package/test/functions.test.ts +22 -0
  138. package/test/ignore-html.js +6 -0
  139. package/test/mocha.opts +6 -0
  140. package/test/modules/DateModule/unit.test.ts +80 -0
  141. package/test/modules/storage/Storage/unit.test.ts +180 -0
  142. package/test/modules/storage/Store/unit.test.ts +192 -0
  143. package/testRegister.js +24 -0
  144. package/tsconfig.json +31 -0
  145. package/webpack.config.js +163 -0
  146. package/lib/index.js +0 -2
  147. package/lib/index.js.map +0 -1
  148. package/lib/service-worker.js +0 -2
  149. package/lib/service-worker.js.map +0 -1
@@ -0,0 +1,222 @@
1
+ import { type Api } from './Api/Api';
2
+ import { type Data } from './Data/Data';
3
+ import DateModule from './DateModule';
4
+ import { type default as InboxMessagesModel } from '../models/InboxMessages';
5
+ import {
6
+ type IInboxMessage,
7
+ type IInboxMessageActionParams,
8
+ type IInboxMessagePublic,
9
+ type IInboxMessages,
10
+ type TInboxActionType,
11
+ type TInboxMessageStatus,
12
+ type TInboxMessageStatusDeleted,
13
+ type TInboxMessageStatusOpen,
14
+ type TInboxMessageStatusRead,
15
+ type TInboxMessageType,
16
+ type TInboxMessageTypeDeeplink,
17
+ type TInboxMessageTypePlain,
18
+ type TInboxMessageTypeRichmedia,
19
+ type TInboxMessageTypeURL,
20
+ } from '../models/InboxMessages.types';
21
+
22
+ export default class InboxMessages implements IInboxMessages {
23
+ private readonly data: Data;
24
+ private readonly api: Api;
25
+ private readonly inboxModel: InboxMessagesModel;
26
+ private dateModule: DateModule;
27
+
28
+ constructor(
29
+ data: Data,
30
+ api: Api,
31
+ inboxModel: InboxMessagesModel,
32
+ dateModule: DateModule = new DateModule(),
33
+ ) {
34
+ this.data = data;
35
+ this.api = api;
36
+ this.inboxModel = inboxModel;
37
+ this.dateModule = dateModule;
38
+
39
+ this.publicMessageBuilder = this.publicMessageBuilder.bind(this);
40
+ }
41
+
42
+ /**
43
+ * Get message type by IInboxMessageActionParams
44
+ * @param actionParams
45
+ */
46
+ private messageTypeFactory(action_type: TInboxActionType, actionParams: IInboxMessageActionParams): TInboxMessageType {
47
+ let messageType: TInboxMessageTypePlain = 0;
48
+ if (action_type === 2) { // 2 is Richmedia Action Type for server loaded messages. See TInboxActionType typings comment.
49
+ (<TInboxMessageTypeRichmedia>messageType) = 1;
50
+ } else if ('l' in actionParams && actionParams.l != null) { // 'l' - URL and deeplink parameter
51
+ if (actionParams.l.startsWith('http')) { // Deeplink parameter - relative URL; URL parameter - full URL
52
+ (<TInboxMessageTypeURL>messageType) = 2;
53
+ } else {
54
+ (<TInboxMessageTypeDeeplink>messageType) = 3;
55
+ }
56
+ }
57
+
58
+ return messageType;
59
+ }
60
+
61
+ /**
62
+ * Update messages status using codes from arguments
63
+ * @param codes
64
+ * @param messages
65
+ * @param status
66
+ */
67
+ private async updateMessagesStatusWithCodes(
68
+ codes: Array<string>,
69
+ messages: Array<IInboxMessage>,
70
+ status: TInboxMessageStatus,
71
+ ): Promise<void> {
72
+ const updatedMessages: Array<IInboxMessage> = [];
73
+ const inboxStatusQueries: Array<Promise<void>> = [];
74
+
75
+ messages.forEach(async (msg) => {
76
+ if (codes.indexOf(msg.inbox_id) === -1) {
77
+ return;
78
+ }
79
+
80
+ msg.status = status;
81
+ updatedMessages.push(msg);
82
+
83
+ // Set inbox status to server
84
+ inboxStatusQueries.push(this.api.inboxStatus(msg.order, msg.status));
85
+ });
86
+
87
+ await this.inboxModel.putBulkMessages(updatedMessages);
88
+ await Promise.all(inboxStatusQueries);
89
+ }
90
+
91
+ /**
92
+ * Build TInboxMessagePublic by TInboxMessage
93
+ * @param message
94
+ */
95
+ async publicMessageBuilder({
96
+ action_type,
97
+ action_params,
98
+ image,
99
+ title,
100
+ send_date,
101
+ inbox_id,
102
+ text,
103
+ status,
104
+ }: IInboxMessage): Promise<IInboxMessagePublic> {
105
+ const imageUrl = image || await this.data.getDefaultNotificationImage();
106
+ const inboxTitle = title || await this.data.getDefaultNotificationTitle();
107
+ const actionParams = JSON.parse(action_params);
108
+
109
+ this.dateModule.date = new Date(parseInt(send_date) * 1000);
110
+ this.dateModule.setLocal();
111
+
112
+ return {
113
+ title: inboxTitle,
114
+ imageUrl,
115
+ code: inbox_id,
116
+ message: text,
117
+ sendDate: this.dateModule.date.toISOString(),
118
+ type: this.messageTypeFactory(action_type, actionParams),
119
+ link: actionParams?.l || '/',
120
+ isRead: <TInboxMessageStatusRead> status === 2 || <TInboxMessageStatusOpen> status === 3,
121
+ isActionPerformed: <TInboxMessageStatusOpen> status === 3,
122
+ };
123
+ }
124
+
125
+ /**
126
+ * Count of messages with no action performed
127
+ */
128
+ messagesWithNoActionPerformedCount(): Promise<number> {
129
+ return this.inboxModel.getDeliveredReadMessagesCount();
130
+ }
131
+
132
+ /**
133
+ * All unread messages
134
+ */
135
+ unreadMessagesCount() {
136
+ return this.inboxModel.getDeliveredMessagesCount();
137
+ }
138
+
139
+ /**
140
+ * All messages count
141
+ */
142
+ messagesCount(): Promise<number> {
143
+ return this.inboxModel.messagesCount();
144
+ }
145
+
146
+ /**
147
+ * Get all active messages
148
+ */
149
+ async loadMessages(): Promise<Array<IInboxMessagePublic>> {
150
+ const readMessages = await this.inboxModel.getReadOpenMessages();
151
+ const unreadMessages = await this.inboxModel.getDeliveredMessages();
152
+ const buildMessagePromises = [...readMessages, ...unreadMessages]
153
+ .sort((msgA: IInboxMessage, msgB: IInboxMessage) => { // sort by send date
154
+ return parseInt(msgB.send_date, 10) - parseInt(msgA.send_date, 10);
155
+ })
156
+ .sort((msgA: IInboxMessage, msgB: IInboxMessage) => { // sort by order
157
+ return parseInt(msgB.order || '0', 10) - parseInt(msgA.order || '0', 10);
158
+ })
159
+ .map(this.publicMessageBuilder);
160
+ return Promise.all(buildMessagePromises);
161
+ }
162
+
163
+ /**
164
+ * Mark messages as read
165
+ * @param codes
166
+ */
167
+ async readMessagesWithCodes(codes: Array<string>): Promise<void> {
168
+ const unreadMessages = await this.inboxModel.getDeliveredMessages();
169
+
170
+ const statusRead: TInboxMessageStatusRead = 2;
171
+ await this.updateMessagesStatusWithCodes(
172
+ codes,
173
+ unreadMessages,
174
+ statusRead,
175
+ );
176
+ }
177
+
178
+ /**
179
+ * Execute message action. Type "richmedia" and "plain" does not support
180
+ * @param code
181
+ */
182
+ async performActionForMessageWithCode(code: string): Promise<void> {
183
+ const message = await this.inboxModel.getMessage(code);
184
+ const actionParams = JSON.parse(message.action_params);
185
+ const messageType = this.messageTypeFactory(message.action_type, actionParams);
186
+
187
+ if (<TInboxMessageTypeURL>messageType === 2 && actionParams.l != null) {
188
+ document.location.href = actionParams.l;
189
+ } else if (<TInboxMessageTypeDeeplink>messageType === 3 && actionParams.l != null) {
190
+ window.history.go(actionParams.l);
191
+ }
192
+
193
+ (<TInboxMessageStatusOpen>message.status) = 3;
194
+ await this.inboxModel.putMessage(message);
195
+
196
+ // Set inbox status to server
197
+ await this.api.inboxStatus(message.order, message.status);
198
+ }
199
+
200
+ /**
201
+ * Delete messages by codes
202
+ * @param codes
203
+ */
204
+ async deleteMessagesWithCodes(codes: Array<string>): Promise<void> {
205
+ const readMessages = await this.inboxModel.getReadOpenMessages();
206
+ const unreadMessages = await this.inboxModel.getDeliveredMessages();
207
+
208
+ const statusDeleted: TInboxMessageStatusDeleted = 4;
209
+ await this.updateMessagesStatusWithCodes(
210
+ codes,
211
+ [...readMessages, ...unreadMessages],
212
+ statusDeleted,
213
+ );
214
+ }
215
+
216
+ /**
217
+ * Sync inbox messages with server
218
+ */
219
+ async syncMessages() {
220
+ await this.inboxModel.updateMessages();
221
+ }
222
+ }
@@ -0,0 +1,170 @@
1
+ import { type TPlatform, type TPlatformChrome, type TPlatformEdge, type TPlatformFirefox, type TPlatformSafari } from './PlatformChecker.types';
2
+
3
+ export class PlatformChecker {
4
+ private readonly global: typeof globalThis;
5
+
6
+ private readonly _isSafari: boolean;
7
+ private readonly _isOpera: boolean;
8
+ private readonly _isEdge: boolean;
9
+ private readonly _isFirefox: boolean;
10
+ private readonly _isChrome: boolean;
11
+
12
+ private readonly _isMacOS: boolean;
13
+
14
+ private readonly _isAvailableServiceWorker: boolean;
15
+ private readonly _isAvailableNotifications: boolean;
16
+
17
+ /**
18
+ * Browser name + version
19
+ * Example: "Chrome 70"
20
+ */
21
+ private readonly _browserVersion: string;
22
+ private readonly _platform: TPlatform;
23
+
24
+ constructor(global: typeof globalThis) {
25
+ this.global = global;
26
+
27
+ this._isSafari = this.isSafariBrowser();
28
+ this._isOpera = this.isOperaBrowser();
29
+ this._isEdge = this.isEdgeBrowser();
30
+ this._isFirefox = this.isFirefoxBrowser();
31
+ this._isChrome = this.isChromeBrowser();
32
+
33
+ this._isMacOS = this.isMacOS();
34
+
35
+ this._isAvailableServiceWorker = this.canUseServiceWorkers();
36
+ this._isAvailableNotifications = this.canReceiveNotifications();
37
+
38
+ this._platform = this.getPlatformType();
39
+ this._browserVersion = this.getBrowserVersion();
40
+ }
41
+
42
+ // Platform flags
43
+ get isEdge() {
44
+ return this._isEdge;
45
+ }
46
+
47
+ get isSafari() {
48
+ return this._isSafari;
49
+ }
50
+
51
+ get isOpera() {
52
+ return this._isOpera;
53
+ }
54
+
55
+ get isAvailableServiceWorker() {
56
+ return this._isAvailableServiceWorker;
57
+ }
58
+
59
+ get isAvailableNotifications() {
60
+ return this._isAvailableNotifications;
61
+ }
62
+
63
+ // Platform values
64
+
65
+ get platform() {
66
+ return this._platform;
67
+ }
68
+
69
+ get browserVersion() {
70
+ return this._browserVersion;
71
+ }
72
+
73
+ isSafariBrowser(): boolean {
74
+ return 'safari' in this.global && navigator.userAgent.indexOf('Safari') > -1;
75
+ }
76
+
77
+ isOperaBrowser(): boolean {
78
+ return navigator.userAgent.indexOf('Opera') !== -1 || navigator.userAgent.indexOf('OPR') !== -1;
79
+ }
80
+
81
+ isEdgeBrowser(): boolean {
82
+ return navigator.userAgent.indexOf('Edge') > -1;
83
+ }
84
+
85
+ isFirefoxBrowser(): boolean {
86
+ return navigator.userAgent.toLowerCase().indexOf('firefox') !== -1;
87
+ }
88
+
89
+ isChromeBrowser(): boolean {
90
+ return /Chrome/.test(navigator.userAgent)
91
+ && /Google Inc/.test(navigator.vendor)
92
+ && !this._isOpera
93
+ && !this._isEdge;
94
+ }
95
+
96
+ isMacOS(): boolean {
97
+ return 'platform' in navigator && navigator.platform.toLowerCase().indexOf('mac') !== -1;
98
+ }
99
+
100
+ canUseServiceWorkers(): boolean {
101
+ return !!navigator.serviceWorker && 'PushManager' in this.global && 'Notification' in this.global;
102
+ }
103
+
104
+ /**
105
+ * Check availability ServiceWorker or safari browser on macos
106
+ */
107
+ canReceiveNotifications(): boolean {
108
+ return (this._isSafari && this._isMacOS) || (this._isAvailableServiceWorker && !this._isEdge);
109
+ }
110
+
111
+ /**
112
+ * Get Pushwoosh system platform code
113
+ */
114
+ getPlatformType(): TPlatform {
115
+ let platform: TPlatformChrome = 11;
116
+
117
+ switch (true) {
118
+ case this._isSafari:
119
+ (<TPlatformSafari>platform) = 10;
120
+ break;
121
+
122
+ case this._isOpera || this._isChrome:
123
+ (<TPlatformChrome>platform) = 11;
124
+ break;
125
+
126
+ case this._isFirefox:
127
+ (<TPlatformFirefox>platform) = 12;
128
+ break;
129
+
130
+ case this._isEdge:
131
+ (<TPlatformEdge>platform) = 150;
132
+ break;
133
+ }
134
+
135
+ return platform;
136
+ }
137
+
138
+ /**
139
+ * Get browser name + version from userAgent
140
+ */
141
+ getBrowserVersion(): string {
142
+ const { userAgent } = navigator;
143
+ const matchOperaVersion = userAgent.match(/\bOPR\/(\d+)/);
144
+ if (matchOperaVersion !== null) {
145
+ return `Opera ${matchOperaVersion[1]}`;
146
+ }
147
+
148
+ const matchEdgeVersion = userAgent.match(/\bEdge\/(\d+)/);
149
+ if (matchEdgeVersion !== null) {
150
+ return `Edge ${matchEdgeVersion[1]}`;
151
+ }
152
+
153
+ // edge on chromium
154
+ const matchEdgVersion = userAgent.match(/\bEdg\/(\d+)/);
155
+ if (matchEdgVersion !== null) {
156
+ return `Edge ${matchEdgVersion[1]}`;
157
+ }
158
+
159
+ let match = userAgent.match(/(opera|chrome|safari|firefox(?=\/))\/?\s*(\d+)/i) || [];
160
+ const [, browser = ''] = match;
161
+
162
+ match = match[2] ? [browser, match[2]] : [navigator.appName, navigator.appVersion, '-?'];
163
+ const version = userAgent.match(/version\/([.\d]+)/i);
164
+ if (version !== null) {
165
+ match.splice(1, 1, version[1]);
166
+ }
167
+
168
+ return match.join(' ');
169
+ }
170
+ }
@@ -0,0 +1,5 @@
1
+ export type TPlatformSafari = 10; // Safari platform code in Pushwoosh system
2
+ export type TPlatformChrome = 11; // Chrome platform code in Pushwoosh system
3
+ export type TPlatformFirefox = 12; // Firefox platform code in Pushwoosh system
4
+ export type TPlatformEdge = 150; // Edge platform code in Pushwoosh system
5
+ export type TPlatform = TPlatformSafari | TPlatformChrome | TPlatformFirefox | TPlatformEdge;
@@ -0,0 +1 @@
1
+ export { PlatformChecker } from './PlatformChecker';
@@ -0,0 +1,164 @@
1
+ import MigrationExecutor from './migrations/MigrationExecutor';
2
+ import { type IIDBOpenEventTargetWithResult, type TIDBKeyType, type TIDBQueryValue, type TSdkStoreName } from './Storage.types';
3
+ import Store from './Store';
4
+ import dbVersion from './version';
5
+
6
+ export default class Storage {
7
+ db: Promise<IDBDatabase>;
8
+
9
+ /**
10
+ * Change database version handler
11
+ * @param db
12
+ * @param event
13
+ */
14
+ private dbVersionChangeHandler(db: IDBDatabase, event: IDBVersionChangeEvent) {
15
+ console.info('onversionchange', event);
16
+ db.close();
17
+ }
18
+
19
+ /**
20
+ * Success database request handler
21
+ * @param resolve
22
+ * @param event
23
+ */
24
+ private dbRequestSuccessHandler(resolve: (db: IDBDatabase) => void, event: Event) {
25
+ const target: IIDBOpenEventTargetWithResult = <IIDBOpenEventTargetWithResult>event.target;
26
+ const database: IDBDatabase = target.result;
27
+
28
+ // close db and resolve new db instance on version change
29
+ database.onversionchange = (event: IDBVersionChangeEvent) => {
30
+ this.dbVersionChangeHandler(database, event);
31
+ };
32
+
33
+ resolve(database);
34
+ }
35
+
36
+ /**
37
+ * Need upgrade database version handler
38
+ * @param event
39
+ */
40
+ private dbRequestUpgradeNeededHandler(event: Event) {
41
+ const target: IIDBOpenEventTargetWithResult = <IIDBOpenEventTargetWithResult>event.target;
42
+ const database: IDBDatabase = target.result;
43
+
44
+ // close db and resolve new db instance on version change
45
+ database.onversionchange = (event: IDBVersionChangeEvent) => {
46
+ this.dbVersionChangeHandler(database, event);
47
+ };
48
+
49
+ // apply migrations
50
+ const migrationExecutor = new MigrationExecutor(database);
51
+ migrationExecutor.applyMigrations();
52
+ }
53
+
54
+ /**
55
+ * Open db
56
+ */
57
+ getDB(): Promise<IDBDatabase> {
58
+ return new Promise<IDBDatabase>((resolve, reject) => {
59
+ const request: IDBOpenDBRequest = indexedDB.open('PUSHWOOSH_SDK_STORE', dbVersion);
60
+
61
+ request.onsuccess = (event: Event) => {
62
+ this.dbRequestSuccessHandler(resolve, event); // Existing db without updates
63
+ };
64
+ request.onupgradeneeded = (event: Event) => {
65
+ this.dbRequestUpgradeNeededHandler(event); // Upgrade DB
66
+ };
67
+ request.onerror = () => reject(request.error); // Handle errors
68
+ });
69
+ }
70
+
71
+ /**
72
+ * https://developer.mozilla.org/en-US/docs/Web/API/IDBObjectStore/put
73
+ * @param storeName
74
+ * @param data
75
+ * @param key
76
+ */
77
+ async put(storeName: TSdkStoreName, data: any, key?: string) {
78
+ const db = await this.getDB();
79
+ const store = new Store(db, storeName);
80
+ const result = await store.put(data, key);
81
+ db.close();
82
+ return result;
83
+ }
84
+
85
+ /**
86
+ * https://developer.mozilla.org/en-US/docs/Web/API/IDBObjectStore/delete
87
+ * @param storeName
88
+ * @param key
89
+ */
90
+ async delete(storeName: TSdkStoreName, key: string | number) {
91
+ const db = await this.getDB();
92
+ const store = new Store(db, storeName);
93
+ const result = await store.delete(key);
94
+ db.close();
95
+ return result;
96
+ }
97
+
98
+ /**
99
+ * https://developer.mozilla.org/en-US/docs/Web/API/IDBObjectStore/get
100
+ * @param storeName
101
+ * @param key
102
+ * @param defaultValue
103
+ */
104
+ async get<Response, D>(
105
+ storeName: TSdkStoreName,
106
+ key: TIDBKeyType,
107
+ defaultValue?: D,
108
+ ): Promise<Response | D> {
109
+ const db = await this.getDB();
110
+ const store = new Store(db, storeName);
111
+ const result = await store.get<Response, D>(key, defaultValue);
112
+ db.close();
113
+ return result;
114
+ }
115
+
116
+ /**
117
+ * https://developer.mozilla.org/en-US/docs/Web/API/IDBObjectStore/getAll
118
+ * @param storeName
119
+ */
120
+ async getAll<Response>(
121
+ storeName: TSdkStoreName,
122
+ ): Promise<Array<Response>> {
123
+ const db = await this.getDB();
124
+ const store = new Store(db, storeName);
125
+ const result = await store.getAll<Response>();
126
+ db.close();
127
+ return result || [];
128
+ }
129
+
130
+ /**
131
+ * https://developer.mozilla.org/en-US/docs/Web/API/IDBObjectStore/count
132
+ * @param storeName
133
+ * @param query
134
+ */
135
+ async count(
136
+ storeName: TSdkStoreName,
137
+ query?: IDBKeyRange,
138
+ ): Promise<number> {
139
+ const db = await this.getDB();
140
+ const store = new Store(db, storeName);
141
+ const result = await store.count(query);
142
+ db.close();
143
+ return result;
144
+ }
145
+
146
+ /**
147
+ * https://developer.mozilla.org/en-US/docs/Web/API/IDBIndex/count
148
+ * @param storeName
149
+ * @param indexName
150
+ * @param key
151
+ */
152
+ async countByIndex(
153
+ storeName: TSdkStoreName,
154
+ indexName: string,
155
+ key?: TIDBQueryValue,
156
+ ): Promise<number> {
157
+ const db = await this.getDB();
158
+ const store = new Store(db, storeName);
159
+ store.index = indexName;
160
+ const result = await store.countByIndex(key);
161
+ db.close();
162
+ return result;
163
+ }
164
+ }
@@ -0,0 +1,54 @@
1
+ export type TKeyValueStoreName = 'keyValue';
2
+ export type TMessageLogStoreName = 'messages';
3
+ export type TMainLogStoreName = 'log';
4
+ export type TInboxMessagesStoreName = 'inboxMessages';
5
+ export type TSdkStoreName =
6
+ | TKeyValueStoreName
7
+ | TMessageLogStoreName
8
+ | TInboxMessagesStoreName
9
+ | TMainLogStoreName;
10
+
11
+ export type TMigrationType = (database: IDBDatabase) => void;
12
+
13
+ export type TMigrationsObjectType = {
14
+ initial: Array<TMigrationType>;
15
+ [date: string]: Array<TMigrationType>; // date in YYYY/MM/DD format
16
+ };
17
+
18
+ export interface IIDBOpenEventTargetWithResult extends EventTarget {
19
+ result: IDBDatabase;
20
+ }
21
+
22
+ export interface IIDBGetTransactionEventTargetWithResult extends EventTarget {
23
+ result: any;
24
+ }
25
+
26
+ export type TIDBKeyType = string | number | Date;
27
+ export type TIDBQueryValue = TIDBKeyType | IDBKeyRange;
28
+
29
+ export interface IDBIndex {
30
+ getAll(query?: TIDBQueryValue, count?: number): IDBRequest;
31
+ }
32
+
33
+ export interface IDBObjectStore {
34
+ getAll(query?: TIDBQueryValue, count?: number): IDBRequest;
35
+ }
36
+
37
+ // KeyValue Keys
38
+
39
+ export type TIDBAppCodeKey = 'params.applicationCode';
40
+ export type TIDBApiUrlKey = 'params.apiUrl';
41
+ export type TIDBHwidKey = 'params.hwid';
42
+ export type TIDBDefaultNotificationImageKey = 'params.defaultNotificationImage';
43
+ export type TIDBDefaultNotificationTitleKey = 'params.defaultNotificationTitle';
44
+ export type TIDBUserIdKey = 'params.userId';
45
+ export type TIDBUserIdWasChangedKey = 'params.userIdWasChanged';
46
+ export type TIDBDeviceType = 'params.deviceType';
47
+
48
+ export type TSubscriptionPopupLastOpen = 'params.subscriptionPopupLastOpen';
49
+
50
+ export type TIDBInboxLastRequestCodeKey = 'inbox.lastRequestCode';
51
+ export type TIDBInboxLastRequestTimeKey = 'inbox.lastRequestTime';
52
+ export type TIDBInboxNewMessagesCountKey = 'inbox.newMessagesCount';
53
+
54
+ ///////////////////