@suprsend/web-sdk 1.5.1 → 2.0.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.
- package/README.md +189 -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/README.md
CHANGED
|
@@ -1,33 +1,206 @@
|
|
|
1
|
-
#
|
|
1
|
+
# SuprSend Javascript Web SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This library is used to integrate SuprSend features like WebPush, Preferences in to your javascript client environments.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
> 📘 This is v2 version of @suprsend/web-sdk
|
|
6
|
+
>
|
|
7
|
+
> We have changed the web SDK authentication from workspace key-secret to public key and JWT based authentication. This is done to improve security in frontend applications.
|
|
8
|
+
>
|
|
9
|
+
> - Refer the v1 SDK [documentation](https://docs.suprsend.com/v1.2.1/docs/javascript-sdk)
|
|
10
|
+
> - For migrating to v2, follow this [guide](https://docs.suprsend.com/docs/js-migration-from-v1)
|
|
11
|
+
|
|
12
|
+
## Documentation
|
|
6
13
|
|
|
7
|
-
|
|
14
|
+
Checkout detailed [documentation](https://docs.suprsend.com/docs/javascript-sdk) for this library.
|
|
8
15
|
|
|
9
|
-
|
|
16
|
+
## Installation
|
|
10
17
|
|
|
11
18
|
```bash
|
|
12
|
-
|
|
19
|
+
# using npm
|
|
20
|
+
npm install @suprsend/web-sdk@latest
|
|
21
|
+
|
|
22
|
+
# using yarn
|
|
23
|
+
yarn add @suprsend/web-sdk@latest
|
|
13
24
|
```
|
|
14
25
|
|
|
15
|
-
|
|
26
|
+
## Integration
|
|
16
27
|
|
|
17
|
-
|
|
18
|
-
|
|
28
|
+
### 1. Create Client
|
|
29
|
+
|
|
30
|
+
Create suprSendClient instance and use same instance to access all the methods of SuprSend library.
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import SuprSend from '@suprsend/web-sdk';
|
|
34
|
+
|
|
35
|
+
export const suprSendClient = new SuprSend(publicApiKey: string);
|
|
19
36
|
```
|
|
20
37
|
|
|
21
|
-
|
|
38
|
+
| Params | Description |
|
|
39
|
+
| :------------- | :----------------------------------------------------------------------------------------------------------------------------- |
|
|
40
|
+
| publicApiKey\* | This is public Key used to authenticate api calls to SuprSend. Get it in SuprSend dashboard **ApiKeys -> Public Keys** section |
|
|
22
41
|
|
|
23
|
-
|
|
42
|
+
### 2. Authenticate user
|
|
24
43
|
|
|
25
|
-
|
|
26
|
-
import suprsend from "@suprsend/web-sdk";
|
|
44
|
+
Authenticate user so that all the actions performed after authenticating will be w.r.t that user. This is mandatory step and need to be called before using any other method. This is usually performed after successful login and on reload of page to re-authenticate user (can be changed based on your requirement).
|
|
27
45
|
|
|
28
|
-
|
|
46
|
+
```typescript
|
|
47
|
+
const authResponse = await suprSendClient.identify(
|
|
48
|
+
distinctId: any,
|
|
49
|
+
userToken?: string, // only needed in production environments for security
|
|
50
|
+
{ refreshUserToken: (oldUserToken: string, tokenPayload: Dictionary) => Promise<string> }
|
|
51
|
+
);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
| Properties | Description |
|
|
55
|
+
| :--------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
56
|
+
| distinctId\* | Unique identifier to identify a user across platform. |
|
|
57
|
+
| userToken | Mandatory when enhanced security mode is on. This is ES256 JWT token generated in your server-side. Refer [docs](https://docs.suprsend.com/docs/client-authentication#enhanced-security-mode-with-signed-user-token) to create userToken. |
|
|
58
|
+
| refreshUserToken | This function is called by SDK internally to get new userToken before existing token is expired. The returned string is used as the new userToken. |
|
|
59
|
+
|
|
60
|
+
### 3. Reset user
|
|
61
|
+
|
|
62
|
+
This will remove user data from SuprSend instance similar to logout action.
|
|
29
63
|
|
|
30
|
-
|
|
64
|
+
```typescript
|
|
65
|
+
await suprSendClient.reset();
|
|
31
66
|
```
|
|
32
67
|
|
|
33
|
-
|
|
68
|
+
## User Methods
|
|
69
|
+
|
|
70
|
+
Use these methods to manipulate user properties and notification channel data of user
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
await suprSendClient.user.addEmail(email: string)
|
|
74
|
+
await suprSendClient.user.removeEmail(email: string)
|
|
75
|
+
|
|
76
|
+
// mobile should be as per E.164 standard
|
|
77
|
+
await suprSendClient.user.addSms(mobile: string)
|
|
78
|
+
await suprSendClient.user.removeSms(mobile: string)
|
|
79
|
+
|
|
80
|
+
// mobile should be as per E.164 standard
|
|
81
|
+
await suprSendClient.user.addWhatsapp(mobile: string)
|
|
82
|
+
await suprSendClient.user.removeWhatsapp(mobile: string)
|
|
83
|
+
|
|
84
|
+
// set custom user properties
|
|
85
|
+
await suprSendClient.user.set(arg1: string | Dictionary, arg2?: unknown)
|
|
86
|
+
|
|
87
|
+
// set properties only once that cannot be overridden
|
|
88
|
+
await suprSendClient.user.setOnce(arg1: string | Dictionary, arg2?: unknown)
|
|
89
|
+
|
|
90
|
+
// increase or decrease property by given value
|
|
91
|
+
await suprSendClient.user.increment(arg1: string | Dictionary, arg2?: number)
|
|
92
|
+
|
|
93
|
+
// Add items to list if user property is list
|
|
94
|
+
await suprSend.user.append(arg1: string | Dictionary, arg2?: unknown)
|
|
95
|
+
|
|
96
|
+
// Remove items from list if user property is list.
|
|
97
|
+
await suprSend.user.remove(arg1: string | Dictionary, arg2?: unknown)
|
|
98
|
+
|
|
99
|
+
// remove user property. If channel needs to be removed pass $email, $sms, $whatsapp
|
|
100
|
+
await suprSend.user.unset(arg: string | string[])
|
|
101
|
+
|
|
102
|
+
//2-letter language code in "ISO 639-1 Alpha-2" format e.g. en (for English)
|
|
103
|
+
await suprSendClient.user.setPreferredLanguage(language: string)
|
|
104
|
+
|
|
105
|
+
// set timezone property at user level in IANA timezone format
|
|
106
|
+
await suprSendClient.user.setTimezone(timezone: string)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Triggering Events
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
const response = await suprSendClient.track(event: string, properties?: Dictionary)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Webpush Setup
|
|
116
|
+
|
|
117
|
+
### 1. Configuration
|
|
118
|
+
|
|
119
|
+
While creating SuprSend instance you have to pass vapidKey (get it in SuprSend Dashboard --> Vendors --> WebPush).
|
|
120
|
+
|
|
121
|
+
If you want to customise serviceworker file name instead of `serviceworker.js`, you can pass name of it in `swFileName`.
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
new SuprSend(publicApiKey: string, {vapidKey?: string, swFileName?: string})
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 2. Add ServiceWorker file
|
|
128
|
+
|
|
129
|
+
Service worker file is the background worker script which handles push notifications.
|
|
130
|
+
|
|
131
|
+
Create `serviceworker.js` file such that it should be publicly accessible from `https://<your_domain>/serviceworker.js`. Then include below lines of code and replace publicApiKey with key you find in API Keys page in SuprSend Dashboard.
|
|
132
|
+
|
|
133
|
+
```javascript
|
|
134
|
+
importScripts(
|
|
135
|
+
'https://cdn.jsdelivr.net/npm/@suprsend/web-sdk@2.0.0/public/serviceworker.min.js'
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
initSuprSend(publicApiKey);
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 3. Register Push
|
|
142
|
+
|
|
143
|
+
Call `registerPush` in your code, which will perform following tasks:
|
|
144
|
+
|
|
145
|
+
- Ask for notification permission.
|
|
146
|
+
- Register push service and generate webpush token.
|
|
147
|
+
- Send webpush token to SuprSend.
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
const response = await suprSendClient.webpush.registerPush();
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Preferences
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
// get full user preferences data
|
|
157
|
+
const preferencesResp = await suprSendClient.user.preferences.getPreferences(args?: {tenantId?: string});
|
|
158
|
+
|
|
159
|
+
// update category level preference
|
|
160
|
+
const updatedPreferencesResp = await suprSendClient.user.preferences.updateCategoryPreference(category: string, preference: 'opt_in'|'opt_out', args?: { tenantId?: string });
|
|
161
|
+
|
|
162
|
+
// update category level channel preference
|
|
163
|
+
const updatedPreferencesResp = await suprSendClient.user.preferences.updateChannelPreferenceInCategory(channel: string, preference: 'opt_in'|'opt_out', category: string, args?: { tenantId?: string });
|
|
164
|
+
|
|
165
|
+
// update overall channel level preference
|
|
166
|
+
const updatedPreferencesResp = await suprSendClient.user.preferences.updateOverallChannelPreference(channel: string, preference: 'all'|'required');
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
All preferences update api's are optimistic updates. Actual api call will happen in background with 1 second debounce. Since its a background task SDK also provides event listener to get updated preference data based on api call status.
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
// listen for update in preferences data and update your UI accordingly in callback
|
|
173
|
+
suprSendClient.emitter.on('preferences_updated', (preferenceDataResp) => void);
|
|
174
|
+
|
|
175
|
+
// listen for errors and show error state like toast etc
|
|
176
|
+
suprSendClient.emitter.on('preferences_error', (errorResp) => void);
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Response Structure
|
|
180
|
+
|
|
181
|
+
Almost all methods of this library return `Promise<ApiResponse>`
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
interface ApiResponse {
|
|
185
|
+
status: 'success' | 'error';
|
|
186
|
+
statusCode?: number;
|
|
187
|
+
error?: { type?: string; message?: string };
|
|
188
|
+
body?: any;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// success response
|
|
192
|
+
{
|
|
193
|
+
status: "success",
|
|
194
|
+
body?: any,
|
|
195
|
+
statusCode?: number
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// error response
|
|
199
|
+
{
|
|
200
|
+
status: "error",
|
|
201
|
+
error: {
|
|
202
|
+
type: string,
|
|
203
|
+
message: string
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
```
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var x=Object.defineProperty;var $=(i,e,t)=>e in i?x(i,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):i[e]=t;var d=(i,e,t)=>$(i,typeof e!="symbol"?e+"":e,t);Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});var p=(i=>(i.OPT_IN="opt_in",i.OPT_OUT="opt_out",i))(p||{}),E=(i=>(i.ALL="all",i.REQUIRED="required",i))(E||{}),o=(i=>(i.VALIDATION_ERROR="VALIDATION_ERROR",i.NETWORK_ERROR="NETWORK_ERROR",i.UNKNOWN_ERROR="UNKNOWN_ERROR",i.PERMISSION_DENIED="PERMISSION_DENIED",i.UNSUPPORTED_ACTION="UNSUPPORTED_ACTION",i))(o||{}),n=(i=>(i.SUCCESS="success",i.ERROR="error",i))(n||{});function b(){let i=new Date().getTime();return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(t){const r=(i+Math.random()*16)%16|0;return i=Math.floor(i/16),(t=="x"?r:r&3|8).toString(16)})}function C(){return Math.round(Date.now())}function f(i){return Object.keys(i).length===0}function j(i){return(i==null?void 0:i.length)<=0}function K(i){const e="=".repeat((4-i.length%4)%4),t=(i+e).replace(/-/g,"+").replace(/_/g,"/"),r=atob(t),s=new Uint8Array(r.length);for(let u=0;u<r.length;++u)s[u]=r.charCodeAt(u);return s}function W(i,e){let t;return(...r)=>(clearTimeout(t),new Promise(s=>{t=setTimeout(()=>s(i(...r)),e)}))}function N(i,e){const t={};return(...r)=>{const[s]=r,u=r.slice(1);return typeof t[s]=="function"?t[s](...u):(t[s]=W(i,e),t[s](...u))}}function a(i){const e={status:i.status};return i.statusCode&&(e.statusCode=i.statusCode),i.body&&(e.body=i.body),i.status===n.ERROR&&(e.error={type:i.errorType,message:i.errorMessage}),e}function g(){return typeof window<"u"}function M(i,e){g()&&(typeof e=="object"&&(e=JSON.stringify(e)),localStorage.setItem(i,e))}function V(i){if(!g())return;const e=localStorage.getItem(i);if(e)try{return JSON.parse(e)}catch{return e}}function F(i){g()&&localStorage.removeItem(i)}function P(i){this.message=i}P.prototype=new Error,P.prototype.name="InvalidCharacterError";var D=typeof window<"u"&&window.atob&&window.atob.bind(window)||function(i){var e=String(i).replace(/=+$/,"");if(e.length%4==1)throw new P("'atob' failed: The string to be decoded is not correctly encoded.");for(var t,r,s=0,u=0,c="";r=e.charAt(u++);~r&&(t=s%4?64*t+r:r,s++%4)?c+=String.fromCharCode(255&t>>(-2*s&6)):0)r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(r);return c};function H(i){var e=i.replace(/-/g,"+").replace(/_/g,"/");switch(e.length%4){case 0:break;case 2:e+="==";break;case 3:e+="=";break;default:throw"Illegal base64url string!"}try{return function(t){return decodeURIComponent(D(t).replace(/(.)/g,function(r,s){var u=s.charCodeAt(0).toString(16).toUpperCase();return u.length<2&&(u="0"+u),"%"+u}))}(e)}catch{return D(e)}}function _(i){this.message=i}function L(i,e){if(typeof i!="string")throw new _("Invalid token specified");var t=(e=e||{}).header===!0?0:1;try{return JSON.parse(H(i.split(".")[t]))}catch(r){throw new _("Invalid token specified: "+r.message)}}_.prototype=new Error,_.prototype.name="InvalidTokenError";class S{constructor(e){d(this,"config");this.config=e}getUrl(e){return`${this.config.host}/${e}`}getHeaders(){const e={"Content-Type":"application/json",Authorization:this.config.publicApiKey};return this.config.userToken&&(e["x-ss-signature"]=this.config.userToken),e}requestApiInstance(e){switch(e.type){case"get":return this.get(e.path);case"post":return this.post(e.path,(e==null?void 0:e.payload)||{});case"patch":return this.patch(e.path,(e==null?void 0:e.payload)||{});default:return this.get(e.path)}}get(e){const t=this.getUrl(e);return fetch(t,{method:"GET",headers:this.getHeaders()})}post(e,t){const r=this.getUrl(e);return fetch(r,{method:"POST",body:JSON.stringify(t),headers:this.getHeaders()})}patch(e,t){const r=this.getUrl(e);return fetch(r,{method:"PATCH",body:JSON.stringify(t),headers:this.getHeaders()})}async request(e){var t,r,s;if(!this.config.distinctId)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"User isn't authenticated. Call identify method before performing any action"});if((t=this.config.authenticateOptions)!=null&&t.refreshUserToken&&this.config.userToken){const u=L(this.config.userToken),c=(u.exp||0)*1e3,h=Date.now();if(c<=h)try{const R=await this.config.authenticateOptions.refreshUserToken(this.config.userToken,u);R&&typeof R=="string"&&this.config.identify(this.config.distinctId,R,this.config.authenticateOptions)}catch{}}try{const u=await this.requestApiInstance(e),c=await u.json(),h=(c==null?void 0:c.status)||(u.ok?n.SUCCESS:n.ERROR);return a({status:h,body:c,statusCode:u.status,errorMessage:(r=c==null?void 0:c.error)==null?void 0:r.message,errorType:(s=c==null?void 0:c.error)==null?void 0:s.type})}catch(u){return console.error(u),a({status:n.ERROR,statusCode:500,errorMessage:(u==null?void 0:u.message)||"network error",errorType:o.NETWORK_ERROR})}}}class Q{constructor(e){d(this,"config");d(this,"preferenceData");d(this,"preferenceArgs");d(this,"debouncedUpdateCategoryPreferences");d(this,"debouncedUpdateChannelPreferences");d(this,"debounceTime",1e3);this.config=e,this.debouncedUpdateCategoryPreferences=N(this._updateCategoryPreferences.bind(this),this.debounceTime),this.debouncedUpdateChannelPreferences=N(this._updateChannelPreferences.bind(this),this.debounceTime)}validateQueryParams(e={}){const t={};for(const r in e)e[r]&&(t[r]=String(e[r]));return t}set data(e){this.preferenceData=e}get data(){return this.preferenceData}getUrlPath(e,t){const r=`v2/subscriber/${this.config.distinctId}/${e}`,s=this.validateQueryParams(t),u=new URLSearchParams(s).toString();return u?`${r}/?${u}`:r}async getPreferences(e){const t={tenant_id:e==null?void 0:e.tenantId,show_opt_out_channels:(e==null?void 0:e.showOptOutChannels)!==!1};this.preferenceArgs={tenantId:t==null?void 0:t.tenant_id,showOptOutChannels:t==null?void 0:t.show_opt_out_channels};const r=this.getUrlPath("full_preference",t),s=await this.config.client().request({type:"get",path:r});return s.error||(this.data=s.body),s}async getCategories(e){const t={tenant_id:e==null?void 0:e.tenantId,show_opt_out_channels:(e==null?void 0:e.showOptOutChannels)!==!1,limit:e==null?void 0:e.limit,offset:e==null?void 0:e.offset},r=this.getUrlPath("category",t);return await this.config.client().request({type:"get",path:r})}async getCategory(e,t){if(!e)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"Category parameter is missing"});const r={tenant_id:t==null?void 0:t.tenantId,show_opt_out_channels:(t==null?void 0:t.showOptOutChannels)!==!1},s=this.getUrlPath(`category/${e}`,r);return await this.config.client().request({type:"get",path:s})}async getOverallChannelPreferences(){const e=this.getUrlPath("channel_preference");return await this.config.client().request({type:"get",path:e})}async _updateCategoryPreferences(e,t,r,s){const u=this.getUrlPath(`category/${e}`,s),c=await this.config.client().request({type:"patch",path:u,payload:t});return c!=null&&c.error?this.config.emitter.emit("preferences_error",c):(Object.assign(r,c.body),this.config.emitter.emit("preferences_updated",{status:n.SUCCESS,statusCode:200,body:this.data})),c}async _updateChannelPreferences(e){const t=this.getUrlPath("channel_preference"),r=await this.config.client().request({type:"patch",path:t,payload:e});return r!=null&&r.error?this.config.emitter.emit("preferences_error",r):(await this.getPreferences(this.preferenceArgs),this.config.emitter.emit("preferences_updated",{status:n.SUCCESS,statusCode:200,body:this.data})),r}async updateCategoryPreference(e,t,r){var R;if(!e||![p.OPT_IN,p.OPT_OUT].includes(t))return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:e?"Preference parameter is invalid":"Category parameter is missing"});if(!this.data)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"Call getPreferences method before performing action"});if(!this.data.sections)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"Sections doesn't exist"});let s=null,u=!1;for(const y of this.data.sections){let v=!1;if(y.subcategories){for(const l of y.subcategories)if(l.category===e)if(s=l,l.is_editable){if(l.preference!==t){l.preference=t,u=!0,v=!0;break}}else return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"Category preference is not editable"});if(v)break}}if(!s)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"Category not found"});if(!u)return a({status:n.SUCCESS,body:this.data});const c=[];(R=s==null?void 0:s.channels)==null||R.forEach(y=>{y.preference===p.OPT_OUT&&c.push(y.channel)});const h=(r==null?void 0:r.showOptOutChannels)!==!1,O={preference:s.preference,opt_out_channels:h&&t===p.OPT_IN?null:c};return this.debouncedUpdateCategoryPreferences(e,e,O,s,{tenant_id:r==null?void 0:r.tenantId,show_opt_out_channels:h}),a({status:n.SUCCESS,body:this.data})}async updateChannelPreferenceInCategory(e,t,r,s){var l;if(!e||!r)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:e?"Category parameter is missing":"Channel parameter is missing"});if(![p.OPT_IN,p.OPT_OUT].includes(t))return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"Preference parameter is invalid"});if(!this.data)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"Call getPreferences method before performing action"});if(!this.data.sections)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"Sections doesn't exist"});let u=null,c=null,h=!1;for(const T of this.data.sections){let A=!1;if(T.subcategories){for(const m of T.subcategories){if(m.category===r){if(u=m,!m.channels)continue;for(const I of m.channels)if(I.channel===e)if(c=I,I.is_editable){if(I.preference!==t){I.preference=t,t===p.OPT_IN&&(m.preference=p.OPT_IN),h=!0,A=!0;break}}else return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"Channel preference is not editable"})}if(A)break}if(A)break}}if(!u)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"Category not found"});if(!c)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"Category's channel not found"});if(!h)return a({status:n.SUCCESS,body:this.data});const O=[];(l=u==null?void 0:u.channels)==null||l.forEach(T=>{T.preference===p.OPT_OUT&&O.push(T.channel)});const R=(s==null?void 0:s.showOptOutChannels)!==!1,v={preference:R&&u.preference===p.OPT_OUT&&t===p.OPT_IN?p.OPT_IN:u.preference,opt_out_channels:O};return this.debouncedUpdateCategoryPreferences(r,r,v,u,{tenant_id:s==null?void 0:s.tenantId,show_opt_out_channels:R}),a({status:n.SUCCESS,body:this.data})}async updateOverallChannelPreference(e,t){if(!e||![E.ALL,E.REQUIRED].includes(t))return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:e?"Preference parameter is invalid":"Channel parameter is missing"});if(!this.data)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"Call getPreferences method before performing action"});if(!this.data.channel_preferences)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"Channel preferences doesn't exist"});let r=null,s=!1;const u=t===E.REQUIRED;for(const c of this.data.channel_preferences)if(c.channel===e&&(r=c,c.is_restricted!==u)){c.is_restricted=u,s=!0;break}return r?s?(this.debouncedUpdateChannelPreferences(r.channel,{channel_preferences:[r]}),a({status:n.SUCCESS,body:this.data})):a({status:n.SUCCESS,body:this.data}):a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"Channel data not found"})}}const U="ss_device_id";class J{constructor(e){d(this,"config");d(this,"preferences");this.config=e,this.preferences=new Q(e)}isReservedKey(e){var t;return e.startsWith("$")||((t=e==null?void 0:e.toLowerCase())==null?void 0:t.startsWith("ss_"))}formatParamsToObj(e,t){let r=null;return typeof e=="object"&&t===void 0?r=e:typeof e=="string"&&t!==void 0?r={[e]:t}:console.warn("[SuprSend]: Invalid input parameters"),r}formatParamsToArray(e){if(e)return Array.isArray(e)?e:[e]}validateObjData(e,t){const r={},s=(t==null?void 0:t.allowReservedKeys)||!1,u=(t==null?void 0:t.valueType)||"";for(const c in e){let h=e[c];if(!(c&&h===void 0)){if(!s&&this.isReservedKey(c)){console.warn("[SuprSend]: key cannot start with $ or ss_");continue}u==="number"?h=Number(h):u==="boolean"&&(h=!!h),r[c]=h}}return r}validateArrayData(e){const t=[];for(const r of e)if(r!=null){if(this.isReservedKey(r)){console.warn("[SuprSend]: key cannot start with $ or ss_");continue}t.push(String(r))}return t}async triggerUserEvent(e){return this.config.eventApi({distinct_id:this.config.distinctId,$insert_id:b(),$time:C(),...e})}async set(e,t){const r=this.formatParamsToObj(e,t);if(!r)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"data provided is empty"});const s=this.validateObjData(r);return f(s)?a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"data provided is empty"}):this.triggerUserEvent({$set:s})}async setOnce(e,t){const r=this.formatParamsToObj(e,t);if(!r)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"data provided is empty"});const s=this.validateObjData(r);return f(s)?a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"data provided is empty"}):this.triggerUserEvent({$set_once:s})}async increment(e,t){const r=this.formatParamsToObj(e,t);if(!r)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"data provided is empty"});const s=this.validateObjData(r,{valueType:"number"});return f(s)?a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"data provided is empty"}):this.triggerUserEvent({$add:s})}async append(e,t){const r=this.formatParamsToObj(e,t);if(!r)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"data provided is empty"});const s=this.validateObjData(r);return f(s)?a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"data provided is empty"}):this.triggerUserEvent({$append:s})}async remove(e,t){const r=this.formatParamsToObj(e,t);if(!r)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"data provided is empty"});const s=this.validateObjData(r);return f(s)?a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"data provided is empty"}):this.triggerUserEvent({$remove:s})}async unset(e){const t=this.formatParamsToArray(e);if(!t)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"data provided is empty"});const r=this.validateArrayData(t);return j(r)?a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"data provided is empty"}):this.triggerUserEvent({$unset:r})}appendInternal(e,t){const r=this.formatParamsToObj(e,t);if(!r)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"data provided is empty"});const s=this.validateObjData(r,{allowReservedKeys:!0});return f(s)?a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"data provided is empty"}):this.triggerUserEvent({$append:s})}removeInternal(e,t){const r=this.formatParamsToObj(e,t);if(!r)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"data provided is empty"});const s=this.validateObjData(r,{allowReservedKeys:!0});return f(s)?a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"data provided is empty"}):this.triggerUserEvent({$remove:s})}setInternal(e,t){const r=this.formatParamsToObj(e,t);if(!r)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"data provided is empty"});const s=this.validateObjData(r,{allowReservedKeys:!0});return f(s)?a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"data provided is empty"}):this.triggerUserEvent({$set:s})}validateEmail(e){return/\S+@\S+\.\S+/.test(e)}validateMobile(e){return/^\+[1-9]\d{1,14}$/.test(e)}async addEmail(e){return this.validateEmail(e)?this.appendInternal({$email:e}):a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"provided email is invalid"})}async removeEmail(e){return this.validateEmail(e)?this.removeInternal({$email:e}):a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"provided email is invalid"})}async addSms(e){return this.validateMobile(e)?this.appendInternal({$sms:e}):a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"provided mobile number is invalid, must be as per E.164 standard"})}async removeSms(e){return this.validateMobile(e)?this.removeInternal({$sms:e}):a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"provided mobile number is invalid, must be as per E.164 standard"})}async addWhatsapp(e){return this.validateMobile(e)?this.appendInternal({$whatsapp:e}):a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"provided mobile number is invalid, must be as per E.164 standard"})}async removeWhatsapp(e){return this.validateMobile(e)?this.removeInternal({$whatsapp:e}):a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"provided mobile number is invalid, must be as per E.164 standard"})}getDeviceId(){let e=V(U);return e||(e=b(),M(U,e)),e}async addWebPush(e){if(typeof e!="object")return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"provided push subscription is invalid, must be an object"});const t=this.getDeviceId();return this.appendInternal({$webpush:e,$id_provider:"vapid",$device_id:t})}async removeWebPush(e){if(typeof e!="object")return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"provided push subscription is invalid, must be an object"});const t=this.getDeviceId();return this.removeInternal({$webpush:e,$id_provider:"vapid",$device_id:t})}async addSlack(e){return typeof e!="object"?a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"provided slack data is invalid, must be an object"}):this.appendInternal({$slack:e})}async removeSlack(e){return typeof e!="object"?a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"provided slack data is invalid, must be an object"}):this.removeInternal({$slack:e})}async addMSTeams(e){return typeof e!="object"?a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"provided ms_teams data is invalid, must be object"}):this.appendInternal({$ms_teams:e})}async removeMSTeams(e){return typeof e!="object"?a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"provided ms_teams data is invalid, must be object"}):this.removeInternal({$ms_teams:e})}async setPreferredLanguage(e){return typeof e!="string"?a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"provided language is invalid, must be string"}):this.setInternal({$preferred_language:e})}async setTimezone(e){return typeof e!="string"?a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"provided timezone is invalid, must be string"}):this.setInternal({$timezone:e})}}class z{constructor(e){d(this,"config");this.config=e}async getPushSubscription(){if(!g())return;const e=await navigator.serviceWorker.getRegistration();if(!e)return;const t=e.pushManager.getSubscription();if(t)return t}async handleRegisterPush(){try{if(await navigator.serviceWorker.register(`/${this.config.swFileName}`),await Notification.requestPermission()!=="granted")return console.warn("[SuprSend]: Notification permission isnt granted"),a({status:n.ERROR,errorType:o.PERMISSION_DENIED,errorMessage:"Notification permission isn't granted"});const t=await navigator.serviceWorker.ready,r=await t.pushManager.getSubscription();if(r)return this.config.user.addWebPush(r);if(!this.config.vapidKey)return console.warn("[SuprSend]: Vapid key is missing. Add it while creating SuprSend instance"),a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"Vapid key is missing. Add it while creating SuprSend instance"});const s=await t.pushManager.subscribe({userVisibleOnly:!0,applicationServerKey:K(this.config.vapidKey)});return this.config.user.addWebPush(s)}catch(e){return console.warn("SuprSend: Error getting push subscription",e),a({status:n.ERROR,errorType:o.UNKNOWN_ERROR,errorMessage:(e==null?void 0:e.message)||"Unknown error occured while registering for push"})}}async registerPush(){return g()&&"serviceWorker"in navigator&&"PushManager"in window?this.handleRegisterPush():(console.warn("[SuprSend]: Webpush isn't supported"),a({status:n.ERROR,errorType:o.UNSUPPORTED_ACTION,errorMessage:"Webpush isn't supported"}))}async updatePushSubscription(){const e=await this.getPushSubscription();if(e)return this.config.user.addWebPush(e)}async removePushSubscription(){const e=await this.getPushSubscription();if(e)return this.config.user.removeWebPush(e)}notificationPermission(){return Notification.permission}async pushSubscribed(){return!!await this.getPushSubscription()}}function B(i){return{all:i=i||new Map,on:function(e,t){var r=i.get(e);r?r.push(t):i.set(e,[t])},off:function(e,t){var r=i.get(e);r&&(t?r.splice(r.indexOf(t)>>>0,1):i.set(e,[]))},emit:function(e,t){var r=i.get(e);r&&r.slice().map(function(s){s(t)}),(r=i.get("*"))&&r.slice().map(function(s){s(e,t)})}}}const G="https://hub.suprsend.com",X="serviceworker.js",w="ss_distinct_id";class k{constructor(e,t){d(this,"host");d(this,"publicApiKey");d(this,"distinctId");d(this,"userToken");d(this,"vapidKey");d(this,"swFileName");d(this,"apiClient",null);d(this,"userTokenExpirationTimer",null);d(this,"authenticateOptions");d(this,"user",new J(this));d(this,"webpush",new z(this));d(this,"emitter",B());if(!e)throw new Error("[SuprSend]: publicApiKey is missing");this.publicApiKey=e,this.host=(t==null?void 0:t.host)||G,this.vapidKey=(t==null?void 0:t.vapidKey)||"",this.swFileName=(t==null?void 0:t.swFileName)||X}handleRefreshUserToken(e){if(!this.userToken||!g())return;const t=L(this.userToken),r=(t.exp||0)*1e3,s=Date.now(),u=1e3*30;if(r&&r>s){const c=r-s-u;this.userTokenExpirationTimer&&clearTimeout(this.userTokenExpirationTimer),this.userTokenExpirationTimer=setTimeout(async()=>{let h="";try{h=await e(this.userToken,t)}catch{try{h=await e(this.userToken,t)}catch(R){console.warn("[SuprSend]: Couldn't fetch new userToken",R)}}h&&typeof h=="string"&&this.identify(this.distinctId,h,this.authenticateOptions)},c)}}client(){return this.distinctId||console.warn("[SuprSend]: distinctId is missing. User should be authenticated"),this.apiClient||(this.apiClient=new S(this)),this.apiClient}eventApi(e){return this.client().request({path:"v2/event",payload:e,type:"post"})}async identify(e,t,r){if(!e)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"distinctId is missing"});if(this.apiClient&&this.distinctId&&this.distinctId!==e)return a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"User already loggedin, reset current user to login new user"});if(this.apiClient&&this.distinctId===e&&this.userToken!==t)return this.userToken=t,this.apiClient=new S(this),r!=null&&r.refreshUserToken&&this.handleRefreshUserToken(r.refreshUserToken),a({status:n.SUCCESS});if(this.distinctId&&this.apiClient)return a({status:n.SUCCESS});this.distinctId=e,this.userToken=t,this.apiClient=new S(this),this.authenticateOptions=r;const s=V(w);if(r!=null&&r.refreshUserToken&&this.handleRefreshUserToken(r.refreshUserToken),s==this.distinctId)return this.webpush.updatePushSubscription(),a({status:n.SUCCESS});const u=await this.eventApi({event:"$identify",$insert_id:b(),$time:C(),properties:{$identified_id:e}});return u.status===n.SUCCESS?(this.webpush.updatePushSubscription(),M(w,this.distinctId)):this.reset({unsubscribePush:!1}),u}isIdentified(e){return e?!!(this.userToken&&this.distinctId):!!this.distinctId}async track(e,t){let r={};return e?(typeof t=="object"&&(r={...r,...t}),this.eventApi({event:String(e),$insert_id:b(),$time:C(),distinct_id:this.distinctId,properties:r})):a({status:n.ERROR,errorType:o.VALIDATION_ERROR,errorMessage:"event name is missing"})}async reset(e){var r;return(e==null?void 0:e.unsubscribePush)!==!1&&await((r=this.webpush)==null?void 0:r.removePushSubscription()),this.apiClient=null,this.distinctId=null,this.userToken="",F(w),this.userTokenExpirationTimer&&clearTimeout(this.userTokenExpirationTimer),a({status:n.SUCCESS})}}exports.ChannelLevelPreferenceOptions=E;exports.ERROR_TYPE=o;exports.PreferenceOptions=p;exports.RESPONSE_STATUS=n;exports.SuprSend=k;exports.default=k;
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../src/interface.ts","../../src/utils.ts","../../node_modules/jwt-decode/build/jwt-decode.esm.js","../../src/api.ts","../../src/preferences.ts","../../src/user.ts","../../src/webpush.ts","../../node_modules/mitt/dist/mitt.mjs","../../src/index.ts"],"sourcesContent":["export type Dictionary = Record<string, unknown>;\n\nexport interface SuprSendOptions {\n host?: string;\n vapidKey?: string;\n swFileName?: string;\n}\n\nexport type RefreshTokenCallback = (\n oldUserToken: string,\n tokenPayload: Dictionary\n) => Promise<string>;\n\nexport interface AuthenticateOptions {\n refreshUserToken: RefreshTokenCallback;\n}\n\nexport interface ResponseOptions {\n status: RESPONSE_STATUS.ERROR | RESPONSE_STATUS.SUCCESS;\n statusCode?: number;\n // eslint-disable-next-line\n body?: any;\n errorMessage?: string;\n errorType?: string;\n}\n\ninterface IError {\n type?: string;\n message?: string;\n}\n\nexport interface ApiResponse {\n status: RESPONSE_STATUS.ERROR | RESPONSE_STATUS.SUCCESS;\n statusCode?: number;\n error?: IError;\n // eslint-disable-next-line\n body?: any;\n}\n\nexport enum PreferenceOptions {\n OPT_IN = 'opt_in',\n OPT_OUT = 'opt_out',\n}\n\nexport enum ChannelLevelPreferenceOptions {\n ALL = 'all',\n REQUIRED = 'required',\n}\n\nexport interface CategoryChannel {\n channel: string;\n preference: PreferenceOptions;\n is_editable: boolean;\n}\n\nexport interface Category {\n name: string;\n category: string;\n description?: string | null;\n preference: PreferenceOptions;\n is_editable: boolean;\n channels?: CategoryChannel[] | null;\n}\n\nexport interface Section {\n name?: string | null;\n description?: string | null;\n subcategories?: Category[] | null;\n}\n\nexport interface ChannelPreference {\n channel: string;\n is_restricted: boolean;\n}\n\nexport interface PreferenceData {\n sections?: Section[] | null;\n channel_preferences?: ChannelPreference[] | null;\n}\n\nexport interface PreferenceApiResponse extends ApiResponse {\n body: PreferenceData;\n}\n\n// eslint-disable-next-line\nexport type EmitterEvents = {\n preferences_updated: PreferenceApiResponse;\n preferences_error: ApiResponse;\n};\n\nexport interface HandleRequest {\n type: 'get' | 'post' | 'patch';\n path: string;\n payload?: Dictionary;\n}\n\nexport interface ValidatedDataOptions {\n allowReservedKeys?: boolean;\n valueType?: string;\n}\n\nexport enum ERROR_TYPE {\n VALIDATION_ERROR = 'VALIDATION_ERROR',\n NETWORK_ERROR = 'NETWORK_ERROR',\n UNKNOWN_ERROR = 'UNKNOWN_ERROR',\n PERMISSION_DENIED = 'PERMISSION_DENIED',\n UNSUPPORTED_ACTION = 'UNSUPPORTED_ACTION',\n}\n\nexport enum RESPONSE_STATUS {\n SUCCESS = 'success',\n ERROR = 'error',\n}\n","import {\n ApiResponse,\n Dictionary,\n ResponseOptions,\n RESPONSE_STATUS,\n} from './interface';\n\nexport function uuid() {\n let dt = new Date().getTime();\n const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(\n /[xy]/g,\n function (c) {\n const r = (dt + Math.random() * 16) % 16 | 0;\n dt = Math.floor(dt / 16);\n return (c == 'x' ? r : (r & 0x3) | 0x8).toString(16);\n }\n );\n return uuid;\n}\n\nexport function epochMs() {\n return Math.round(Date.now());\n}\n\nexport function isObjectEmpty(objectName: Dictionary) {\n return Object.keys(objectName).length === 0;\n}\n\nexport function isArrayEmpty(arrayName: unknown[]) {\n return arrayName?.length <= 0;\n}\n\nexport function urlB64ToUint8Array(base64String: string) {\n const padding = '='.repeat((4 - (base64String.length % 4)) % 4);\n const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');\n const rawData = atob(base64);\n const outputArray = new Uint8Array(rawData.length);\n for (let i = 0; i < rawData.length; ++i) {\n outputArray[i] = rawData.charCodeAt(i);\n }\n return outputArray;\n}\n\nexport function debounce<T extends unknown[], U>(\n callback: (...args: T) => PromiseLike<U> | U,\n wait: number\n) {\n let timer: ReturnType<typeof setTimeout>;\n\n return (...args: T): Promise<U> => {\n clearTimeout(timer);\n return new Promise((resolve) => {\n timer = setTimeout(() => resolve(callback(...args)), wait);\n });\n };\n}\n\n// https://gist.github.com/nzvtrk/1a444cdf6a86a5a6e6d6a34f0db19065\nexport function debounceByType(func, wait) {\n const memory = {};\n\n return (...args) => {\n const [searchType] = args;\n const payload = args.slice(1);\n\n if (typeof memory[searchType] === 'function') {\n return memory[searchType](...payload);\n }\n\n memory[searchType] = debounce(func, wait);\n return memory[searchType](...payload);\n };\n}\n\nexport function getResponsePayload(options: ResponseOptions) {\n const response: ApiResponse = { status: options.status };\n\n if (options.statusCode) {\n response.statusCode = options.statusCode;\n }\n\n if (options.body) {\n response.body = options.body;\n }\n\n if (options.status === RESPONSE_STATUS.ERROR) {\n response.error = {\n type: options.errorType,\n message: options.errorMessage,\n };\n }\n return response;\n}\n\nexport function windowSupport() {\n return typeof window !== 'undefined';\n}\n\nexport function setLocalStorageData(key: string, value: string) {\n if (!windowSupport()) return;\n\n if (typeof value === 'object') {\n value = JSON.stringify(value);\n }\n localStorage.setItem(key, value);\n}\n\nexport function getLocalStorageData(key: string) {\n if (!windowSupport()) return;\n\n const value = localStorage.getItem(key);\n if (!value) return;\n try {\n return JSON.parse(value);\n } catch (e) {\n return value;\n }\n}\n\nexport function removeLocalStorageData(key: string) {\n if (!windowSupport()) return;\n\n localStorage.removeItem(key);\n}\n","function e(e){this.message=e}e.prototype=new Error,e.prototype.name=\"InvalidCharacterError\";var r=\"undefined\"!=typeof window&&window.atob&&window.atob.bind(window)||function(r){var t=String(r).replace(/=+$/,\"\");if(t.length%4==1)throw new e(\"'atob' failed: The string to be decoded is not correctly encoded.\");for(var n,o,a=0,i=0,c=\"\";o=t.charAt(i++);~o&&(n=a%4?64*n+o:o,a++%4)?c+=String.fromCharCode(255&n>>(-2*a&6)):0)o=\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\".indexOf(o);return c};function t(e){var t=e.replace(/-/g,\"+\").replace(/_/g,\"/\");switch(t.length%4){case 0:break;case 2:t+=\"==\";break;case 3:t+=\"=\";break;default:throw\"Illegal base64url string!\"}try{return function(e){return decodeURIComponent(r(e).replace(/(.)/g,(function(e,r){var t=r.charCodeAt(0).toString(16).toUpperCase();return t.length<2&&(t=\"0\"+t),\"%\"+t})))}(t)}catch(e){return r(t)}}function n(e){this.message=e}function o(e,r){if(\"string\"!=typeof e)throw new n(\"Invalid token specified\");var o=!0===(r=r||{}).header?0:1;try{return JSON.parse(t(e.split(\".\")[o]))}catch(e){throw new n(\"Invalid token specified: \"+e.message)}}n.prototype=new Error,n.prototype.name=\"InvalidTokenError\";export default o;export{n as InvalidTokenError};\n//# sourceMappingURL=jwt-decode.esm.js.map\n","import { SuprSend } from '.';\nimport {\n Dictionary,\n HandleRequest,\n ERROR_TYPE,\n RESPONSE_STATUS,\n} from './interface';\nimport { getResponsePayload } from './utils';\nimport jwt_decode from 'jwt-decode';\n\nexport default class ApiClient {\n private config: SuprSend;\n\n constructor(config: SuprSend) {\n this.config = config;\n }\n\n private getUrl(path: string) {\n return `${this.config.host}/${path}`;\n }\n\n private getHeaders() {\n const headers = {\n 'Content-Type': 'application/json',\n Authorization: this.config.publicApiKey,\n };\n\n if (this.config.userToken) {\n headers['x-ss-signature'] = this.config.userToken;\n }\n\n return headers;\n }\n\n private requestApiInstance(reqData: HandleRequest) {\n switch (reqData.type) {\n case 'get':\n return this.get(reqData.path);\n case 'post':\n return this.post(reqData.path, reqData?.payload || {});\n case 'patch':\n return this.patch(reqData.path, reqData?.payload || {});\n default:\n return this.get(reqData.path);\n }\n }\n\n private get(path: string) {\n const url = this.getUrl(path);\n\n return fetch(url, {\n method: 'GET',\n headers: this.getHeaders(),\n });\n }\n\n private post(path: string, payload: Dictionary) {\n const url = this.getUrl(path);\n\n return fetch(url, {\n method: 'POST',\n body: JSON.stringify(payload),\n headers: this.getHeaders(),\n });\n }\n\n private patch(path: string, payload: Dictionary) {\n const url = this.getUrl(path);\n\n return fetch(url, {\n method: 'PATCH',\n body: JSON.stringify(payload),\n headers: this.getHeaders(),\n });\n }\n\n async request(reqData: HandleRequest) {\n if (!this.config.distinctId) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage:\n \"User isn't authenticated. Call identify method before performing any action\",\n });\n }\n\n if (\n this.config.authenticateOptions?.refreshUserToken &&\n this.config.userToken\n ) {\n const jwtPayload = jwt_decode(this.config.userToken) as Dictionary;\n const expiresOn = ((jwtPayload.exp as number) || 0) * 1000; // in ms\n const now = Date.now(); // in ms\n const hasExpired = expiresOn <= now;\n if (hasExpired) {\n try {\n const newUserToken =\n await this.config.authenticateOptions.refreshUserToken(\n this.config.userToken,\n jwtPayload\n );\n\n if (newUserToken && typeof newUserToken === 'string') {\n this.config.identify(\n this.config.distinctId,\n newUserToken,\n this.config.authenticateOptions\n );\n }\n } catch (e) {\n // error while getting token go ahead with calling api\n }\n }\n }\n\n try {\n const resp = await this.requestApiInstance(reqData);\n const respData = await resp.json();\n\n const respStatus =\n respData?.status ||\n (resp.ok ? RESPONSE_STATUS.SUCCESS : RESPONSE_STATUS.ERROR);\n\n return getResponsePayload({\n status: respStatus,\n body: respData,\n statusCode: resp.status,\n errorMessage: respData?.error?.message,\n errorType: respData?.error?.type,\n });\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (e: any) {\n console.error(e);\n\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n statusCode: 500,\n errorMessage: e?.message || 'network error',\n errorType: ERROR_TYPE.NETWORK_ERROR,\n });\n }\n }\n}\n","import { SuprSend } from './index';\nimport {\n Dictionary,\n PreferenceData,\n Category,\n PreferenceOptions,\n CategoryChannel,\n ChannelLevelPreferenceOptions,\n ChannelPreference,\n ERROR_TYPE,\n RESPONSE_STATUS,\n} from './interface';\nimport { debounceByType, getResponsePayload } from './utils';\n\nexport default class Preferences {\n private config: SuprSend;\n private preferenceData: PreferenceData;\n private preferenceArgs?: { tenantId?: string; showOptOutChannels?: boolean };\n private debouncedUpdateCategoryPreferences;\n private debouncedUpdateChannelPreferences;\n private debounceTime = 1000;\n\n constructor(config: SuprSend) {\n this.config = config;\n\n this.debouncedUpdateCategoryPreferences = debounceByType(\n this._updateCategoryPreferences.bind(this),\n this.debounceTime\n );\n this.debouncedUpdateChannelPreferences = debounceByType(\n this._updateChannelPreferences.bind(this),\n this.debounceTime\n );\n }\n\n private validateQueryParams(queryParams: Dictionary = {}) {\n const validatedParams: Record<string, string> = {};\n for (const key in queryParams) {\n if (queryParams[key]) {\n validatedParams[key] = String(queryParams[key]);\n }\n }\n return validatedParams;\n }\n\n set data(value) {\n this.preferenceData = value;\n }\n\n get data() {\n return this.preferenceData;\n }\n\n getUrlPath(path: string, qp?: Dictionary) {\n const urlPath = `v2/subscriber/${this.config.distinctId}/${path}`;\n\n const validatedQueryParams = this.validateQueryParams(qp);\n const queryParamsString = new URLSearchParams(\n validatedQueryParams\n ).toString();\n\n return queryParamsString ? `${urlPath}/?${queryParamsString}` : urlPath;\n }\n\n /**\n * Used to get user's whole preferences data.\n */\n async getPreferences(args?: {\n tenantId?: string;\n showOptOutChannels?: boolean;\n }) {\n const queryParams = {\n tenant_id: args?.tenantId,\n show_opt_out_channels: args?.showOptOutChannels === false ? false : true,\n };\n\n this.preferenceArgs = {\n tenantId: queryParams?.tenant_id,\n showOptOutChannels: queryParams?.show_opt_out_channels,\n };\n const path = this.getUrlPath('full_preference', queryParams);\n\n const response = await this.config.client().request({ type: 'get', path });\n\n if (!response.error) {\n this.data = response.body;\n }\n return response;\n }\n\n /**\n * Used to get user's preference of all categories.\n */\n async getCategories(args?: {\n tenantId?: string;\n showOptOutChannels?: boolean;\n limit?: number;\n offset?: number;\n }) {\n const queryParams = {\n tenant_id: args?.tenantId,\n show_opt_out_channels: args?.showOptOutChannels === false ? false : true,\n limit: args?.limit,\n offset: args?.offset,\n };\n const path = this.getUrlPath('category', queryParams);\n\n const response = await this.config.client().request({ type: 'get', path });\n return response;\n }\n\n /**\n * Used to get user's preference of specific category.\n */\n async getCategory(\n category: string,\n args?: { tenantId?: string; showOptOutChannels?: boolean }\n ) {\n if (!category) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'Category parameter is missing',\n });\n }\n\n const queryParams = {\n tenant_id: args?.tenantId,\n show_opt_out_channels: args?.showOptOutChannels === false ? false : true,\n };\n const path = this.getUrlPath(`category/${category}`, queryParams);\n\n const response = await this.config.client().request({ type: 'get', path });\n return response;\n }\n\n /**\n * Used to get user's all channel level preference.\n */\n async getOverallChannelPreferences() {\n const path = this.getUrlPath('channel_preference');\n\n const response = await this.config.client().request({ type: 'get', path });\n return response;\n }\n\n private async _updateCategoryPreferences(\n category: string,\n body: Dictionary,\n subcategory: Category,\n args: Dictionary\n ) {\n const path = this.getUrlPath(`category/${category}`, args);\n\n const response = await this.config\n .client()\n .request({ type: 'patch', path, payload: body });\n\n if (response?.error) {\n this.config.emitter.emit('preferences_error', response);\n } else {\n Object.assign(subcategory, response.body);\n this.config.emitter.emit('preferences_updated', {\n status: RESPONSE_STATUS.SUCCESS,\n statusCode: 200,\n body: this.data as PreferenceData,\n });\n }\n return response;\n }\n\n private async _updateChannelPreferences(body: Dictionary) {\n const path = this.getUrlPath('channel_preference');\n\n const response = await this.config\n .client()\n .request({ type: 'patch', path, payload: body });\n\n if (response?.error) {\n this.config.emitter.emit('preferences_error', response);\n } else {\n await this.getPreferences(this.preferenceArgs);\n this.config.emitter.emit('preferences_updated', {\n status: RESPONSE_STATUS.SUCCESS,\n statusCode: 200,\n body: this.data as PreferenceData,\n });\n }\n return response;\n }\n\n /**\n * Used to update user's category level preference.\n */\n async updateCategoryPreference(\n category: string,\n preference: PreferenceOptions,\n args?: { tenantId?: string; showOptOutChannels?: boolean }\n ) {\n if (\n !category ||\n ![PreferenceOptions.OPT_IN, PreferenceOptions.OPT_OUT].includes(\n preference\n )\n ) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: !category\n ? 'Category parameter is missing'\n : 'Preference parameter is invalid',\n });\n }\n\n if (!this.data) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'Call getPreferences method before performing action',\n });\n }\n\n if (!this.data.sections) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: \"Sections doesn't exist\",\n });\n }\n\n let categoryData: Category | null = null;\n let dataUpdated = false;\n\n // optimistic update in local store\n for (const section of this.data.sections) {\n let abort = false;\n if (!section.subcategories) continue;\n\n for (const subcategory of section.subcategories) {\n if (subcategory.category === category) {\n categoryData = subcategory;\n if (subcategory.is_editable) {\n if (subcategory.preference !== preference) {\n subcategory.preference = preference;\n dataUpdated = true;\n abort = true;\n break;\n } else {\n // console.log(`category is already ${status}ed`);\n }\n } else {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'Category preference is not editable',\n });\n }\n }\n }\n if (abort) break;\n }\n\n if (!categoryData) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'Category not found',\n });\n }\n\n if (!dataUpdated) {\n return getResponsePayload({\n status: RESPONSE_STATUS.SUCCESS,\n body: this.data,\n });\n }\n\n const optOutChannels: string[] = [];\n categoryData?.channels?.forEach((channel) => {\n if (channel.preference === PreferenceOptions.OPT_OUT) {\n optOutChannels.push(channel.channel);\n }\n });\n\n const showOptOutChannels =\n args?.showOptOutChannels === false ? false : true;\n\n const requestPayload = {\n preference: categoryData.preference,\n opt_out_channels:\n showOptOutChannels && preference === PreferenceOptions.OPT_IN\n ? null\n : optOutChannels,\n };\n\n this.debouncedUpdateCategoryPreferences(\n category,\n category,\n requestPayload,\n categoryData,\n { tenant_id: args?.tenantId, show_opt_out_channels: showOptOutChannels }\n );\n\n return getResponsePayload({\n status: RESPONSE_STATUS.SUCCESS,\n body: this.data,\n });\n }\n\n /**\n * Used to update user's category level channel preference.\n */\n async updateChannelPreferenceInCategory(\n channel: string,\n preference: PreferenceOptions,\n category: string,\n args?: { tenantId?: string; showOptOutChannels?: boolean }\n ) {\n if (!channel || !category) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: !channel\n ? 'Channel parameter is missing'\n : 'Category parameter is missing',\n });\n }\n\n if (\n ![PreferenceOptions.OPT_IN, PreferenceOptions.OPT_OUT].includes(\n preference\n )\n ) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'Preference parameter is invalid',\n });\n }\n\n if (!this.data) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'Call getPreferences method before performing action',\n });\n }\n\n if (!this.data.sections) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: \"Sections doesn't exist\",\n });\n }\n\n let categoryData: Category | null = null;\n let selectedChannelData: CategoryChannel | null = null;\n let dataUpdated = false;\n\n // optimistic update in local store\n for (const section of this.data.sections) {\n let abort = false;\n if (!section.subcategories) continue;\n\n for (const subcategory of section.subcategories) {\n if (subcategory.category === category) {\n categoryData = subcategory;\n if (!subcategory.channels) continue;\n\n for (const channelData of subcategory.channels) {\n if (channelData.channel === channel) {\n selectedChannelData = channelData;\n if (channelData.is_editable) {\n if (channelData.preference !== preference) {\n channelData.preference = preference;\n if (preference === PreferenceOptions.OPT_IN) {\n subcategory.preference = PreferenceOptions.OPT_IN;\n }\n dataUpdated = true;\n abort = true;\n break;\n } else {\n // console.log(`channel is already ${preference}`);\n }\n } else {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'Channel preference is not editable',\n });\n }\n }\n }\n }\n if (abort) break;\n }\n if (abort) break;\n }\n\n if (!categoryData) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'Category not found',\n });\n }\n\n if (!selectedChannelData) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: \"Category's channel not found\",\n });\n }\n\n if (!dataUpdated) {\n return getResponsePayload({\n status: RESPONSE_STATUS.SUCCESS,\n body: this.data,\n });\n }\n\n const optOutChannels: string[] = [];\n categoryData?.channels?.forEach((channel) => {\n if (channel.preference === PreferenceOptions.OPT_OUT) {\n optOutChannels.push(channel.channel);\n }\n });\n\n const showOptOutChannels =\n args?.showOptOutChannels === false ? false : true;\n\n const categoryPreference =\n showOptOutChannels &&\n categoryData.preference === PreferenceOptions.OPT_OUT &&\n preference === PreferenceOptions.OPT_IN\n ? PreferenceOptions.OPT_IN\n : categoryData.preference;\n\n const requestPayload = {\n preference: categoryPreference,\n opt_out_channels: optOutChannels,\n };\n\n this.debouncedUpdateCategoryPreferences(\n category,\n category,\n requestPayload,\n categoryData,\n { tenant_id: args?.tenantId, show_opt_out_channels: showOptOutChannels }\n );\n\n return getResponsePayload({\n status: RESPONSE_STATUS.SUCCESS,\n body: this.data,\n });\n }\n\n /**\n * Used to update user's channel level preference.\n */\n async updateOverallChannelPreference(\n channel: string,\n preference: ChannelLevelPreferenceOptions\n ) {\n if (\n !channel ||\n ![\n ChannelLevelPreferenceOptions.ALL,\n ChannelLevelPreferenceOptions.REQUIRED,\n ].includes(preference)\n ) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: !channel\n ? 'Channel parameter is missing'\n : 'Preference parameter is invalid',\n });\n }\n\n if (!this.data) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'Call getPreferences method before performing action',\n });\n }\n\n if (!this.data.channel_preferences) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: \"Channel preferences doesn't exist\",\n });\n }\n\n let channelData: ChannelPreference | null = null;\n let dataUpdated = false;\n const preferenceRestricted =\n preference === ChannelLevelPreferenceOptions.REQUIRED;\n\n for (const channelItem of this.data.channel_preferences) {\n if (channelItem.channel === channel) {\n channelData = channelItem;\n if (channelItem.is_restricted !== preferenceRestricted) {\n channelItem.is_restricted = preferenceRestricted;\n dataUpdated = true;\n break;\n }\n }\n }\n\n if (!channelData) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'Channel data not found',\n });\n }\n\n if (!dataUpdated) {\n return getResponsePayload({\n status: RESPONSE_STATUS.SUCCESS,\n body: this.data,\n });\n }\n\n this.debouncedUpdateChannelPreferences(channelData.channel, {\n channel_preferences: [channelData],\n });\n\n return getResponsePayload({\n status: RESPONSE_STATUS.SUCCESS,\n body: this.data,\n });\n }\n}\n","import { SuprSend } from './index';\nimport {\n Dictionary,\n ERROR_TYPE,\n RESPONSE_STATUS,\n ValidatedDataOptions,\n} from './interface';\nimport {\n epochMs,\n getLocalStorageData,\n getResponsePayload,\n isArrayEmpty,\n isObjectEmpty,\n setLocalStorageData,\n uuid,\n} from './utils';\nimport Preferences from './preferences';\n\nconst DEVICE_ID_KEY = 'ss_device_id';\n\nexport default class User {\n private config: SuprSend;\n public preferences: Preferences;\n\n constructor(config: SuprSend) {\n this.config = config;\n this.preferences = new Preferences(config);\n }\n\n private isReservedKey(key: string) {\n return key.startsWith('$') || key?.toLowerCase()?.startsWith('ss_');\n }\n\n private formatParamsToObj(arg1: string | Dictionary, arg2?: unknown) {\n let data: Dictionary | null = null;\n\n if (typeof arg1 === 'object' && arg2 === undefined) {\n data = arg1;\n } else if (typeof arg1 === 'string' && arg2 !== undefined) {\n data = { [arg1]: arg2 };\n } else {\n console.warn('[SuprSend]: Invalid input parameters');\n }\n\n return data;\n }\n\n private formatParamsToArray(arg1: string | string[]) {\n if (!arg1) return;\n\n return Array.isArray(arg1) ? arg1 : [arg1];\n }\n\n private validateObjData(data: Dictionary, options?: ValidatedDataOptions) {\n const validatedData = {};\n const allowReservedKeys = options?.allowReservedKeys || false;\n const valueType = options?.valueType || '';\n\n for (const key in data) {\n let value = data[key];\n\n if (key && value === undefined) continue;\n\n if (!allowReservedKeys && this.isReservedKey(key)) {\n console.warn('[SuprSend]: key cannot start with $ or ss_');\n continue;\n }\n\n if (valueType === 'number') {\n value = Number(value);\n } else if (valueType === 'boolean') {\n value = !!value;\n }\n\n validatedData[key] = value;\n }\n\n return validatedData;\n }\n\n private validateArrayData(data: string[]) {\n const validatedData: string[] = [];\n\n for (const item of data) {\n if (item === undefined || item === null) continue;\n\n if (this.isReservedKey(item)) {\n console.warn('[SuprSend]: key cannot start with $ or ss_');\n continue;\n }\n\n validatedData.push(String(item));\n }\n\n return validatedData;\n }\n\n private async triggerUserEvent(data: Dictionary) {\n return this.config.eventApi({\n distinct_id: this.config.distinctId,\n $insert_id: uuid(),\n $time: epochMs(),\n ...data,\n });\n }\n\n /**\n * Used to set user properties. Keys with $ and ss_ will be removed.\n */\n async set(arg1: string | Dictionary, arg2?: unknown) {\n const data = this.formatParamsToObj(arg1, arg2);\n if (!data) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'data provided is empty',\n });\n }\n\n const validatedData = this.validateObjData(data);\n if (isObjectEmpty(validatedData)) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'data provided is empty',\n });\n }\n\n return this.triggerUserEvent({ $set: validatedData });\n }\n\n /**\n * Used to set user properties only once. Properties once set cannot be changed later.\n * Keys with $ and ss_ will be removed.\n */\n async setOnce(arg1: string | Dictionary, arg2?: unknown) {\n const data = this.formatParamsToObj(arg1, arg2);\n if (!data) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'data provided is empty',\n });\n }\n\n const validatedData = this.validateObjData(data);\n if (isObjectEmpty(validatedData)) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'data provided is empty',\n });\n }\n\n return this.triggerUserEvent({ $set_once: validatedData });\n }\n\n /**\n * Used to increment/decrement user properties whose values are numbers. To decrement use -ve values.\n * Keys with $ and ss_ will be removed.\n */\n async increment(arg1: string | Dictionary, arg2?: number) {\n const data = this.formatParamsToObj(arg1, arg2);\n if (!data) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'data provided is empty',\n });\n }\n\n const validatedData = this.validateObjData(data, { valueType: 'number' });\n if (isObjectEmpty(validatedData)) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'data provided is empty',\n });\n }\n\n return this.triggerUserEvent({ $add: validatedData });\n }\n\n /**\n * Used to add items to list if user property is list (example: wishlist: [iphone, macbook]).\n * Keys with $ and ss_ will be removed.\n */\n async append(arg1: string | Dictionary, arg2?: unknown) {\n const data = this.formatParamsToObj(arg1, arg2);\n if (!data) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'data provided is empty',\n });\n }\n\n const validatedData = this.validateObjData(data);\n if (isObjectEmpty(validatedData)) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'data provided is empty',\n });\n }\n\n return this.triggerUserEvent({ $append: validatedData });\n }\n\n /**\n * Used to remove items from list if user property is list.\n * Keys with $ and ss_ will be removed.\n */\n async remove(arg1: string | Dictionary, arg2?: unknown) {\n const data = this.formatParamsToObj(arg1, arg2);\n if (!data) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'data provided is empty',\n });\n }\n\n const validatedData = this.validateObjData(data);\n if (isObjectEmpty(validatedData)) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'data provided is empty',\n });\n }\n\n return this.triggerUserEvent({ $remove: validatedData });\n }\n\n /**\n * Used to remove user property. Keys with $ and ss_ will be removed.\n */\n async unset(arg: string | string[]) {\n const data = this.formatParamsToArray(arg);\n if (!data) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'data provided is empty',\n });\n }\n\n const validatedData = this.validateArrayData(data);\n if (isArrayEmpty(validatedData)) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'data provided is empty',\n });\n }\n\n return this.triggerUserEvent({ $unset: validatedData });\n }\n\n // this append is only used internally since it allows internal events\n private appendInternal(arg1: string | Dictionary, arg2?: unknown) {\n const data = this.formatParamsToObj(arg1, arg2);\n if (!data) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'data provided is empty',\n });\n }\n\n const validatedData = this.validateObjData(data, {\n allowReservedKeys: true,\n });\n if (isObjectEmpty(validatedData)) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'data provided is empty',\n });\n }\n\n return this.triggerUserEvent({ $append: validatedData });\n }\n\n // this remove is only used internally since it allows internal events\n private removeInternal(arg1: string | Dictionary, arg2?: unknown) {\n const data = this.formatParamsToObj(arg1, arg2);\n if (!data) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'data provided is empty',\n });\n }\n\n const validatedData = this.validateObjData(data, {\n allowReservedKeys: true,\n });\n if (isObjectEmpty(validatedData)) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'data provided is empty',\n });\n }\n\n return this.triggerUserEvent({ $remove: validatedData });\n }\n\n private setInternal(arg1: string | Dictionary, arg2?: unknown) {\n const data = this.formatParamsToObj(arg1, arg2);\n if (!data) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'data provided is empty',\n });\n }\n\n const validatedData = this.validateObjData(data, {\n allowReservedKeys: true,\n });\n if (isObjectEmpty(validatedData)) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'data provided is empty',\n });\n }\n\n return this.triggerUserEvent({ $set: validatedData });\n }\n\n private validateEmail(email: string) {\n const emailRegex = /\\S+@\\S+\\.\\S+/;\n\n return emailRegex.test(email);\n }\n\n private validateMobile(mobile: string) {\n const mobileRegex = /^\\+[1-9]\\d{1,14}$/;\n\n return mobileRegex.test(mobile);\n }\n\n async addEmail(email: string) {\n const isValid = this.validateEmail(email);\n\n if (!isValid) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'provided email is invalid',\n });\n }\n\n return this.appendInternal({ $email: email });\n }\n\n async removeEmail(email: string) {\n const isValid = this.validateEmail(email);\n\n if (!isValid) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'provided email is invalid',\n });\n }\n\n return this.removeInternal({ $email: email });\n }\n\n /**\n * Mobile number must be as per {@link https://www.twilio.com/docs/glossary/what-e164 E.164 standard}.\n */\n async addSms(mobile: string) {\n const isValid = this.validateMobile(mobile);\n\n if (!isValid) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage:\n 'provided mobile number is invalid, must be as per E.164 standard',\n });\n }\n\n return this.appendInternal({ $sms: mobile });\n }\n\n /**\n * Mobile number must be as per {@link https://www.twilio.com/docs/glossary/what-e164 E.164 standard}.\n */\n async removeSms(mobile: string) {\n const isValid = this.validateMobile(mobile);\n\n if (!isValid) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage:\n 'provided mobile number is invalid, must be as per E.164 standard',\n });\n }\n\n return this.removeInternal({ $sms: mobile });\n }\n\n /**\n * Mobile number must be as per {@link https://www.twilio.com/docs/glossary/what-e164 E.164 standard}.\n */\n async addWhatsapp(mobile: string) {\n const isValid = this.validateMobile(mobile);\n\n if (!isValid) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage:\n 'provided mobile number is invalid, must be as per E.164 standard',\n });\n }\n\n return this.appendInternal({ $whatsapp: mobile });\n }\n\n /**\n * Mobile number must be as per {@link https://www.twilio.com/docs/glossary/what-e164 E.164 standard}.\n */\n async removeWhatsapp(mobile: string) {\n const isValid = this.validateMobile(mobile);\n\n if (!isValid) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage:\n 'provided mobile number is invalid, must be as per E.164 standard',\n });\n }\n\n return this.removeInternal({ $whatsapp: mobile });\n }\n\n private getDeviceId(): string {\n let deviceId = getLocalStorageData(DEVICE_ID_KEY);\n\n if (!deviceId) {\n deviceId = uuid();\n setLocalStorageData(DEVICE_ID_KEY, deviceId);\n }\n\n return deviceId;\n }\n\n async addWebPush(push: PushSubscription) {\n if (typeof push !== 'object') {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage:\n 'provided push subscription is invalid, must be an object',\n });\n }\n\n const deviceId: string = this.getDeviceId();\n\n return this.appendInternal({\n $webpush: push,\n $id_provider: 'vapid',\n $device_id: deviceId,\n });\n }\n\n async removeWebPush(push: PushSubscription) {\n if (typeof push !== 'object') {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage:\n 'provided push subscription is invalid, must be an object',\n });\n }\n\n const deviceId: string = this.getDeviceId();\n\n return this.removeInternal({\n $webpush: push,\n $id_provider: 'vapid',\n $device_id: deviceId,\n });\n }\n\n async addSlack(data: Dictionary) {\n if (typeof data !== 'object') {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'provided slack data is invalid, must be an object',\n });\n }\n\n return this.appendInternal({ $slack: data });\n }\n\n async removeSlack(data: Dictionary) {\n if (typeof data !== 'object') {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'provided slack data is invalid, must be an object',\n });\n }\n\n return this.removeInternal({ $slack: data });\n }\n\n async addMSTeams(data: Dictionary) {\n if (typeof data !== 'object') {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'provided ms_teams data is invalid, must be object',\n });\n }\n\n return this.appendInternal({ $ms_teams: data });\n }\n\n async removeMSTeams(data: Dictionary) {\n if (typeof data !== 'object') {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'provided ms_teams data is invalid, must be object',\n });\n }\n\n return this.removeInternal({ $ms_teams: data });\n }\n\n /**\n * language passed should be 2-letter language code in {@link https://gist.github.com/jrnk/8eb57b065ea0b098d571 ISO 639-1 Alpha-2 format}.\n * e.g. en (for English), es (for Spanish), fr (for French) etc.\n */\n async setPreferredLanguage(language: string) {\n if (typeof language !== 'string') {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'provided language is invalid, must be string',\n });\n }\n\n return this.setInternal({ $preferred_language: language });\n }\n\n /**\n * Timezone passed should be in {@link https://timeapi.io/documentation/iana-timezones IANA timezone format}.\n */\n async setTimezone(timezone: string) {\n if (typeof timezone !== 'string') {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'provided timezone is invalid, must be string',\n });\n }\n\n return this.setInternal({ $timezone: timezone });\n }\n}\n","import { SuprSend } from './index';\nimport { urlB64ToUint8Array, getResponsePayload, windowSupport } from './utils';\nimport { ERROR_TYPE, RESPONSE_STATUS } from './interface';\n\nexport default class WebPush {\n private config: SuprSend;\n\n constructor(config: SuprSend) {\n this.config = config;\n }\n\n private async getPushSubscription() {\n if (!windowSupport()) return;\n\n const registration = await navigator.serviceWorker.getRegistration();\n if (!registration) return;\n\n const subscription = registration.pushManager.getSubscription();\n if (!subscription) return;\n return subscription;\n }\n\n private async handleRegisterPush() {\n try {\n // register the service worker\n await navigator.serviceWorker.register(`/${this.config.swFileName}`);\n\n // request notification permission\n const permission = await Notification.requestPermission();\n if (permission !== 'granted') {\n console.warn('[SuprSend]: Notification permission isnt granted');\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.PERMISSION_DENIED,\n errorMessage: \"Notification permission isn't granted\",\n });\n }\n\n // wait until the service worker is ready\n const readyRegistration = await navigator.serviceWorker.ready;\n\n // if push subscribed present then do nothing\n const pushSubscriptionObj =\n await readyRegistration.pushManager.getSubscription();\n if (pushSubscriptionObj) {\n return this.config.user.addWebPush(pushSubscriptionObj);\n }\n\n if (!this.config.vapidKey) {\n console.warn(\n '[SuprSend]: Vapid key is missing. Add it while creating SuprSend instance'\n );\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage:\n 'Vapid key is missing. Add it while creating SuprSend instance',\n });\n }\n\n // get the push token object\n const subscription = await readyRegistration.pushManager.subscribe({\n userVisibleOnly: true,\n applicationServerKey: urlB64ToUint8Array(this.config.vapidKey),\n });\n\n // send push token object to suprsend\n return this.config.user.addWebPush(subscription);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (e: any) {\n console.warn('SuprSend: Error getting push subscription', e);\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.UNKNOWN_ERROR,\n errorMessage:\n e?.message || 'Unknown error occured while registering for push',\n });\n }\n }\n\n /**\n * Used to register push service. This method will\n * 1. Ask for notification permission.\n * 2. Register push service and generate webpush token.\n * 3. Send webpush token to SuprSend.\n */\n async registerPush() {\n const pushSupported =\n windowSupport() &&\n 'serviceWorker' in navigator &&\n 'PushManager' in window;\n\n if (pushSupported) {\n return this.handleRegisterPush();\n } else {\n console.warn(\"[SuprSend]: Webpush isn't supported\");\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.UNSUPPORTED_ACTION,\n errorMessage: \"Webpush isn't supported\",\n });\n }\n }\n\n async updatePushSubscription() {\n const subscription = await this.getPushSubscription();\n if (subscription) {\n return this.config.user.addWebPush(subscription);\n }\n }\n\n async removePushSubscription() {\n const subscription = await this.getPushSubscription();\n if (subscription) {\n return this.config.user.removeWebPush(subscription);\n }\n }\n\n /**\n * Used to get browser level permission to show notifications.\n */\n notificationPermission() {\n return Notification.permission;\n }\n\n /**\n * Used to check if push service is already active in browser.\n */\n async pushSubscribed() {\n const subscription = await this.getPushSubscription();\n return !!subscription;\n }\n}\n","export default function(n){return{all:n=n||new Map,on:function(t,e){var i=n.get(t);i?i.push(e):n.set(t,[e])},off:function(t,e){var i=n.get(t);i&&(e?i.splice(i.indexOf(e)>>>0,1):n.set(t,[]))},emit:function(t,e){var i=n.get(t);i&&i.slice().map(function(n){n(e)}),(i=n.get(\"*\"))&&i.slice().map(function(n){n(t,e)})}}}\n//# sourceMappingURL=mitt.mjs.map\n","import {\n SuprSendOptions,\n Dictionary,\n EmitterEvents,\n AuthenticateOptions,\n RefreshTokenCallback,\n ERROR_TYPE,\n RESPONSE_STATUS,\n} from './interface';\nimport ApiClient from './api';\nimport {\n uuid,\n epochMs,\n windowSupport,\n getResponsePayload,\n getLocalStorageData,\n setLocalStorageData,\n removeLocalStorageData,\n} from './utils';\nimport User from './user';\nimport WebPush from './webpush';\nimport mitt, { Emitter } from 'mitt';\nimport jwt_decode from 'jwt-decode';\n\nconst DEFAULT_HOST = 'https://hub.suprsend.com';\nconst DEFAULT_SW_FILENAME = 'serviceworker.js';\nconst AUTHENTICATED_DISTINCT_ID = 'ss_distinct_id';\n\nexport class SuprSend {\n public host: string;\n public publicApiKey: string;\n public distinctId: unknown;\n public userToken?: string;\n public vapidKey: string;\n public swFileName: string;\n private apiClient: ApiClient | null = null;\n private userTokenExpirationTimer: ReturnType<typeof setTimeout> | null = null;\n public authenticateOptions?: AuthenticateOptions;\n\n readonly user = new User(this);\n readonly webpush = new WebPush(this);\n readonly emitter: Emitter<EmitterEvents> = mitt();\n\n constructor(publicApiKey: string, options?: SuprSendOptions) {\n if (!publicApiKey) {\n throw new Error('[SuprSend]: publicApiKey is missing');\n }\n\n this.publicApiKey = publicApiKey;\n this.host = options?.host || DEFAULT_HOST;\n this.vapidKey = options?.vapidKey || '';\n this.swFileName = options?.swFileName || DEFAULT_SW_FILENAME;\n }\n\n private handleRefreshUserToken(refreshUserToken: RefreshTokenCallback) {\n if (!this.userToken || !windowSupport()) return;\n\n const jwtPayload = jwt_decode(this.userToken) as Dictionary;\n const expiresOn = ((jwtPayload.exp as number) || 0) * 1000; // in ms\n const now = Date.now(); // in ms\n const refreshBefore = 1000 * 30; // call refresh api before 30sec of expiry\n\n if (expiresOn && expiresOn > now) {\n const timeDiff = expiresOn - now - refreshBefore;\n\n if (this.userTokenExpirationTimer) {\n clearTimeout(this.userTokenExpirationTimer);\n }\n this.userTokenExpirationTimer = setTimeout(async () => {\n let newToken = '';\n try {\n newToken = await refreshUserToken(\n this.userToken as string,\n jwtPayload\n );\n } catch (e) {\n // retry fetching token\n try {\n newToken = await refreshUserToken(\n this.userToken as string,\n jwtPayload\n );\n } catch (e) {\n console.warn(\"[SuprSend]: Couldn't fetch new userToken\", e);\n }\n }\n\n if (newToken && typeof newToken === 'string') {\n this.identify(this.distinctId, newToken, this.authenticateOptions);\n }\n }, timeDiff);\n }\n }\n\n client() {\n if (!this.distinctId) {\n console.warn(\n '[SuprSend]: distinctId is missing. User should be authenticated'\n );\n }\n\n if (!this.apiClient) {\n this.apiClient = new ApiClient(this);\n }\n\n return this.apiClient;\n }\n\n eventApi(payload: Dictionary) {\n return this.client().request({ path: 'v2/event', payload, type: 'post' });\n }\n\n /**\n * Used to authenticate user. Usually called just after successful login and on reload of loggedin route to re-authenticate loggedin user.\n * In production env's userToken is mandatory for security purposes.\n */\n async identify(\n distinctId: unknown,\n userToken?: string,\n options?: AuthenticateOptions\n ) {\n if (!distinctId) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'distinctId is missing',\n });\n }\n\n // other user already present\n if (this.apiClient && this.distinctId && this.distinctId !== distinctId) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage:\n 'User already loggedin, reset current user to login new user',\n });\n }\n\n // updating usertoken for existing user\n if (\n this.apiClient &&\n this.distinctId === distinctId &&\n this.userToken !== userToken\n ) {\n this.userToken = userToken;\n this.apiClient = new ApiClient(this);\n if (options?.refreshUserToken) {\n this.handleRefreshUserToken(options.refreshUserToken);\n }\n return getResponsePayload({ status: RESPONSE_STATUS.SUCCESS });\n }\n\n // ignore more than one identify call\n if (this.distinctId && this.apiClient) {\n return getResponsePayload({ status: RESPONSE_STATUS.SUCCESS });\n }\n\n this.distinctId = distinctId;\n this.userToken = userToken;\n this.apiClient = new ApiClient(this);\n this.authenticateOptions = options;\n const authenticatedDistinctId = getLocalStorageData(\n AUTHENTICATED_DISTINCT_ID\n );\n\n if (options?.refreshUserToken) {\n this.handleRefreshUserToken(options.refreshUserToken);\n }\n\n // already loggedin\n if (authenticatedDistinctId == this.distinctId) {\n this.webpush.updatePushSubscription();\n return getResponsePayload({ status: RESPONSE_STATUS.SUCCESS });\n }\n\n // first time login\n const resp = await this.eventApi({\n event: '$identify',\n $insert_id: uuid(),\n $time: epochMs(),\n properties: {\n $identified_id: distinctId,\n },\n });\n\n if (resp.status === RESPONSE_STATUS.SUCCESS) {\n // store user so that other method calls dont need api calls\n this.webpush.updatePushSubscription();\n setLocalStorageData(AUTHENTICATED_DISTINCT_ID, this.distinctId as string);\n } else {\n // reset user data so that user can retry\n this.reset({ unsubscribePush: false });\n }\n return resp;\n }\n\n /**\n * Check's if SuprSend instance is authenticated. To check if userToken is also present pass true.\n */\n isIdentified(checkUserToken?: boolean) {\n return checkUserToken\n ? !!(this.userToken && this.distinctId)\n : !!this.distinctId;\n }\n\n /**\n * Used to trigger events to suprsend.\n */\n async track(event: string, properties?: Dictionary) {\n let propertiesObj: Dictionary = {};\n\n if (!event) {\n return getResponsePayload({\n status: RESPONSE_STATUS.ERROR,\n errorType: ERROR_TYPE.VALIDATION_ERROR,\n errorMessage: 'event name is missing',\n });\n }\n // TODO: add check to validate special keys\n if (typeof properties === 'object') {\n propertiesObj = { ...propertiesObj, ...properties };\n }\n\n return this.eventApi({\n event: String(event),\n $insert_id: uuid(),\n $time: epochMs(),\n distinct_id: this.distinctId,\n properties: propertiesObj,\n });\n }\n\n /**\n * Clears user related data attached to SuprSend instance. Usually called during logout.\n */\n async reset(options?: { unsubscribePush?: boolean }) {\n const unsubscribePush = !(options?.unsubscribePush === false); // defaults to true\n\n if (unsubscribePush) {\n await this.webpush?.removePushSubscription();\n }\n\n this.apiClient = null;\n this.distinctId = null;\n this.userToken = '';\n removeLocalStorageData(AUTHENTICATED_DISTINCT_ID);\n\n if (this.userTokenExpirationTimer) {\n clearTimeout(this.userTokenExpirationTimer);\n }\n return getResponsePayload({ status: RESPONSE_STATUS.SUCCESS });\n }\n}\n\nexport default SuprSend;\nexport * from './interface';\n"],"names":["PreferenceOptions","ChannelLevelPreferenceOptions","ERROR_TYPE","RESPONSE_STATUS","uuid","dt","c","epochMs","isObjectEmpty","objectName","isArrayEmpty","arrayName","urlB64ToUint8Array","base64String","padding","base64","rawData","outputArray","i","debounce","callback","wait","timer","args","resolve","debounceByType","func","memory","searchType","payload","getResponsePayload","options","response","windowSupport","setLocalStorageData","key","value","getLocalStorageData","removeLocalStorageData","e","r","t","n","o","a","ApiClient","config","__publicField","path","headers","reqData","url","_a","jwtPayload","jwt_decode","expiresOn","now","newUserToken","resp","respData","respStatus","_b","_c","Preferences","queryParams","validatedParams","qp","urlPath","validatedQueryParams","queryParamsString","category","body","subcategory","preference","categoryData","dataUpdated","section","abort","optOutChannels","channel","showOptOutChannels","requestPayload","selectedChannelData","channelData","preferenceRestricted","channelItem","DEVICE_ID_KEY","User","arg1","arg2","data","validatedData","allowReservedKeys","valueType","item","arg","email","mobile","deviceId","push","language","timezone","WebPush","registration","subscription","readyRegistration","pushSubscriptionObj","mitt","DEFAULT_HOST","DEFAULT_SW_FILENAME","AUTHENTICATED_DISTINCT_ID","SuprSend","publicApiKey","refreshUserToken","refreshBefore","timeDiff","newToken","distinctId","userToken","authenticatedDistinctId","checkUserToken","event","properties","propertiesObj"],"mappings":"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","x_google_ignoreList":[2,7]}
|