@suprsend/node-sdk 1.1.0 → 1.1.2

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.
@@ -15,6 +15,8 @@ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/creat
15
15
 
16
16
  var _utils = require("./utils");
17
17
 
18
+ var _language_codes = _interopRequireDefault(require("./language_codes"));
19
+
18
20
  // ---------- Identity keys
19
21
  var IDENT_KEY_EMAIL = "$email";
20
22
  var IDENT_KEY_SMS = "$sms";
@@ -25,7 +27,8 @@ var IDENT_KEY_WEBPUSH = "$webpush";
25
27
  var IDENT_KEY_SLACK = "$slack";
26
28
  var IDENT_KEYS_ALL = [IDENT_KEY_EMAIL, IDENT_KEY_SMS, IDENT_KEY_ANDROIDPUSH, IDENT_KEY_IOSPUSH, IDENT_KEY_WHATSAPP, IDENT_KEY_WEBPUSH, IDENT_KEY_SLACK];
27
29
  var KEY_PUSHVENDOR = "$pushvendor";
28
- var OTHER_RESERVED_KEYS = ["$messenger", "$inbox", KEY_PUSHVENDOR, "$device_id", "$insert_id", "$time", "$set", "$set_once", "$add", "$append", "$remove", "$unset", "$identify", "$anon_id", "$identified_id", "$notification_delivered", "$notification_dismiss", "$notification_clicked"];
30
+ var KEY_PREFERRED_LANGUAGE = "$preferred_language";
31
+ var OTHER_RESERVED_KEYS = ["$messenger", "$inbox", KEY_PUSHVENDOR, "$device_id", "$insert_id", "$time", "$set", "$set_once", "$add", "$append", "$remove", "$unset", "$identify", "$anon_id", "$identified_id", KEY_PREFERRED_LANGUAGE, "$notification_delivered", "$notification_dismiss", "$notification_clicked"];
29
32
  var SUPER_PROPERTY_KEYS = ["$app_version_string", "$app_build_number", "$brand", "$carrier", "$manufacturer", "$model", "$os", "$ss_sdk_version", "$insert_id", "$time"];
30
33
  var ALL_RESERVED_KEYS = [].concat(SUPER_PROPERTY_KEYS, OTHER_RESERVED_KEYS, IDENT_KEYS_ALL);
31
34
  var EMAIL_REGEX = /\S+@\S+\.\S+/;
@@ -36,6 +39,8 @@ var _SubscriberInternalHelper = /*#__PURE__*/function () {
36
39
  (0, _classCallCheck2["default"])(this, _SubscriberInternalHelper);
37
40
  this.distinct_id = distinct_id;
38
41
  this.workspace_key = workspace_key;
42
+ this.__dict_set = {};
43
+ this.__set_count = 0;
39
44
  this.__dict_append = {};
40
45
  this.__append_count = 0;
41
46
  this.__dict_remove = {};
@@ -49,6 +54,8 @@ var _SubscriberInternalHelper = /*#__PURE__*/function () {
49
54
  (0, _createClass2["default"])(_SubscriberInternalHelper, [{
50
55
  key: "reset",
51
56
  value: function reset() {
57
+ this.__dict_set = {};
58
+ this.__set_count = 0;
52
59
  this.__dict_append = {};
53
60
  this.__append_count = 0;
54
61
  this.__dict_remove = {};
@@ -67,6 +74,7 @@ var _SubscriberInternalHelper = /*#__PURE__*/function () {
67
74
  errors: this.__errors,
68
75
  info: this.__info,
69
76
  event: evt,
77
+ set: this.__set_count,
70
78
  append: this.__append_count,
71
79
  remove: this.__remove_count,
72
80
  unset: this.__unset_count
@@ -77,7 +85,7 @@ var _SubscriberInternalHelper = /*#__PURE__*/function () {
77
85
  }, {
78
86
  key: "__form_event",
79
87
  value: function __form_event() {
80
- if (!(0, _utils.is_empty)(this.__dict_append) || !(0, _utils.is_empty)(this.__dict_remove) || !(0, _utils.is_empty)(this.__list_unset)) {
88
+ if (!(0, _utils.is_empty)(this.__dict_set) || !(0, _utils.is_empty)(this.__dict_append) || !(0, _utils.is_empty)(this.__dict_remove) || !(0, _utils.is_empty)(this.__list_unset)) {
81
89
  var event = {
82
90
  $insert_id: (0, _utils.uuid)(),
83
91
  $time: (0, _utils.epoch_milliseconds)(),
@@ -85,6 +93,11 @@ var _SubscriberInternalHelper = /*#__PURE__*/function () {
85
93
  distinct_id: this.distinct_id
86
94
  };
87
95
 
96
+ if (!(0, _utils.is_empty)(this.__dict_set)) {
97
+ event["$set"] = this.__dict_set;
98
+ this.__set_count += 1;
99
+ }
100
+
88
101
  if (!(0, _utils.is_empty)(this.__dict_append)) {
89
102
  event["$append"] = this.__dict_append;
90
103
  this.__append_count += 1;
@@ -208,6 +221,17 @@ var _SubscriberInternalHelper = /*#__PURE__*/function () {
208
221
 
209
222
  this.__list_unset.push(validated_key);
210
223
  }
224
+ }, {
225
+ key: "_set_preferred_language",
226
+ value: function _set_preferred_language(lang_code, caller) {
227
+ if (!_language_codes["default"].includes(lang_code)) {
228
+ this.__info.push("[".concat(caller, "] invalid value ").concat(lang_code));
229
+
230
+ return;
231
+ }
232
+
233
+ this.__dict_set[KEY_PREFERRED_LANGUAGE] = lang_code;
234
+ }
211
235
  }, {
212
236
  key: "__add_identity",
213
237
  value: function __add_identity(key, value, args, caller) {
package/dist/utils.js CHANGED
@@ -5,7 +5,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
5
5
  Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
- exports.SuprsendError = exports.SuprsendConfigError = void 0;
8
+ exports.SuprsendError = exports.SuprsendConfigError = exports.SuprsendApiError = void 0;
9
9
  exports.base64Encode = base64Encode;
10
10
  exports.epoch_milliseconds = epoch_milliseconds;
11
11
  exports.get_apparent_event_size = get_apparent_event_size;
@@ -114,6 +114,33 @@ var SuprsendConfigError = /*#__PURE__*/function (_Error2) {
114
114
 
115
115
  exports.SuprsendConfigError = SuprsendConfigError;
116
116
 
117
+ var SuprsendApiError = /*#__PURE__*/function (_Error3) {
118
+ (0, _inherits2["default"])(SuprsendApiError, _Error3);
119
+
120
+ var _super3 = _createSuper(SuprsendApiError);
121
+
122
+ function SuprsendApiError(error) {
123
+ var _this3;
124
+
125
+ (0, _classCallCheck2["default"])(this, SuprsendApiError);
126
+ var message;
127
+
128
+ if (error.response) {
129
+ message = "".concat(error.response.status, ": ").concat(error.response.data.message);
130
+ } else {
131
+ message = error.message;
132
+ }
133
+
134
+ _this3 = _super3.call(this, message);
135
+ _this3.name = "SuprsendApiError";
136
+ return _this3;
137
+ }
138
+
139
+ return SuprsendApiError;
140
+ }( /*#__PURE__*/(0, _wrapNativeSuper2["default"])(Error));
141
+
142
+ exports.SuprsendApiError = SuprsendApiError;
143
+
117
144
  function is_string(value) {
118
145
  return typeof value === "string";
119
146
  }
package/dist/workflow.js CHANGED
@@ -38,6 +38,7 @@ var Workflow = /*#__PURE__*/function () {
38
38
 
39
39
  this.body = body;
40
40
  this.idempotency_key = kwargs === null || kwargs === void 0 ? void 0 : kwargs.idempotency_key;
41
+ this.brand_id = kwargs === null || kwargs === void 0 ? void 0 : kwargs.brand_id;
41
42
  }
42
43
 
43
44
  (0, _createClass2["default"])(Workflow, [{
@@ -76,6 +77,10 @@ var Workflow = /*#__PURE__*/function () {
76
77
  this.body["$idempotency_key"] = this.idempotency_key;
77
78
  }
78
79
 
80
+ if (this.brand_id) {
81
+ this.body["brand_id"] = this.brand_id;
82
+ }
83
+
79
84
  this.body = (0, _utils.validate_workflow_body_schema)(this.body);
80
85
  var apparent_size = (0, _utils.get_apparent_workflow_body_size)(this.body, is_part_of_bulk); // review
81
86
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suprsend/node-sdk",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Suprsend Node SDK to trigger workflow from backend",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
package/src/brands.js ADDED
@@ -0,0 +1,120 @@
1
+ import get_request_signature from "./signature";
2
+ import { SuprsendApiError } from "./utils";
3
+ import axios from "axios";
4
+
5
+ class BrandsApi {
6
+ constructor(config) {
7
+ this.config = config;
8
+ this.list_url = this.__list_url();
9
+ this.__headers = this.__common_headers();
10
+ }
11
+
12
+ __list_url() {
13
+ const list_uri_template = `${this.config.base_url}v1/brand/`;
14
+ return list_uri_template;
15
+ }
16
+
17
+ __common_headers() {
18
+ return {
19
+ "Content-Type": "application/json; charset=utf-8",
20
+ "User-Agent": this.config.user_agent,
21
+ };
22
+ }
23
+
24
+ cleaned_limit_offset(limit, offset) {
25
+ let cleaned_limit =
26
+ typeof limit === "number" && limit > 0 && limit <= 1000 ? limit : 20;
27
+ let cleaned_offset = typeof offset === "number" && offset >= 0 ? offset : 0;
28
+ return [cleaned_limit, cleaned_offset];
29
+ }
30
+
31
+ __dynamic_headers() {
32
+ return {
33
+ Date: new Date().toUTCString(),
34
+ };
35
+ }
36
+
37
+ async list(kwargs = {}) {
38
+ const limit = kwargs?.limit;
39
+ const offset = kwargs?.offset;
40
+ const [cleaned_limit, cleaner_offset] = this.cleaned_limit_offset(
41
+ limit,
42
+ offset
43
+ );
44
+ const final_url_obj = new URL(this.list_url);
45
+ final_url_obj.searchParams.append("limit", cleaned_limit);
46
+ final_url_obj.searchParams.append("offset", cleaner_offset);
47
+ const final_url_string = final_url_obj.href;
48
+
49
+ const headers = { ...this.__headers, ...this.__dynamic_headers() };
50
+
51
+ const signature = get_request_signature(
52
+ final_url_string,
53
+ "GET",
54
+ "",
55
+ headers,
56
+ this.config.workspace_secret
57
+ );
58
+ headers["Authorization"] = `${this.config.workspace_key}:${signature}`;
59
+
60
+ try {
61
+ const response = await axios.get(final_url_string, { headers });
62
+ return response.data;
63
+ } catch (err) {
64
+ throw new SuprsendApiError(err);
65
+ }
66
+ }
67
+
68
+ detail_url(brand_id = "") {
69
+ const cleaned_brand_id = brand_id.toString().trim();
70
+ const brand_id_encoded = encodeURI(cleaned_brand_id);
71
+ const url = `${this.list_url}${brand_id_encoded}/`;
72
+ return url;
73
+ }
74
+
75
+ async get(brand_id = "") {
76
+ const url = this.detail_url(brand_id);
77
+
78
+ const headers = { ...this.__headers, ...this.__dynamic_headers() };
79
+ const signature = get_request_signature(
80
+ url,
81
+ "GET",
82
+ "",
83
+ headers,
84
+ this.config.workspace_secret
85
+ );
86
+ headers["Authorization"] = `${this.config.workspace_key}:${signature}`;
87
+
88
+ try {
89
+ const response = await axios.get(url, { headers });
90
+ return response.data;
91
+ } catch (err) {
92
+ throw new SuprsendApiError(err);
93
+ }
94
+ }
95
+
96
+ async upsert(brand_id = "", brand_payload = {}) {
97
+ const url = this.detail_url(brand_id);
98
+
99
+ const headers = { ...this.__headers, ...this.__dynamic_headers() };
100
+ const content_text = JSON.stringify(brand_payload);
101
+
102
+ const signature = get_request_signature(
103
+ url,
104
+ "POST",
105
+ content_text,
106
+ headers,
107
+ this.config.workspace_secret
108
+ );
109
+ headers["Authorization"] = `${this.config.workspace_key}:${signature}`;
110
+
111
+ try {
112
+ const response = await axios.post(url, content_text, { headers });
113
+ return response.data;
114
+ } catch (err) {
115
+ throw new SuprsendApiError(err);
116
+ }
117
+ }
118
+ }
119
+
120
+ export default BrandsApi;
package/src/event.js CHANGED
@@ -32,6 +32,7 @@ export default class Event {
32
32
  this.event_name = event_name;
33
33
  this.properties = properties;
34
34
  this.idempotency_key = kwargs?.idempotency_key;
35
+ this.brand_id = kwargs?.brand_id;
35
36
  // --- validate
36
37
  this.__validate_distinct_id();
37
38
  this.__validate_event_name();
@@ -107,6 +108,9 @@ export default class Event {
107
108
  if (this.idempotency_key) {
108
109
  event_dict["$idempotency_key"] = this.idempotency_key;
109
110
  }
111
+ if (this.brand_id) {
112
+ event_dict["brand_id"] = this.brand_id;
113
+ }
110
114
  event_dict = validate_track_event_schema(event_dict);
111
115
  const apparent_size = get_apparent_event_size(event_dict, is_part_of_bulk);
112
116
  if (apparent_size > SINGLE_EVENT_MAX_APPARENT_SIZE_IN_BYTES) {
package/src/index.js CHANGED
@@ -6,6 +6,7 @@ import Event, { EventCollector } from "./event";
6
6
  import { BulkEventsFactory } from "./events_bulk";
7
7
  import SubscriberFactory from "./subscriber";
8
8
  import BulkSubscribersFactory from "./subscribers_bulk";
9
+ import BrandsApi from "./brands";
9
10
  import { DEFAULT_UAT_URL, DEFAULT_URL } from "./constants";
10
11
 
11
12
  const package_json = require("../package.json");
@@ -31,6 +32,9 @@ class Suprsend {
31
32
  this._bulk_users = new BulkSubscribersFactory(this);
32
33
 
33
34
  this._user = new SubscriberFactory(this);
35
+
36
+ this.brands = new BrandsApi(this);
37
+
34
38
  this._validate();
35
39
  }
36
40
 
@@ -0,0 +1,188 @@
1
+ const LANG_CODE_NAME_MAPPING = {
2
+ aa: "Afar",
3
+ ab: "Abkhazian",
4
+ ae: "Avestan",
5
+ af: "Afrikaans",
6
+ ak: "Akan",
7
+ am: "Amharic",
8
+ an: "Aragonese",
9
+ ar: "Arabic",
10
+ as: "Assamese",
11
+ av: "Avaric",
12
+ ay: "Aymara",
13
+ az: "Azerbaijani",
14
+ ba: "Bashkir",
15
+ be: "Belarusian",
16
+ bg: "Bulgarian",
17
+ bi: "Bislama",
18
+ bm: "Bambara",
19
+ bn: "Bengali",
20
+ bo: "Tibetan",
21
+ br: "Breton",
22
+ bs: "Bosnian",
23
+ ca: "Catalan; Valencian",
24
+ ce: "Chechen",
25
+ ch: "Chamorro",
26
+ co: "Corsican",
27
+ cr: "Cree",
28
+ cs: "Czech",
29
+ cu: "Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic",
30
+ cv: "Chuvash",
31
+ cy: "Welsh",
32
+ da: "Danish",
33
+ de: "German",
34
+ dv: "Divehi; Dhivehi; Maldivian",
35
+ dz: "Dzongkha",
36
+ ee: "Ewe",
37
+ el: "Greek, Modern (1453-)",
38
+ en: "English",
39
+ eo: "Esperanto",
40
+ es: "Spanish; Castilian",
41
+ et: "Estonian",
42
+ eu: "Basque",
43
+ fa: "Persian",
44
+ ff: "Fulah",
45
+ fi: "Finnish",
46
+ fj: "Fijian",
47
+ fo: "Faroese",
48
+ fr: "French",
49
+ fy: "Western Frisian",
50
+ ga: "Irish",
51
+ gd: "Gaelic; Scottish Gaelic",
52
+ gl: "Galician",
53
+ gn: "Guarani",
54
+ gu: "Gujarati",
55
+ gv: "Manx",
56
+ ha: "Hausa",
57
+ he: "Hebrew",
58
+ hi: "Hindi",
59
+ ho: "Hiri Motu",
60
+ hr: "Croatian",
61
+ ht: "Haitian; Haitian Creole",
62
+ hu: "Hungarian",
63
+ hy: "Armenian",
64
+ hz: "Herero",
65
+ ia: "Interlingua (International Auxiliary Language Association)",
66
+ id: "Indonesian",
67
+ ie: "Interlingue; Occidental",
68
+ ig: "Igbo",
69
+ ii: "Sichuan Yi; Nuosu",
70
+ ik: "Inupiaq",
71
+ io: "Ido",
72
+ is: "Icelandic",
73
+ it: "Italian",
74
+ iu: "Inuktitut",
75
+ ja: "Japanese",
76
+ jv: "Javanese",
77
+ ka: "Georgian",
78
+ kg: "Kongo",
79
+ ki: "Kikuyu; Gikuyu",
80
+ kj: "Kuanyama; Kwanyama",
81
+ kk: "Kazakh",
82
+ kl: "Kalaallisut; Greenlandic",
83
+ km: "Central Khmer",
84
+ kn: "Kannada",
85
+ ko: "Korean",
86
+ kr: "Kanuri",
87
+ ks: "Kashmiri",
88
+ ku: "Kurdish",
89
+ kv: "Komi",
90
+ kw: "Cornish",
91
+ ky: "Kirghiz; Kyrgyz",
92
+ la: "Latin",
93
+ lb: "Luxembourgish; Letzeburgesch",
94
+ lg: "Ganda",
95
+ li: "Limburgan; Limburger; Limburgish",
96
+ ln: "Lingala",
97
+ lo: "Lao",
98
+ lt: "Lithuanian",
99
+ lu: "Luba-Katanga",
100
+ lv: "Latvian",
101
+ mg: "Malagasy",
102
+ mh: "Marshallese",
103
+ mi: "Maori",
104
+ mk: "Macedonian",
105
+ ml: "Malayalam",
106
+ mn: "Mongolian",
107
+ mr: "Marathi",
108
+ ms: "Malay",
109
+ mt: "Maltese",
110
+ my: "Burmese",
111
+ na: "Nauru",
112
+ nb: "Bokmål, Norwegian; Norwegian Bokmål",
113
+ nd: "Ndebele, North; North Ndebele",
114
+ ne: "Nepali",
115
+ ng: "Ndonga",
116
+ nl: "Dutch; Flemish",
117
+ nn: "Norwegian Nynorsk; Nynorsk, Norwegian",
118
+ no: "Norwegian",
119
+ nr: "Ndebele, South; South Ndebele",
120
+ nv: "Navajo; Navaho",
121
+ ny: "Chichewa; Chewa; Nyanja",
122
+ oc: "Occitan (post 1500)",
123
+ oj: "Ojibwa",
124
+ om: "Oromo",
125
+ or: "Oriya",
126
+ os: "Ossetian; Ossetic",
127
+ pa: "Panjabi; Punjabi",
128
+ pi: "Pali",
129
+ pl: "Polish",
130
+ ps: "Pushto; Pashto",
131
+ pt: "Portuguese",
132
+ qu: "Quechua",
133
+ rm: "Romansh",
134
+ rn: "Rundi",
135
+ ro: "Romanian; Moldavian; Moldovan",
136
+ ru: "Russian",
137
+ rw: "Kinyarwanda",
138
+ sa: "Sanskrit",
139
+ sc: "Sardinian",
140
+ sd: "Sindhi",
141
+ se: "Northern Sami",
142
+ sg: "Sango",
143
+ si: "Sinhala; Sinhalese",
144
+ sk: "Slovak",
145
+ sl: "Slovenian",
146
+ sm: "Samoan",
147
+ sn: "Shona",
148
+ so: "Somali",
149
+ sq: "Albanian",
150
+ sr: "Serbian",
151
+ ss: "Swati",
152
+ st: "Sotho, Southern",
153
+ su: "Sundanese",
154
+ sv: "Swedish",
155
+ sw: "Swahili",
156
+ ta: "Tamil",
157
+ te: "Telugu",
158
+ tg: "Tajik",
159
+ th: "Thai",
160
+ ti: "Tigrinya",
161
+ tk: "Turkmen",
162
+ tl: "Tagalog",
163
+ tn: "Tswana",
164
+ to: "Tonga (Tonga Islands)",
165
+ tr: "Turkish",
166
+ ts: "Tsonga",
167
+ tt: "Tatar",
168
+ tw: "Twi",
169
+ ty: "Tahitian",
170
+ ug: "Uighur; Uyghur",
171
+ uk: "Ukrainian",
172
+ ur: "Urdu",
173
+ uz: "Uzbek",
174
+ ve: "Venda",
175
+ vi: "Vietnamese",
176
+ vo: "Volapük",
177
+ wa: "Walloon",
178
+ wo: "Wolof",
179
+ xh: "Xhosa",
180
+ yi: "Yiddish",
181
+ yo: "Yoruba",
182
+ za: "Zhuang; Chuang",
183
+ zh: "Chinese",
184
+ zu: "Zulu",
185
+ };
186
+
187
+ const ALL_LANG_CODES = [...new Set(Object.keys(LANG_CODE_NAME_MAPPING))];
188
+ export default ALL_LANG_CODES;
@@ -11,6 +11,11 @@
11
11
  "maxLength": 64,
12
12
  "description": "unique id provided by client for request"
13
13
  },
14
+ "brand_id": {
15
+ "type": ["string", "null"],
16
+ "maxLength": 64,
17
+ "description": "brand id for workflow to be run in context of a brand"
18
+ },
14
19
  "$insert_id": {
15
20
  "type": "string",
16
21
  "minLength": 36,
@@ -11,6 +11,11 @@
11
11
  "maxLength": 64,
12
12
  "description": "unique id provided by client for request"
13
13
  },
14
+ "brand_id": {
15
+ "type": ["string", "null"],
16
+ "maxLength": 64,
17
+ "description": "brand id for workflow to be run in context of a brand"
18
+ },
14
19
  "name": {
15
20
  "$ref": "#/definitions/non_empty_string",
16
21
  "description": "name of workflow"
package/src/signature.js CHANGED
@@ -12,17 +12,18 @@ export default function get_request_signature(
12
12
  headers,
13
13
  secret
14
14
  ) {
15
- if (http_verb === "GET") {
16
- return "";
15
+ let content_md5 = "";
16
+ let content_type = headers["Content-Type"] || "";
17
+ if (content) {
18
+ content_md5 = crypto.createHash("md5").update(content).digest("hex");
17
19
  }
18
- const content_md5 = crypto.createHash("md5").update(content).digest("hex");
19
20
  const request_uri = get_path(url);
20
21
  const sign_string =
21
22
  http_verb +
22
23
  "\n" +
23
24
  content_md5 +
24
25
  "\n" +
25
- headers["Content-Type"] +
26
+ content_type +
26
27
  "\n" +
27
28
  headers["Date"] +
28
29
  "\n" +
package/src/subscriber.js CHANGED
@@ -50,6 +50,7 @@ export class Subscriber {
50
50
  this.__info = [];
51
51
  this._append_count = 0;
52
52
  this._remove_count = 0;
53
+ this._set_count = 0;
53
54
  this._unset_count = 0;
54
55
  this._events = [];
55
56
  this._helper = new _SubscriberInternalHelper(
@@ -90,7 +91,11 @@ export class Subscriber {
90
91
  e["properties"] = this.__supr_props;
91
92
  }
92
93
 
93
- if (all_events.length === 0 || this._append_count > 0) {
94
+ if (
95
+ all_events.length === 0 ||
96
+ this._append_count > 0 ||
97
+ this._set_count > 0
98
+ ) {
94
99
  const user_identify_event = {
95
100
  $insert_id: uuid(),
96
101
  $time: epoch_milliseconds(),
@@ -196,6 +201,7 @@ export class Subscriber {
196
201
  }
197
202
  if (!is_empty(resp["event"])) {
198
203
  this._events.push(resp["event"]);
204
+ this._set_count += resp["set"];
199
205
  this._append_count += resp["append"];
200
206
  this._remove_count += resp["remove"];
201
207
  this._unset_count += resp["unset"];
@@ -267,6 +273,12 @@ export class Subscriber {
267
273
  }
268
274
  }
269
275
 
276
+ set_preferred_language(lang_code) {
277
+ const caller = "set_preferred_language";
278
+ this._helper._set_preferred_language(lang_code, caller);
279
+ this._collect_event();
280
+ }
281
+
270
282
  add_email(email) {
271
283
  const caller = "add_email";
272
284
  this._helper._add_email(email, caller);
@@ -6,6 +6,7 @@ import {
6
6
  is_empty,
7
7
  is_string,
8
8
  } from "./utils";
9
+ import ALL_LANG_CODES from "./language_codes";
9
10
 
10
11
  // ---------- Identity keys
11
12
  const IDENT_KEY_EMAIL = "$email";
@@ -27,6 +28,7 @@ const IDENT_KEYS_ALL = [
27
28
  ];
28
29
 
29
30
  const KEY_PUSHVENDOR = "$pushvendor";
31
+ const KEY_PREFERRED_LANGUAGE = "$preferred_language";
30
32
 
31
33
  const OTHER_RESERVED_KEYS = [
32
34
  "$messenger",
@@ -44,6 +46,7 @@ const OTHER_RESERVED_KEYS = [
44
46
  "$identify",
45
47
  "$anon_id",
46
48
  "$identified_id",
49
+ KEY_PREFERRED_LANGUAGE,
47
50
  "$notification_delivered",
48
51
  "$notification_dismiss",
49
52
  "$notification_clicked",
@@ -76,6 +79,9 @@ export default class _SubscriberInternalHelper {
76
79
  this.distinct_id = distinct_id;
77
80
  this.workspace_key = workspace_key;
78
81
 
82
+ this.__dict_set = {};
83
+ this.__set_count = 0;
84
+
79
85
  this.__dict_append = {};
80
86
  this.__append_count = 0;
81
87
 
@@ -90,6 +96,9 @@ export default class _SubscriberInternalHelper {
90
96
  }
91
97
 
92
98
  reset() {
99
+ this.__dict_set = {};
100
+ this.__set_count = 0;
101
+
93
102
  this.__dict_append = {};
94
103
  this.__append_count = 0;
95
104
 
@@ -109,6 +118,7 @@ export default class _SubscriberInternalHelper {
109
118
  errors: this.__errors,
110
119
  info: this.__info,
111
120
  event: evt,
121
+ set: this.__set_count,
112
122
  append: this.__append_count,
113
123
  remove: this.__remove_count,
114
124
  unset: this.__unset_count,
@@ -119,6 +129,7 @@ export default class _SubscriberInternalHelper {
119
129
 
120
130
  __form_event() {
121
131
  if (
132
+ !is_empty(this.__dict_set) ||
122
133
  !is_empty(this.__dict_append) ||
123
134
  !is_empty(this.__dict_remove) ||
124
135
  !is_empty(this.__list_unset)
@@ -129,6 +140,10 @@ export default class _SubscriberInternalHelper {
129
140
  env: this.workspace_key,
130
141
  distinct_id: this.distinct_id,
131
142
  };
143
+ if (!is_empty(this.__dict_set)) {
144
+ event["$set"] = this.__dict_set;
145
+ this.__set_count += 1;
146
+ }
132
147
  if (!is_empty(this.__dict_append)) {
133
148
  event["$append"] = this.__dict_append;
134
149
  this.__append_count += 1;
@@ -216,6 +231,14 @@ export default class _SubscriberInternalHelper {
216
231
  this.__list_unset.push(validated_key);
217
232
  }
218
233
 
234
+ _set_preferred_language(lang_code, caller) {
235
+ if (!ALL_LANG_CODES.includes(lang_code)) {
236
+ this.__info.push(`[${caller}] invalid value ${lang_code}`);
237
+ return;
238
+ }
239
+ this.__dict_set[KEY_PREFERRED_LANGUAGE] = lang_code;
240
+ }
241
+
219
242
  __add_identity(key, value, args, caller) {
220
243
  switch (key) {
221
244
  case IDENT_KEY_EMAIL:
package/src/utils.js CHANGED
@@ -44,6 +44,19 @@ export class SuprsendConfigError extends Error {
44
44
  }
45
45
  }
46
46
 
47
+ export class SuprsendApiError extends Error {
48
+ constructor(error) {
49
+ let message;
50
+ if (error.response) {
51
+ message = `${error.response.status}: ${error.response.data.message}`;
52
+ } else {
53
+ message = error.message;
54
+ }
55
+ super(message);
56
+ this.name = "SuprsendApiError";
57
+ }
58
+ }
59
+
47
60
  export function is_string(value) {
48
61
  return typeof value === "string";
49
62
  }