@suprsend/node-sdk 1.11.1 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,316 @@
1
+ import { is_string, InputValueError, SuprsendApiError } from "./utils";
2
+ import get_request_signature from "./signature";
3
+ import axios from "axios";
4
+ import ObjectEdit from "./object_edit";
5
+
6
+ export default class ObjectsApi {
7
+ constructor(config) {
8
+ this.config = config;
9
+ this.list_url = `${this.config.base_url}v1/object/`;
10
+ }
11
+
12
+ get_headers() {
13
+ return {
14
+ "Content-Type": "application/json; charset=utf-8",
15
+ "User-Agent": this.config.user_agent,
16
+ Date: new Date().toISOString(), // Adjust to your header date format
17
+ };
18
+ }
19
+
20
+ validate_object_type(object_type) {
21
+ if (!is_string(object_type)) {
22
+ throw new InputValueError("object_type must be a string");
23
+ }
24
+ object_type = object_type.trim();
25
+ if (!object_type) {
26
+ throw new InputValueError("missing object_type");
27
+ }
28
+ return object_type;
29
+ }
30
+
31
+ validate_object_id(object_id) {
32
+ if (!is_string(object_id)) {
33
+ throw new InputValueError("object_id must be a string");
34
+ }
35
+ object_id = object_id.trim();
36
+ if (!object_id) {
37
+ throw new InputValueError("missing object_id");
38
+ }
39
+ return object_id;
40
+ }
41
+
42
+ async list(object_type, options = {}) {
43
+ const params = new URLSearchParams(options).toString();
44
+ const validated_type = this.validate_object_type(object_type);
45
+ const encoded_type = encodeURIComponent(validated_type);
46
+ const url = `${this.list_url}${encoded_type}/?${params}`;
47
+ const headers = this.get_headers();
48
+ const signature = get_request_signature(
49
+ url,
50
+ "GET",
51
+ "",
52
+ headers,
53
+ this.config.workspace_secret
54
+ );
55
+ headers["Authorization"] = `${this.config.workspace_key}:${signature}`;
56
+
57
+ try {
58
+ const response = await axios.get(url, { headers });
59
+ return response.data;
60
+ } catch (err) {
61
+ throw new SuprsendApiError(err);
62
+ }
63
+ }
64
+
65
+ detail_url(object_type, object_id) {
66
+ const validated_type = this.validate_object_type(object_type);
67
+ const encoded_type = encodeURIComponent(validated_type);
68
+
69
+ const validated_id = this.validate_object_id(object_id);
70
+ const encoded_id = encodeURIComponent(validated_id);
71
+
72
+ return `${this.list_url}${encoded_type}/${encoded_id}/`;
73
+ }
74
+
75
+ async get(object_type, object_id) {
76
+ const url = this.detail_url(object_type, object_id);
77
+ const headers = this.get_headers();
78
+ const signature = get_request_signature(
79
+ url,
80
+ "GET",
81
+ "",
82
+ headers,
83
+ this.config.workspace_secret
84
+ );
85
+ headers["Authorization"] = `${this.config.workspace_key}:${signature}`;
86
+
87
+ try {
88
+ const response = await axios.get(url, { headers });
89
+ return response.data;
90
+ } catch (err) {
91
+ throw new SuprsendApiError(err);
92
+ }
93
+ }
94
+
95
+ async upsert(object_type, object_id, object_payload = {}) {
96
+ const url = this.detail_url(object_type, object_id);
97
+ const headers = this.get_headers();
98
+ const content_text = JSON.stringify(object_payload || {});
99
+ const signature = get_request_signature(
100
+ url,
101
+ "POST",
102
+ content_text,
103
+ headers,
104
+ this.config.workspace_secret
105
+ );
106
+ headers["Authorization"] = `${this.config.workspace_key}:${signature}`;
107
+
108
+ try {
109
+ const response = await axios.post(url, content_text, { headers });
110
+ return response.data;
111
+ } catch (err) {
112
+ throw new SuprsendApiError(err);
113
+ }
114
+ }
115
+
116
+ async edit(object_type, object_id, edit_payload = {}) {
117
+ let url, payload;
118
+
119
+ if (object_type instanceof ObjectEdit) {
120
+ const edit_instance = object_type;
121
+ edit_instance.validate_body();
122
+ url = this.detail_url(
123
+ edit_instance.get_object_type(),
124
+ edit_instance.get_object_id()
125
+ );
126
+ payload = edit_instance.get_payload();
127
+ } else {
128
+ url = this.detail_url(object_type, object_id);
129
+ payload = edit_payload;
130
+ }
131
+
132
+ const content_text = JSON.stringify(payload || {});
133
+ const headers = this.get_headers();
134
+ const signature = get_request_signature(
135
+ url,
136
+ "PATCH",
137
+ content_text,
138
+ headers,
139
+ this.config.workspace_secret
140
+ );
141
+ headers["Authorization"] = `${this.config.workspace_key}:${signature}`;
142
+
143
+ try {
144
+ const response = await axios.patch(url, content_text, { headers });
145
+ return response.data;
146
+ } catch (err) {
147
+ throw new SuprsendApiError(err);
148
+ }
149
+ }
150
+
151
+ async delete(object_type, object_id) {
152
+ const url = this.detail_url(object_type, object_id);
153
+ const headers = this.get_headers();
154
+ const signature = get_request_signature(
155
+ url,
156
+ "DELETE",
157
+ "",
158
+ headers,
159
+ this.config.workspace_secret
160
+ );
161
+ headers["Authorization"] = `${this.config.workspace_key}:${signature}`;
162
+
163
+ try {
164
+ const response = await axios.delete(url, { headers });
165
+ if (response.status >= 200 && response.status < 300) {
166
+ return { success: true, status_code: response.status };
167
+ } else {
168
+ throw new SuprsendApiError(response.statusText);
169
+ }
170
+ } catch (err) {
171
+ throw new SuprsendApiError(err);
172
+ }
173
+ }
174
+
175
+ async bulk_ops_url(object_type) {
176
+ const validatedType = this.validate_object_type(object_type);
177
+ const encodedType = encodeURIComponent(validatedType);
178
+
179
+ return `${this.config.base_url}v1/bulk/object/${encodedType}/`;
180
+ }
181
+
182
+ async bulk_delete(object_type, payload) {
183
+ const url = await this.bulk_ops_url(object_type);
184
+ const headers = this.get_headers();
185
+ payload = payload || {};
186
+ const content_text = JSON.stringify(payload);
187
+ const signature = get_request_signature(
188
+ url,
189
+ "DELETE",
190
+ content_text,
191
+ headers,
192
+ this.config.workspace_secret
193
+ );
194
+ headers["Authorization"] = `${this.config.workspace_key}:${signature}`;
195
+
196
+ try {
197
+ const response = await axios.delete(url, {
198
+ headers: headers,
199
+ data: payload,
200
+ });
201
+ if (response.status >= 200 && response.status < 300) {
202
+ return { success: true, status_code: response.status };
203
+ } else {
204
+ throw new SuprsendApiError(response.statusText);
205
+ }
206
+ } catch (err) {
207
+ throw new SuprsendApiError(err);
208
+ }
209
+ }
210
+
211
+ async get_subscriptions(object_type, object_id, options = {}) {
212
+ const params = new URLSearchParams(options).toString();
213
+ const url = this.detail_url(object_type, object_id);
214
+ const subscription_url = `${url}subscription/?${params}`;
215
+ const headers = this.get_headers();
216
+ const signature = get_request_signature(
217
+ subscription_url,
218
+ "GET",
219
+ "",
220
+ headers,
221
+ this.config.workspace_secret
222
+ );
223
+ headers["Authorization"] = `${this.config.workspace_key}:${signature}`;
224
+
225
+ try {
226
+ const response = await axios.get(subscription_url, { headers });
227
+ return response.data;
228
+ } catch (err) {
229
+ throw new SuprsendApiError(err);
230
+ }
231
+ }
232
+
233
+ async create_subscriptions(object_type, object_id, subscriptions) {
234
+ const url = this.detail_url(object_type, object_id);
235
+ const subscription_url = `${url}subscription/`;
236
+ const headers = this.get_headers();
237
+ subscriptions = subscriptions || {};
238
+ const content_text = JSON.stringify(subscriptions);
239
+ const signature = get_request_signature(
240
+ subscription_url,
241
+ "POST",
242
+ content_text,
243
+ headers,
244
+ this.config.workspace_secret
245
+ );
246
+ headers["Authorization"] = `${this.config.workspace_key}:${signature}`;
247
+
248
+ try {
249
+ const response = await axios.post(subscription_url, content_text, {
250
+ headers,
251
+ });
252
+ return response.data;
253
+ } catch (err) {
254
+ throw new SuprsendApiError(err);
255
+ }
256
+ }
257
+
258
+ async delete_subscriptions(object_type, object_id, subscriptions) {
259
+ const url = this.detail_url(object_type, object_id);
260
+ const subscription_url = `${url}subscription/`;
261
+ const headers = this.get_headers();
262
+ subscriptions = subscriptions || {};
263
+ const content_text = JSON.stringify(subscriptions);
264
+ const signature = get_request_signature(
265
+ subscription_url,
266
+ "DELETE",
267
+ content_text,
268
+ headers,
269
+ this.config.workspace_secret
270
+ );
271
+ headers["Authorization"] = `${this.config.workspace_key}:${signature}`;
272
+
273
+ try {
274
+ const response = await axios.delete(subscription_url, {
275
+ headers: headers,
276
+ data: subscriptions,
277
+ });
278
+ if (response.status >= 200 && response.status < 300) {
279
+ return { success: true, status_code: response.status };
280
+ } else {
281
+ throw new SuprsendApiError(response.statusText);
282
+ }
283
+ } catch (err) {
284
+ throw new SuprsendApiError(err);
285
+ }
286
+ }
287
+
288
+ async get_objects_subscribed_to(object_type, object_id, options = {}) {
289
+ const params = new URLSearchParams(options).toString();
290
+ const url = this.detail_url(object_type, object_id);
291
+ const subscription_url = `${url}subscribed_to/object/?${params}`;
292
+ const headers = this.get_headers();
293
+ const signature = get_request_signature(
294
+ subscription_url,
295
+ "GET",
296
+ "",
297
+ headers,
298
+ this.config.workspace_secret
299
+ );
300
+ headers["Authorization"] = `${this.config.workspace_key}:${signature}`;
301
+
302
+ try {
303
+ const response = await axios.get(subscription_url, { headers });
304
+ return response.data;
305
+ } catch (err) {
306
+ throw new SuprsendApiError(err);
307
+ }
308
+ }
309
+
310
+ get_instance(object_type, object_id) {
311
+ const validated_type = this.validate_object_type(object_type);
312
+ const validated_id = this.validate_object_id(object_id);
313
+
314
+ return new ObjectEdit(this.config, validated_type, validated_id);
315
+ }
316
+ }
package/src/subscriber.js CHANGED
@@ -120,7 +120,8 @@ export class Subscriber {
120
120
  if (is_part_of_bulk) {
121
121
  console.log(err_msg);
122
122
  } else {
123
- throw new InputValueError(err_msg);
123
+ // throw new InputValueError(err_msg);
124
+ console.log(err_msg);
124
125
  }
125
126
  }
126
127
  return this.__warnings_list;
@@ -1,11 +1,4 @@
1
- import {
2
- is_object,
3
- has_special_char,
4
- epoch_milliseconds,
5
- uuid,
6
- is_empty,
7
- is_string,
8
- } from "./utils";
1
+ import { is_object, has_special_char, is_empty, is_string } from "./utils";
9
2
  import ALL_LANG_CODES from "./language_codes";
10
3
 
11
4
  // ---------- Identity keys
@@ -29,14 +22,14 @@ const IDENT_KEYS_ALL = [
29
22
  IDENT_KEY_MS_TEAMS,
30
23
  ];
31
24
 
32
- const KEY_PUSHVENDOR = "$pushvendor";
25
+ const KEY_ID_PROVIDER = "$id_provider";
33
26
  const KEY_PREFERRED_LANGUAGE = "$preferred_language";
34
27
  const KEY_TIMEZONE = "$timezone";
35
28
 
36
29
  const OTHER_RESERVED_KEYS = [
37
30
  "$messenger",
38
31
  "$inbox",
39
- KEY_PUSHVENDOR,
32
+ KEY_ID_PROVIDER,
40
33
  "$device_id",
41
34
  "$insert_id",
42
35
  "$time",
@@ -75,9 +68,6 @@ const ALL_RESERVED_KEYS = [
75
68
  ...IDENT_KEYS_ALL,
76
69
  ];
77
70
 
78
- const EMAIL_REGEX = /\S+@\S+\.\S+/;
79
- const MOBILE_REGEX = /^\+[0-9\s]+/;
80
-
81
71
  export default class _SubscriberInternalHelper {
82
72
  constructor(distinct_id, workspace_key) {
83
73
  this.distinct_id = distinct_id;
@@ -274,13 +264,13 @@ export default class _SubscriberInternalHelper {
274
264
  this._add_whatsapp(value, new_caller);
275
265
  break;
276
266
  case IDENT_KEY_ANDROIDPUSH:
277
- this._add_androidpush(value, args[KEY_PUSHVENDOR], new_caller);
267
+ this._add_androidpush(value, args[KEY_ID_PROVIDER], new_caller);
278
268
  break;
279
269
  case IDENT_KEY_IOSPUSH:
280
- this._add_iospush(value, args[KEY_PUSHVENDOR], new_caller);
270
+ this._add_iospush(value, args[KEY_ID_PROVIDER], new_caller);
281
271
  break;
282
272
  case IDENT_KEY_WEBPUSH:
283
- this._add_webpush(value, args[KEY_PUSHVENDOR], new_caller);
273
+ this._add_webpush(value, args[KEY_ID_PROVIDER], new_caller);
284
274
  break;
285
275
  case IDENT_KEY_SLACK:
286
276
  this._add_slack(value, caller);
@@ -306,13 +296,13 @@ export default class _SubscriberInternalHelper {
306
296
  this._remove_whatsapp(value, new_caller);
307
297
  break;
308
298
  case IDENT_KEY_ANDROIDPUSH:
309
- this._remove_androidpush(value, args[KEY_PUSHVENDOR], new_caller);
299
+ this._remove_androidpush(value, args[KEY_ID_PROVIDER], new_caller);
310
300
  break;
311
301
  case IDENT_KEY_IOSPUSH:
312
- this._remove_iospush(value, args[KEY_PUSHVENDOR], new_caller);
302
+ this._remove_iospush(value, args[KEY_ID_PROVIDER], new_caller);
313
303
  break;
314
304
  case IDENT_KEY_WEBPUSH:
315
- this._remove_webpush(value, args[KEY_PUSHVENDOR], new_caller);
305
+ this._remove_webpush(value, args[KEY_ID_PROVIDER], new_caller);
316
306
  break;
317
307
  case IDENT_KEY_SLACK:
318
308
  this._remove_slack(val, caller);
@@ -339,31 +329,8 @@ export default class _SubscriberInternalHelper {
339
329
  return [value, true];
340
330
  }
341
331
 
342
- // email methods
343
- __validate_email(value, caller) {
344
- const [email, is_valid] = this.__check_ident_val_string(value, caller);
345
- if (!is_valid) {
346
- return [email, false];
347
- }
348
- const message = "value in email format required. e.g. user@example.com";
349
- const min_length = 6;
350
- const max_length = 127;
351
- const is_valid_email = EMAIL_REGEX.test(email);
352
- if (!is_valid_email) {
353
- this.__errors.push(`[${caller}] invalid value ${email}. ${message}`);
354
- return [email, false];
355
- }
356
- if (email.length < min_length || email.length > max_length) {
357
- this.__errors.push(
358
- `[${caller}] invalid value ${email}. must be 6 <= email.length <= 127`
359
- );
360
- return [email, false];
361
- }
362
- return [email, true];
363
- }
364
-
365
332
  _add_email(email, caller) {
366
- const [value, is_valid] = this.__validate_email(email, caller);
333
+ const [value, is_valid] = this.__check_ident_val_string(email, caller);
367
334
  if (!is_valid) {
368
335
  return;
369
336
  }
@@ -371,38 +338,15 @@ export default class _SubscriberInternalHelper {
371
338
  }
372
339
 
373
340
  _remove_email(email, caller) {
374
- const [value, is_valid] = this.__validate_email(email, caller);
341
+ const [value, is_valid] = this.__check_ident_val_string(email, caller);
375
342
  if (!is_valid) {
376
343
  return;
377
344
  }
378
345
  this.__dict_remove[IDENT_KEY_EMAIL] = value;
379
346
  }
380
347
 
381
- // mobile methods
382
- __validate_mobile_no(value, caller) {
383
- const [mobile, is_valid] = this.__check_ident_val_string(value, caller);
384
- if (!is_valid) {
385
- return [mobile, false];
386
- }
387
- const message =
388
- "number must start with + and must contain country code. e.g. +41446681800";
389
- const min_length = 8;
390
- const is_valid_mobile = MOBILE_REGEX.test(mobile);
391
- if (!is_valid_mobile) {
392
- this.__errors.push(`[${caller}] invalid value ${mobile}. ${message}`);
393
- return [mobile, false];
394
- }
395
- if (mobile.length < min_length) {
396
- this.__errors.push(
397
- `[${caller}] invalid value ${mobile}. mobile_no.length must be >= 8`
398
- );
399
- return [mobile, false];
400
- }
401
- return [mobile, true];
402
- }
403
-
404
348
  _add_sms(mobile_no, caller) {
405
- const [value, is_valid] = this.__validate_mobile_no(mobile_no, caller);
349
+ const [value, is_valid] = this.__check_ident_val_string(mobile_no, caller);
406
350
  if (!is_valid) {
407
351
  return;
408
352
  }
@@ -410,7 +354,7 @@ export default class _SubscriberInternalHelper {
410
354
  }
411
355
 
412
356
  _remove_sms(mobile_no, caller) {
413
- const [value, is_valid] = this.__validate_mobile_no(mobile_no, caller);
357
+ const [value, is_valid] = this.__check_ident_val_string(mobile_no, caller);
414
358
  if (!is_valid) {
415
359
  return;
416
360
  }
@@ -418,7 +362,7 @@ export default class _SubscriberInternalHelper {
418
362
  }
419
363
 
420
364
  _add_whatsapp(mobile_no, caller) {
421
- const [value, is_valid] = this.__validate_mobile_no(mobile_no, caller);
365
+ const [value, is_valid] = this.__check_ident_val_string(mobile_no, caller);
422
366
  if (!is_valid) {
423
367
  return;
424
368
  }
@@ -426,7 +370,7 @@ export default class _SubscriberInternalHelper {
426
370
  }
427
371
 
428
372
  _remove_whatsapp(mobile_no, caller) {
429
- const [value, is_valid] = this.__validate_mobile_no(mobile_no, caller);
373
+ const [value, is_valid] = this.__check_ident_val_string(mobile_no, caller);
430
374
  if (!is_valid) {
431
375
  return;
432
376
  }
@@ -440,17 +384,11 @@ export default class _SubscriberInternalHelper {
440
384
  return [push_token, provider, false];
441
385
  }
442
386
  if (!provider) {
443
- provider = "fcm";
387
+ provider = "";
444
388
  }
445
389
  if (typeof provider === "string") {
446
390
  provider = provider.toLocaleLowerCase();
447
391
  }
448
- if (!["fcm", "xiaomi", "oppo"].includes(provider)) {
449
- this.__errors.push(
450
- `[${caller}] unsupported androidpush provider ${provider}`
451
- );
452
- return [push_token, provider, false];
453
- }
454
392
  return [push_token, provider, true];
455
393
  }
456
394
 
@@ -464,7 +402,7 @@ export default class _SubscriberInternalHelper {
464
402
  return;
465
403
  }
466
404
  this.__dict_append[IDENT_KEY_ANDROIDPUSH] = value;
467
- this.__dict_append[KEY_PUSHVENDOR] = vendor;
405
+ this.__dict_append[KEY_ID_PROVIDER] = vendor;
468
406
  }
469
407
 
470
408
  _remove_androidpush(push_token, provider = "fcm") {
@@ -478,7 +416,7 @@ export default class _SubscriberInternalHelper {
478
416
  return;
479
417
  }
480
418
  this.__dict_remove[IDENT_KEY_ANDROIDPUSH] = value;
481
- this.__dict_remove[KEY_PUSHVENDOR] = vendor;
419
+ this.__dict_remove[KEY_ID_PROVIDER] = vendor;
482
420
  }
483
421
 
484
422
  // ios push methods
@@ -488,17 +426,11 @@ export default class _SubscriberInternalHelper {
488
426
  return [push_token, provider, false];
489
427
  }
490
428
  if (!provider) {
491
- provider = "apns";
429
+ provider = "";
492
430
  }
493
431
  if (typeof provider === "string") {
494
432
  provider = provider.toLocaleLowerCase();
495
433
  }
496
- if (!["apns"].includes(provider)) {
497
- this.__errors.push(
498
- `[${caller}] unsupported iospush provider ${provider}`
499
- );
500
- return [push_token, provider, false];
501
- }
502
434
  return [push_token, provider, true];
503
435
  }
504
436
 
@@ -512,7 +444,7 @@ export default class _SubscriberInternalHelper {
512
444
  return;
513
445
  }
514
446
  this.__dict_append[IDENT_KEY_IOSPUSH] = value;
515
- this.__dict_append[KEY_PUSHVENDOR] = vendor;
447
+ this.__dict_append[KEY_ID_PROVIDER] = vendor;
516
448
  }
517
449
 
518
450
  _remove_iospush(push_token, provider = "apns", caller) {
@@ -525,7 +457,7 @@ export default class _SubscriberInternalHelper {
525
457
  return;
526
458
  }
527
459
  this.__dict_remove[IDENT_KEY_IOSPUSH] = value;
528
- this.__dict_remove[KEY_PUSHVENDOR] = vendor;
460
+ this.__dict_remove[KEY_ID_PROVIDER] = vendor;
529
461
  }
530
462
 
531
463
  // web push methods
@@ -537,17 +469,11 @@ export default class _SubscriberInternalHelper {
537
469
  return [value, provider, false];
538
470
  }
539
471
  if (!provider) {
540
- provider = "vapid";
472
+ provider = "";
541
473
  }
542
474
  if (typeof provider === "string") {
543
475
  provider = provider.toLocaleLowerCase();
544
476
  }
545
- if (!["vapid"].includes(provider)) {
546
- this.__errors.push(
547
- `[${caller}] unsupported webpush provider ${provider}`
548
- );
549
- return [value, provider, false];
550
- }
551
477
  return [value, provider, true];
552
478
  }
553
479
 
@@ -561,7 +487,7 @@ export default class _SubscriberInternalHelper {
561
487
  return;
562
488
  }
563
489
  this.__dict_append[IDENT_KEY_WEBPUSH] = value;
564
- this.__dict_append[KEY_PUSHVENDOR] = vendor;
490
+ this.__dict_append[KEY_ID_PROVIDER] = vendor;
565
491
  }
566
492
 
567
493
  _remove_webpush(push_token, provider = "vapid", caller) {
@@ -574,7 +500,7 @@ export default class _SubscriberInternalHelper {
574
500
  return;
575
501
  }
576
502
  this.__dict_remove[IDENT_KEY_WEBPUSH] = value;
577
- this.__dict_remove[KEY_PUSHVENDOR] = vendor;
503
+ this.__dict_remove[KEY_ID_PROVIDER] = vendor;
578
504
  }
579
505
 
580
506
  __check_slack_dict(value, caller) {