@suprsend/web-sdk 1.5.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +182 -16
- package/dist/cjs/index.cjs +2 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/es/index.js +1111 -0
- package/dist/es/index.js.map +1 -0
- package/dist/types/api.d.ts +14 -0
- package/dist/types/index.d.ts +45 -0
- package/dist/types/interface.d.ts +89 -0
- package/dist/types/preferences.d.ts +63 -0
- package/dist/types/user.d.ts +82 -0
- package/dist/types/utils.d.ts +14 -0
- package/dist/types/webpush.d.ts +25 -0
- package/package.json +42 -21
- package/public/serviceworker.js +141 -0
- package/babel.config.json +0 -4
- package/dist/cdn_bundle.js +0 -2
- package/dist/cdn_bundle.js.LICENSE.txt +0 -1
- package/dist/cjs_bundle.js +0 -2
- package/dist/cjs_bundle.js.LICENSE.txt +0 -1
- package/serviceworker/serviceworker.js +0 -152
- package/src/config.js +0 -13
- package/src/constants.js +0 -50
- package/src/encryption.js +0 -44
- package/src/errors.js +0 -20
- package/src/index.d.ts +0 -180
- package/src/index.js +0 -182
- package/src/preferences.js +0 -505
- package/src/user.js +0 -196
- package/src/utils.js +0 -318
- package/src/web_push.js +0 -138
- package/webpack.config.js +0 -29
package/src/utils.js
DELETED
|
@@ -1,318 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
browser_useragent_map,
|
|
3
|
-
browser_version_useragent_map,
|
|
4
|
-
os_useragent_map,
|
|
5
|
-
constants,
|
|
6
|
-
internal_events,
|
|
7
|
-
} from "./constants";
|
|
8
|
-
import config from "./config";
|
|
9
|
-
import create_signature from "./encryption";
|
|
10
|
-
|
|
11
|
-
function uuid() {
|
|
12
|
-
var dt = new Date().getTime();
|
|
13
|
-
var uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(
|
|
14
|
-
/[xy]/g,
|
|
15
|
-
function (c) {
|
|
16
|
-
var r = (dt + Math.random() * 16) % 16 | 0;
|
|
17
|
-
dt = Math.floor(dt / 16);
|
|
18
|
-
return (c == "x" ? r : (r & 0x3) | 0x8).toString(16);
|
|
19
|
-
}
|
|
20
|
-
);
|
|
21
|
-
return uuid;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function epoch_milliseconds() {
|
|
25
|
-
return Math.round(Date.now());
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function cookie_enabled() {
|
|
29
|
-
return navigator.cookieEnabled;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function set_cookie(name, value, days = 365) {
|
|
33
|
-
var expires = "";
|
|
34
|
-
if (days) {
|
|
35
|
-
var date = new Date();
|
|
36
|
-
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
|
|
37
|
-
expires = "; expires=" + date.toUTCString();
|
|
38
|
-
}
|
|
39
|
-
document.cookie = name + "=" + (value || "") + expires + "; path=/";
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function get_cookie(name) {
|
|
43
|
-
var nameEQ = name + "=";
|
|
44
|
-
var ca = document.cookie.split(";");
|
|
45
|
-
for (var i = 0; i < ca.length; i++) {
|
|
46
|
-
var c = ca[i];
|
|
47
|
-
while (c.charAt(0) == " ") c = c.substring(1, c.length);
|
|
48
|
-
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
|
|
49
|
-
}
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function remove_cookie(name) {
|
|
54
|
-
document.cookie = name + "=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;";
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function local_storage_enabled() {
|
|
58
|
-
let enabled = true;
|
|
59
|
-
try {
|
|
60
|
-
!!window.localStorage;
|
|
61
|
-
} catch (err) {
|
|
62
|
-
enabled = false;
|
|
63
|
-
}
|
|
64
|
-
return enabled;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function get_local_storage_item(key) {
|
|
68
|
-
if (local_storage_enabled()) {
|
|
69
|
-
return localStorage.getItem(key);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function set_local_storage_item(key, value) {
|
|
74
|
-
if (local_storage_enabled()) {
|
|
75
|
-
localStorage.setItem(key, value);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function remove_local_storage_item(key) {
|
|
80
|
-
if (local_storage_enabled()) {
|
|
81
|
-
localStorage.removeItem(key);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function get_parsed_local_store_data(key, default_value = {}) {
|
|
86
|
-
let existing_data = get_local_storage_item(key);
|
|
87
|
-
existing_data = existing_data ? JSON.parse(existing_data) : default_value;
|
|
88
|
-
return existing_data;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function browser() {
|
|
92
|
-
const userAgent = navigator.userAgent;
|
|
93
|
-
for (let browser_item in browser_useragent_map) {
|
|
94
|
-
for (let str of browser_useragent_map[browser_item]) {
|
|
95
|
-
if (userAgent.indexOf(str) >= 0) {
|
|
96
|
-
return browser_item;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return "";
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function browser_version() {
|
|
104
|
-
const userAgent = navigator.userAgent;
|
|
105
|
-
const browser_name = browser();
|
|
106
|
-
const regexItems = browser_version_useragent_map[browser_name];
|
|
107
|
-
|
|
108
|
-
if (!regexItems || !browser_name) return "";
|
|
109
|
-
|
|
110
|
-
for (let regex_item of regexItems) {
|
|
111
|
-
const regex = regex_item;
|
|
112
|
-
if (regex) {
|
|
113
|
-
const result = userAgent.match(regex);
|
|
114
|
-
if (result && result.length > 1) {
|
|
115
|
-
return result[1];
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return "";
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function os() {
|
|
123
|
-
const userAgent = navigator.userAgent;
|
|
124
|
-
for (let i in os_useragent_map) {
|
|
125
|
-
if (userAgent.indexOf(os_useragent_map[i]) >= 0) {
|
|
126
|
-
return i;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
return "";
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
async function api(route, body, method = "POST") {
|
|
133
|
-
const requested_date = new Date().toGMTString();
|
|
134
|
-
const req_body = JSON.stringify(body);
|
|
135
|
-
const sign = await create_signature(req_body, requested_date, "POST");
|
|
136
|
-
const authorization = sign ? `${config.env_key}:${sign}` : config.env_key;
|
|
137
|
-
return fetch(`${config.api_url}/${route}`, {
|
|
138
|
-
method: method,
|
|
139
|
-
body: req_body,
|
|
140
|
-
headers: {
|
|
141
|
-
"Content-Type": "application/json",
|
|
142
|
-
Authorization: authorization,
|
|
143
|
-
"x-amz-date": requested_date,
|
|
144
|
-
},
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/*
|
|
149
|
-
1. get data from local storage
|
|
150
|
-
2. if data is present create first batch data and call api else schedule next flush
|
|
151
|
-
3. if the above api call is success call next api call with next set of data if it exists
|
|
152
|
-
4. If there is any error in api call then schedule flush after 2min
|
|
153
|
-
*/
|
|
154
|
-
function bulk_call_api() {
|
|
155
|
-
const items = get_parsed_local_store_data(constants.bulk_events_key, []);
|
|
156
|
-
if (items.length) {
|
|
157
|
-
const batch = items.slice(0, config.batch_size);
|
|
158
|
-
api(constants.api_events_route, batch)
|
|
159
|
-
.then((res) => {
|
|
160
|
-
if (!res.ok) {
|
|
161
|
-
throw new Error("Error in Fetch");
|
|
162
|
-
}
|
|
163
|
-
let items = get_parsed_local_store_data(constants.bulk_events_key, []);
|
|
164
|
-
items.splice(0, config.batch_size);
|
|
165
|
-
set_local_storage_item(
|
|
166
|
-
constants.bulk_events_key,
|
|
167
|
-
JSON.stringify(items)
|
|
168
|
-
);
|
|
169
|
-
bulk_call_api();
|
|
170
|
-
})
|
|
171
|
-
.catch(() => {
|
|
172
|
-
schedule_flush(2 * 60 * 1000);
|
|
173
|
-
});
|
|
174
|
-
} else {
|
|
175
|
-
schedule_flush();
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/*
|
|
180
|
-
schedule the flush in some time future
|
|
181
|
-
*/
|
|
182
|
-
function schedule_flush(delay = config.flush_interval) {
|
|
183
|
-
setTimeout(() => {
|
|
184
|
-
bulk_call_api();
|
|
185
|
-
}, delay);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/*
|
|
189
|
-
local storage enabled => add it to local storage which will be picked by continuous flusher
|
|
190
|
-
local storage disabled => call the api directly
|
|
191
|
-
*/
|
|
192
|
-
function batch_or_call(body) {
|
|
193
|
-
if (local_storage_enabled()) {
|
|
194
|
-
let parsed_data = get_parsed_local_store_data(
|
|
195
|
-
constants.bulk_events_key,
|
|
196
|
-
[]
|
|
197
|
-
);
|
|
198
|
-
parsed_data?.push(body);
|
|
199
|
-
set_local_storage_item(
|
|
200
|
-
constants.bulk_events_key,
|
|
201
|
-
JSON.stringify(parsed_data)
|
|
202
|
-
);
|
|
203
|
-
} else {
|
|
204
|
-
api(constants.api_events_route, body);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
function format_props({ key, value, allow_special_tags = false }) {
|
|
209
|
-
var formatted_data;
|
|
210
|
-
if (key instanceof Object) {
|
|
211
|
-
formatted_data = {};
|
|
212
|
-
for (let item in key) {
|
|
213
|
-
if (key[item] !== undefined) {
|
|
214
|
-
if (!allow_special_tags && has_special_char(item)) {
|
|
215
|
-
console.log("SuprSend: key cannot start with $ or ss_");
|
|
216
|
-
continue;
|
|
217
|
-
}
|
|
218
|
-
formatted_data[String(item)] = key[item];
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
} else if (value != undefined) {
|
|
222
|
-
if (!allow_special_tags && has_special_char(String(key))) {
|
|
223
|
-
console.log("SuprSend: key cannot start with $ or ss_");
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
formatted_data = { [String(key)]: value };
|
|
227
|
-
}
|
|
228
|
-
return formatted_data;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
function urlB64ToUint8Array(base64String) {
|
|
232
|
-
const padding = "=".repeat((4 - (base64String.length % 4)) % 4);
|
|
233
|
-
const base64 = (base64String + padding)
|
|
234
|
-
.replace(/\-/g, "+")
|
|
235
|
-
.replace(/_/g, "/");
|
|
236
|
-
const rawData = window.atob(base64);
|
|
237
|
-
const outputArray = new Uint8Array(rawData.length);
|
|
238
|
-
for (let i = 0; i < rawData.length; ++i) {
|
|
239
|
-
outputArray[i] = rawData.charCodeAt(i);
|
|
240
|
-
}
|
|
241
|
-
return outputArray;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
const has_special_char = (str) => {
|
|
245
|
-
return str.startsWith("$") || str?.toLowerCase()?.startsWith("ss_");
|
|
246
|
-
};
|
|
247
|
-
|
|
248
|
-
const is_internal_event = (event) => {
|
|
249
|
-
const internal_events_list = Object.values(internal_events);
|
|
250
|
-
return internal_events_list.includes(event);
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
const is_empty = (value) => {
|
|
254
|
-
if (Array.isArray(value)) {
|
|
255
|
-
return value.length === 0;
|
|
256
|
-
} else if (value instanceof Object) {
|
|
257
|
-
return Object.keys(value).length === 0;
|
|
258
|
-
} else {
|
|
259
|
-
const empty_values = ["", null, undefined];
|
|
260
|
-
return empty_values.includes(value);
|
|
261
|
-
}
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
function debounce(func, timeOut) {
|
|
265
|
-
let timer;
|
|
266
|
-
|
|
267
|
-
return (...args) => {
|
|
268
|
-
if (timer) clearTimeout(timer);
|
|
269
|
-
timer = setTimeout(() => {
|
|
270
|
-
func.apply(this, args);
|
|
271
|
-
}, timeOut);
|
|
272
|
-
return timer;
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// https://gist.github.com/nzvtrk/1a444cdf6a86a5a6e6d6a34f0db19065
|
|
277
|
-
function debounce_by_type(func, wait, options) {
|
|
278
|
-
const memory = {};
|
|
279
|
-
|
|
280
|
-
return (...args) => {
|
|
281
|
-
const [searchType] = args;
|
|
282
|
-
const payload = args.slice(1);
|
|
283
|
-
|
|
284
|
-
if (typeof memory[searchType] === "function") {
|
|
285
|
-
return memory[searchType](...payload);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
memory[searchType] = debounce(func, wait, { ...options, leading: true });
|
|
289
|
-
return memory[searchType](...payload);
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
export default {
|
|
294
|
-
uuid,
|
|
295
|
-
epoch_milliseconds,
|
|
296
|
-
cookie_enabled,
|
|
297
|
-
set_cookie,
|
|
298
|
-
get_cookie,
|
|
299
|
-
remove_cookie,
|
|
300
|
-
local_storage_enabled,
|
|
301
|
-
get_local_storage_item,
|
|
302
|
-
set_local_storage_item,
|
|
303
|
-
remove_local_storage_item,
|
|
304
|
-
get_parsed_local_store_data,
|
|
305
|
-
browser,
|
|
306
|
-
browser_version,
|
|
307
|
-
os,
|
|
308
|
-
schedule_flush,
|
|
309
|
-
format_props,
|
|
310
|
-
urlB64ToUint8Array,
|
|
311
|
-
batch_or_call,
|
|
312
|
-
has_special_char,
|
|
313
|
-
is_empty,
|
|
314
|
-
bulk_call_api,
|
|
315
|
-
is_internal_event,
|
|
316
|
-
api,
|
|
317
|
-
debounce_by_type,
|
|
318
|
-
};
|
package/src/web_push.js
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import utils from "./utils";
|
|
2
|
-
import config from "./config";
|
|
3
|
-
import User from "./user";
|
|
4
|
-
import { initialisedAt } from "./index";
|
|
5
|
-
|
|
6
|
-
var notification_timer;
|
|
7
|
-
class WebPush {
|
|
8
|
-
constructor(instance) {
|
|
9
|
-
this.instance = instance;
|
|
10
|
-
this.user = new User(instance);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
_check_push_support = () => {
|
|
14
|
-
return !!("serviceWorker" in navigator && "PushManager" in window);
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
_ask_notification_permission = async () =>
|
|
18
|
-
await Notification.requestPermission();
|
|
19
|
-
|
|
20
|
-
_register_sw = () => {
|
|
21
|
-
return navigator.serviceWorker
|
|
22
|
-
.register(`/${config.service_worker_file}`)
|
|
23
|
-
.then((registration) => {
|
|
24
|
-
this._subscribe_push(registration);
|
|
25
|
-
})
|
|
26
|
-
.catch((err) => {
|
|
27
|
-
console.error("SuprSend: Unable to register service worker.", err);
|
|
28
|
-
});
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
_get_subscription_without_wait = async () => {
|
|
32
|
-
const registration = await navigator.serviceWorker.getRegistration();
|
|
33
|
-
if (!registration) return;
|
|
34
|
-
|
|
35
|
-
return registration.pushManager
|
|
36
|
-
.getSubscription()
|
|
37
|
-
.then(async (subscription) => {
|
|
38
|
-
if (!subscription) return;
|
|
39
|
-
return subscription;
|
|
40
|
-
});
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
_get_subscription = () => {
|
|
44
|
-
return navigator.serviceWorker.ready
|
|
45
|
-
.then((registration) => {
|
|
46
|
-
return registration.pushManager.getSubscription();
|
|
47
|
-
})
|
|
48
|
-
.then(async (subscription) => {
|
|
49
|
-
if (!subscription) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
return subscription;
|
|
53
|
-
});
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
// this method make sure there is a given delay, as calling notification permission just after load is not good UX practice
|
|
57
|
-
_subscribe_with_delay() {
|
|
58
|
-
const now = new Date();
|
|
59
|
-
const delay = now - initialisedAt;
|
|
60
|
-
const has_delay = delay >= config.sw_delay;
|
|
61
|
-
if (has_delay) {
|
|
62
|
-
this._register_sw();
|
|
63
|
-
} else {
|
|
64
|
-
clearTimeout(notification_timer);
|
|
65
|
-
notification_timer = setTimeout(() => {
|
|
66
|
-
this._register_sw();
|
|
67
|
-
}, config.sw_delay - delay);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// 1. ask permission.
|
|
72
|
-
// 2. if permission is granted then check if its already subscribed.
|
|
73
|
-
// 3. if not subscribed already then subscribe to push.
|
|
74
|
-
_subscribe_push = async (reg) => {
|
|
75
|
-
const permission = await this._ask_notification_permission();
|
|
76
|
-
if (permission === "granted") {
|
|
77
|
-
const subscription = await this._get_subscription();
|
|
78
|
-
if (!subscription) {
|
|
79
|
-
if (!config.vapid_key) {
|
|
80
|
-
console.log("SuprSend: Provide vapid key while calling init");
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
const applicationServerKey = utils.urlB64ToUint8Array(config.vapid_key);
|
|
84
|
-
const subscription = await reg.pushManager.subscribe({
|
|
85
|
-
applicationServerKey,
|
|
86
|
-
userVisibleOnly: true,
|
|
87
|
-
});
|
|
88
|
-
this.user.add_webpush(subscription);
|
|
89
|
-
} else {
|
|
90
|
-
// pass
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
update_subscription() {
|
|
96
|
-
navigator?.serviceWorker?.ready
|
|
97
|
-
.then((registration) => {
|
|
98
|
-
return registration.pushManager.getSubscription();
|
|
99
|
-
})
|
|
100
|
-
.then((subscription) => {
|
|
101
|
-
if (!subscription) {
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
this.user.add_webpush(subscription);
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
register_push = () => {
|
|
109
|
-
if (this._check_push_support()) {
|
|
110
|
-
this._subscribe_with_delay();
|
|
111
|
-
} else {
|
|
112
|
-
console.log("SuprSend: Web Push isn't supported");
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
is_subscribed = async () => {
|
|
117
|
-
const subscription = await this._get_subscription_without_wait();
|
|
118
|
-
return !!subscription;
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
notification_permission() {
|
|
122
|
-
return Notification.permission;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// unsubscribe_push = () => {
|
|
126
|
-
// navigator.serviceWorker.ready
|
|
127
|
-
// .then((registration) => {
|
|
128
|
-
// return registration.pushManager.getSubscription();
|
|
129
|
-
// })
|
|
130
|
-
// .then((subscription) => {
|
|
131
|
-
// return subscription.unsubscribe().then(() => {
|
|
132
|
-
// console.log("API_CALL: unsubscription");
|
|
133
|
-
// });
|
|
134
|
-
// });
|
|
135
|
-
// };
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export default WebPush;
|
package/webpack.config.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
const path = require("path");
|
|
2
|
-
|
|
3
|
-
module.exports = (env) => {
|
|
4
|
-
let library_info = { type: env.module_type };
|
|
5
|
-
if (env.module_type === "window") {
|
|
6
|
-
library_info.name = "suprsend";
|
|
7
|
-
}
|
|
8
|
-
return {
|
|
9
|
-
entry: path.resolve(__dirname, "src/index.js"),
|
|
10
|
-
mode: "production",
|
|
11
|
-
output: {
|
|
12
|
-
filename: env.filename,
|
|
13
|
-
path: path.resolve(__dirname, "dist"),
|
|
14
|
-
library: library_info,
|
|
15
|
-
environment: {
|
|
16
|
-
arrowFunction: false,
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
module: {
|
|
20
|
-
rules: [
|
|
21
|
-
{
|
|
22
|
-
test: /\.(js)$/,
|
|
23
|
-
exclude: /node_modules/,
|
|
24
|
-
use: "babel-loader",
|
|
25
|
-
},
|
|
26
|
-
],
|
|
27
|
-
},
|
|
28
|
-
};
|
|
29
|
-
};
|