@twilio/conversations 2.0.0-rc.1 → 2.0.1-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/README.md +22 -17
  3. package/dist/browser.js +2348 -2683
  4. package/dist/browser.js.map +1 -1
  5. package/dist/docs/assets/js/search.js +1 -1
  6. package/dist/docs/classes/AggregatedDeliveryReceipt.html +22 -6
  7. package/dist/docs/classes/Client.html +78 -33
  8. package/dist/docs/classes/Conversation.html +33 -17
  9. package/dist/docs/classes/DetailedDeliveryReceipt.html +22 -6
  10. package/dist/docs/classes/Media.html +23 -7
  11. package/dist/docs/classes/Message.html +23 -7
  12. package/dist/docs/classes/MessageBuilder.html +3280 -0
  13. package/dist/docs/classes/Participant.html +23 -7
  14. package/dist/docs/classes/PushNotification.html +24 -8
  15. package/dist/docs/classes/RestPaginator.html +28 -9
  16. package/dist/docs/classes/UnsentMessage.html +3144 -0
  17. package/dist/docs/classes/User.html +25 -9
  18. package/dist/docs/index.html +86 -38
  19. package/dist/docs/interfaces/ClientOptions.html +22 -6
  20. package/dist/docs/interfaces/ConversationState.html +22 -6
  21. package/dist/docs/interfaces/CreateConversationOptions.html +22 -6
  22. package/dist/docs/interfaces/LastMessage.html +22 -6
  23. package/dist/docs/interfaces/Paginator.html +3243 -0
  24. package/dist/docs/interfaces/PushNotificationData.html +3168 -0
  25. package/dist/docs/interfaces/SendEmailOptions.html +22 -6
  26. package/dist/docs/interfaces/SendMediaOptions.html +24 -7
  27. package/dist/docs/modules.html +85 -37
  28. package/dist/lib.d.ts +250 -59
  29. package/dist/lib.js +2278 -2142
  30. package/dist/lib.js.map +1 -1
  31. package/dist/react-native.js +502 -879
  32. package/dist/react-native.js.map +1 -1
  33. package/dist/twilio-conversations.js +25174 -23917
  34. package/dist/twilio-conversations.min.js +14 -2
  35. package/package.json +11 -9
@@ -132,15 +132,18 @@ Object.defineProperty(exports, '__esModule', { value: true });
132
132
 
133
133
  var loglevelLog = require('loglevel');
134
134
  var iso8601Duration = require('iso8601-duration');
135
+ var declarativeTypeValidator = require('@twilio/declarative-type-validator');
136
+ var replayEventEmitter = require('@twilio/replay-event-emitter');
137
+ var isEqual = require('lodash.isequal');
135
138
  var operationRetrier = require('@twilio/operation-retrier');
136
139
  var twilsock = require('twilsock');
137
140
  var notifications = require('@twilio/notifications');
138
141
  var twilioSync = require('twilio-sync');
139
142
  var mcsClient = require('@twilio/mcs-client');
140
- var JsonDiff = require('rfc6902');
141
- var declarativeTypeValidator = require('@twilio/declarative-type-validator');
142
143
  var uuid = require('uuid');
143
144
 
145
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
146
+
144
147
  function _interopNamespace(e) {
145
148
  if (e && e.__esModule) return e;
146
149
  var n = Object.create(null);
@@ -162,7 +165,7 @@ function _interopNamespace(e) {
162
165
  }
163
166
 
164
167
  var loglevelLog__namespace = /*#__PURE__*/_interopNamespace(loglevelLog);
165
- var JsonDiff__namespace = /*#__PURE__*/_interopNamespace(JsonDiff);
168
+ var isEqual__default = /*#__PURE__*/_interopDefaultLegacy(isEqual);
166
169
 
167
170
  /*! *****************************************************************************
168
171
  Copyright (c) Microsoft Corporation.
@@ -190,478 +193,6 @@ function __metadata(metadataKey, metadataValue) {
190
193
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
191
194
  }
192
195
 
193
- var domain;
194
-
195
- // This constructor is used to store event handlers. Instantiating this is
196
- // faster than explicitly calling `Object.create(null)` to get a "clean" empty
197
- // object (tested with v8 v4.9).
198
- function EventHandlers() {}
199
- EventHandlers.prototype = Object.create(null);
200
-
201
- function EventEmitter() {
202
- EventEmitter.init.call(this);
203
- }
204
-
205
- // nodejs oddity
206
- // require('events') === require('events').EventEmitter
207
- EventEmitter.EventEmitter = EventEmitter;
208
-
209
- EventEmitter.usingDomains = false;
210
-
211
- EventEmitter.prototype.domain = undefined;
212
- EventEmitter.prototype._events = undefined;
213
- EventEmitter.prototype._maxListeners = undefined;
214
-
215
- // By default EventEmitters will print a warning if more than 10 listeners are
216
- // added to it. This is a useful default which helps finding memory leaks.
217
- EventEmitter.defaultMaxListeners = 10;
218
-
219
- EventEmitter.init = function() {
220
- this.domain = null;
221
- if (EventEmitter.usingDomains) {
222
- // if there is an active domain, then attach to it.
223
- if (domain.active ) ;
224
- }
225
-
226
- if (!this._events || this._events === Object.getPrototypeOf(this)._events) {
227
- this._events = new EventHandlers();
228
- this._eventsCount = 0;
229
- }
230
-
231
- this._maxListeners = this._maxListeners || undefined;
232
- };
233
-
234
- // Obviously not all Emitters should be limited to 10. This function allows
235
- // that to be increased. Set to zero for unlimited.
236
- EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
237
- if (typeof n !== 'number' || n < 0 || isNaN(n))
238
- throw new TypeError('"n" argument must be a positive number');
239
- this._maxListeners = n;
240
- return this;
241
- };
242
-
243
- function $getMaxListeners(that) {
244
- if (that._maxListeners === undefined)
245
- return EventEmitter.defaultMaxListeners;
246
- return that._maxListeners;
247
- }
248
-
249
- EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
250
- return $getMaxListeners(this);
251
- };
252
-
253
- // These standalone emit* functions are used to optimize calling of event
254
- // handlers for fast cases because emit() itself often has a variable number of
255
- // arguments and can be deoptimized because of that. These functions always have
256
- // the same number of arguments and thus do not get deoptimized, so the code
257
- // inside them can execute faster.
258
- function emitNone(handler, isFn, self) {
259
- if (isFn)
260
- handler.call(self);
261
- else {
262
- var len = handler.length;
263
- var listeners = arrayClone(handler, len);
264
- for (var i = 0; i < len; ++i)
265
- listeners[i].call(self);
266
- }
267
- }
268
- function emitOne(handler, isFn, self, arg1) {
269
- if (isFn)
270
- handler.call(self, arg1);
271
- else {
272
- var len = handler.length;
273
- var listeners = arrayClone(handler, len);
274
- for (var i = 0; i < len; ++i)
275
- listeners[i].call(self, arg1);
276
- }
277
- }
278
- function emitTwo(handler, isFn, self, arg1, arg2) {
279
- if (isFn)
280
- handler.call(self, arg1, arg2);
281
- else {
282
- var len = handler.length;
283
- var listeners = arrayClone(handler, len);
284
- for (var i = 0; i < len; ++i)
285
- listeners[i].call(self, arg1, arg2);
286
- }
287
- }
288
- function emitThree(handler, isFn, self, arg1, arg2, arg3) {
289
- if (isFn)
290
- handler.call(self, arg1, arg2, arg3);
291
- else {
292
- var len = handler.length;
293
- var listeners = arrayClone(handler, len);
294
- for (var i = 0; i < len; ++i)
295
- listeners[i].call(self, arg1, arg2, arg3);
296
- }
297
- }
298
-
299
- function emitMany(handler, isFn, self, args) {
300
- if (isFn)
301
- handler.apply(self, args);
302
- else {
303
- var len = handler.length;
304
- var listeners = arrayClone(handler, len);
305
- for (var i = 0; i < len; ++i)
306
- listeners[i].apply(self, args);
307
- }
308
- }
309
-
310
- EventEmitter.prototype.emit = function emit(type) {
311
- var er, handler, len, args, i, events, domain;
312
- var doError = (type === 'error');
313
-
314
- events = this._events;
315
- if (events)
316
- doError = (doError && events.error == null);
317
- else if (!doError)
318
- return false;
319
-
320
- domain = this.domain;
321
-
322
- // If there is no 'error' event listener then throw.
323
- if (doError) {
324
- er = arguments[1];
325
- if (domain) {
326
- if (!er)
327
- er = new Error('Uncaught, unspecified "error" event');
328
- er.domainEmitter = this;
329
- er.domain = domain;
330
- er.domainThrown = false;
331
- domain.emit('error', er);
332
- } else if (er instanceof Error) {
333
- throw er; // Unhandled 'error' event
334
- } else {
335
- // At least give some kind of context to the user
336
- var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
337
- err.context = er;
338
- throw err;
339
- }
340
- return false;
341
- }
342
-
343
- handler = events[type];
344
-
345
- if (!handler)
346
- return false;
347
-
348
- var isFn = typeof handler === 'function';
349
- len = arguments.length;
350
- switch (len) {
351
- // fast cases
352
- case 1:
353
- emitNone(handler, isFn, this);
354
- break;
355
- case 2:
356
- emitOne(handler, isFn, this, arguments[1]);
357
- break;
358
- case 3:
359
- emitTwo(handler, isFn, this, arguments[1], arguments[2]);
360
- break;
361
- case 4:
362
- emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]);
363
- break;
364
- // slower
365
- default:
366
- args = new Array(len - 1);
367
- for (i = 1; i < len; i++)
368
- args[i - 1] = arguments[i];
369
- emitMany(handler, isFn, this, args);
370
- }
371
-
372
- return true;
373
- };
374
-
375
- function _addListener(target, type, listener, prepend) {
376
- var m;
377
- var events;
378
- var existing;
379
-
380
- if (typeof listener !== 'function')
381
- throw new TypeError('"listener" argument must be a function');
382
-
383
- events = target._events;
384
- if (!events) {
385
- events = target._events = new EventHandlers();
386
- target._eventsCount = 0;
387
- } else {
388
- // To avoid recursion in the case that type === "newListener"! Before
389
- // adding it to the listeners, first emit "newListener".
390
- if (events.newListener) {
391
- target.emit('newListener', type,
392
- listener.listener ? listener.listener : listener);
393
-
394
- // Re-assign `events` because a newListener handler could have caused the
395
- // this._events to be assigned to a new object
396
- events = target._events;
397
- }
398
- existing = events[type];
399
- }
400
-
401
- if (!existing) {
402
- // Optimize the case of one listener. Don't need the extra array object.
403
- existing = events[type] = listener;
404
- ++target._eventsCount;
405
- } else {
406
- if (typeof existing === 'function') {
407
- // Adding the second element, need to change to array.
408
- existing = events[type] = prepend ? [listener, existing] :
409
- [existing, listener];
410
- } else {
411
- // If we've already got an array, just append.
412
- if (prepend) {
413
- existing.unshift(listener);
414
- } else {
415
- existing.push(listener);
416
- }
417
- }
418
-
419
- // Check for listener leak
420
- if (!existing.warned) {
421
- m = $getMaxListeners(target);
422
- if (m && m > 0 && existing.length > m) {
423
- existing.warned = true;
424
- var w = new Error('Possible EventEmitter memory leak detected. ' +
425
- existing.length + ' ' + type + ' listeners added. ' +
426
- 'Use emitter.setMaxListeners() to increase limit');
427
- w.name = 'MaxListenersExceededWarning';
428
- w.emitter = target;
429
- w.type = type;
430
- w.count = existing.length;
431
- emitWarning(w);
432
- }
433
- }
434
- }
435
-
436
- return target;
437
- }
438
- function emitWarning(e) {
439
- typeof console.warn === 'function' ? console.warn(e) : console.log(e);
440
- }
441
- EventEmitter.prototype.addListener = function addListener(type, listener) {
442
- return _addListener(this, type, listener, false);
443
- };
444
-
445
- EventEmitter.prototype.on = EventEmitter.prototype.addListener;
446
-
447
- EventEmitter.prototype.prependListener =
448
- function prependListener(type, listener) {
449
- return _addListener(this, type, listener, true);
450
- };
451
-
452
- function _onceWrap(target, type, listener) {
453
- var fired = false;
454
- function g() {
455
- target.removeListener(type, g);
456
- if (!fired) {
457
- fired = true;
458
- listener.apply(target, arguments);
459
- }
460
- }
461
- g.listener = listener;
462
- return g;
463
- }
464
-
465
- EventEmitter.prototype.once = function once(type, listener) {
466
- if (typeof listener !== 'function')
467
- throw new TypeError('"listener" argument must be a function');
468
- this.on(type, _onceWrap(this, type, listener));
469
- return this;
470
- };
471
-
472
- EventEmitter.prototype.prependOnceListener =
473
- function prependOnceListener(type, listener) {
474
- if (typeof listener !== 'function')
475
- throw new TypeError('"listener" argument must be a function');
476
- this.prependListener(type, _onceWrap(this, type, listener));
477
- return this;
478
- };
479
-
480
- // emits a 'removeListener' event iff the listener was removed
481
- EventEmitter.prototype.removeListener =
482
- function removeListener(type, listener) {
483
- var list, events, position, i, originalListener;
484
-
485
- if (typeof listener !== 'function')
486
- throw new TypeError('"listener" argument must be a function');
487
-
488
- events = this._events;
489
- if (!events)
490
- return this;
491
-
492
- list = events[type];
493
- if (!list)
494
- return this;
495
-
496
- if (list === listener || (list.listener && list.listener === listener)) {
497
- if (--this._eventsCount === 0)
498
- this._events = new EventHandlers();
499
- else {
500
- delete events[type];
501
- if (events.removeListener)
502
- this.emit('removeListener', type, list.listener || listener);
503
- }
504
- } else if (typeof list !== 'function') {
505
- position = -1;
506
-
507
- for (i = list.length; i-- > 0;) {
508
- if (list[i] === listener ||
509
- (list[i].listener && list[i].listener === listener)) {
510
- originalListener = list[i].listener;
511
- position = i;
512
- break;
513
- }
514
- }
515
-
516
- if (position < 0)
517
- return this;
518
-
519
- if (list.length === 1) {
520
- list[0] = undefined;
521
- if (--this._eventsCount === 0) {
522
- this._events = new EventHandlers();
523
- return this;
524
- } else {
525
- delete events[type];
526
- }
527
- } else {
528
- spliceOne(list, position);
529
- }
530
-
531
- if (events.removeListener)
532
- this.emit('removeListener', type, originalListener || listener);
533
- }
534
-
535
- return this;
536
- };
537
-
538
- // Alias for removeListener added in NodeJS 10.0
539
- // https://nodejs.org/api/events.html#events_emitter_off_eventname_listener
540
- EventEmitter.prototype.off = function(type, listener){
541
- return this.removeListener(type, listener);
542
- };
543
-
544
- EventEmitter.prototype.removeAllListeners =
545
- function removeAllListeners(type) {
546
- var listeners, events;
547
-
548
- events = this._events;
549
- if (!events)
550
- return this;
551
-
552
- // not listening for removeListener, no need to emit
553
- if (!events.removeListener) {
554
- if (arguments.length === 0) {
555
- this._events = new EventHandlers();
556
- this._eventsCount = 0;
557
- } else if (events[type]) {
558
- if (--this._eventsCount === 0)
559
- this._events = new EventHandlers();
560
- else
561
- delete events[type];
562
- }
563
- return this;
564
- }
565
-
566
- // emit removeListener for all listeners on all events
567
- if (arguments.length === 0) {
568
- var keys = Object.keys(events);
569
- for (var i = 0, key; i < keys.length; ++i) {
570
- key = keys[i];
571
- if (key === 'removeListener') continue;
572
- this.removeAllListeners(key);
573
- }
574
- this.removeAllListeners('removeListener');
575
- this._events = new EventHandlers();
576
- this._eventsCount = 0;
577
- return this;
578
- }
579
-
580
- listeners = events[type];
581
-
582
- if (typeof listeners === 'function') {
583
- this.removeListener(type, listeners);
584
- } else if (listeners) {
585
- // LIFO order
586
- do {
587
- this.removeListener(type, listeners[listeners.length - 1]);
588
- } while (listeners[0]);
589
- }
590
-
591
- return this;
592
- };
593
-
594
- EventEmitter.prototype.listeners = function listeners(type) {
595
- var evlistener;
596
- var ret;
597
- var events = this._events;
598
-
599
- if (!events)
600
- ret = [];
601
- else {
602
- evlistener = events[type];
603
- if (!evlistener)
604
- ret = [];
605
- else if (typeof evlistener === 'function')
606
- ret = [evlistener.listener || evlistener];
607
- else
608
- ret = unwrapListeners(evlistener);
609
- }
610
-
611
- return ret;
612
- };
613
-
614
- EventEmitter.listenerCount = function(emitter, type) {
615
- if (typeof emitter.listenerCount === 'function') {
616
- return emitter.listenerCount(type);
617
- } else {
618
- return listenerCount.call(emitter, type);
619
- }
620
- };
621
-
622
- EventEmitter.prototype.listenerCount = listenerCount;
623
- function listenerCount(type) {
624
- var events = this._events;
625
-
626
- if (events) {
627
- var evlistener = events[type];
628
-
629
- if (typeof evlistener === 'function') {
630
- return 1;
631
- } else if (evlistener) {
632
- return evlistener.length;
633
- }
634
- }
635
-
636
- return 0;
637
- }
638
-
639
- EventEmitter.prototype.eventNames = function eventNames() {
640
- return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : [];
641
- };
642
-
643
- // About 1.5x faster than the two-arg version of Array#splice().
644
- function spliceOne(list, index) {
645
- for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1)
646
- list[i] = list[k];
647
- list.pop();
648
- }
649
-
650
- function arrayClone(arr, i) {
651
- var copy = new Array(i);
652
- while (i--)
653
- copy[i] = arr[i];
654
- return copy;
655
- }
656
-
657
- function unwrapListeners(arr) {
658
- var ret = new Array(arr.length);
659
- for (var i = 0; i < ret.length; ++i) {
660
- ret[i] = arr[i].listener || arr[i];
661
- }
662
- return ret;
663
- }
664
-
665
196
  function prepareLine(prefix, args) {
666
197
  return [`${new Date().toISOString()} Conversations ${prefix}:`].concat(Array.from(args));
667
198
  }
@@ -754,6 +285,321 @@ class Configuration {
754
285
  }
755
286
  }
756
287
 
288
+ /**
289
+ * Deep-clone an object. Note that this does not work on object containing
290
+ * functions.
291
+ * @param {object} obj - the object to deep-clone
292
+ * @returns {object}
293
+ */
294
+ function deepClone(obj) {
295
+ return JSON.parse(JSON.stringify(obj));
296
+ }
297
+ function parseToNumber(value) {
298
+ if (typeof value !== 'undefined' && !isNaN(Number(value))) {
299
+ return Number(value);
300
+ }
301
+ return null;
302
+ }
303
+ // timeString cannot be typed `string` because in member.ts
304
+ // call to parseTime(data.lastReadTimestamp) uses number not a string for timestamp.
305
+ function parseTime$1(timeString) {
306
+ try {
307
+ return new Date(timeString);
308
+ }
309
+ catch (e) {
310
+ return null;
311
+ }
312
+ }
313
+ function parseAttributes(rawAttributes, warningMessage, log) {
314
+ let attributes = {};
315
+ if (rawAttributes) {
316
+ try {
317
+ attributes = JSON.parse(rawAttributes);
318
+ }
319
+ catch (e) {
320
+ log.warn(warningMessage, e);
321
+ }
322
+ }
323
+ return attributes;
324
+ }
325
+ /**
326
+ * Construct URI with query parameters
327
+ */
328
+ class UriBuilder {
329
+ constructor(base) {
330
+ this.base = base.replace(/\/$/, '');
331
+ this.args = [];
332
+ this.paths = [];
333
+ }
334
+ arg(name, value) {
335
+ if (typeof value !== 'undefined') {
336
+ this.args.push(encodeURIComponent(name) + '=' + encodeURIComponent(value));
337
+ }
338
+ return this;
339
+ }
340
+ path(name) {
341
+ this.paths.push(encodeURIComponent(name));
342
+ return this;
343
+ }
344
+ build() {
345
+ let result = this.base;
346
+ if (this.paths.length) {
347
+ result += '/' + this.paths.join('/');
348
+ }
349
+ if (this.args.length) {
350
+ result += '?' + this.args.join('&');
351
+ }
352
+ return result;
353
+ }
354
+ }
355
+
356
+ const log$8 = Logger.scope('User');
357
+ /**
358
+ * Extended user information.
359
+ * Note that `isOnline` and `isNotifiable` properties are eligible
360
+ * for use only if the reachability function is enabled.
361
+ * You may check if it is enabled by reading the value of {@link Client.reachabilityEnabled}.
362
+ */
363
+ class User extends replayEventEmitter.ReplayEventEmitter {
364
+ /**
365
+ * @internal
366
+ */
367
+ constructor(identity, entityName, configuration, services) {
368
+ super();
369
+ this.promiseToFetch = null;
370
+ /**
371
+ * Fired when the properties or the reachability status of the message has been updated.
372
+ *
373
+ * Parameters:
374
+ * 1. object `data` - info object provided with the event. It has the following properties:
375
+ * * {@link User} `user` - the user in question
376
+ * * {@link UserUpdateReason}[] `updateReasons` - array of reasons for the update
377
+ * @event
378
+ */
379
+ this.updated = 'updated';
380
+ /**
381
+ * Fired when the client has subscribed to the user.
382
+ *
383
+ * Parameters:
384
+ * 1. {@link User} `user` - the user in question
385
+ * @event
386
+ */
387
+ this.userSubscribed = 'userSubscribed';
388
+ /**
389
+ * Fired when the client has unsubscribed from the user.
390
+ *
391
+ * Parameters:
392
+ * 1. {@link User} `user` - the user in question
393
+ * @event
394
+ */
395
+ this.userUnsubscribed = 'userUnsubscribed';
396
+ this.services = services;
397
+ this.subscribed = 'initializing';
398
+ this.setMaxListeners(0);
399
+ this.state = {
400
+ identity,
401
+ entityName,
402
+ friendlyName: null,
403
+ attributes: {},
404
+ online: null,
405
+ notifiable: null
406
+ };
407
+ this._initializationPromise = new Promise((resolve) => {
408
+ this._resolveInitializationPromise = resolve;
409
+ });
410
+ if (configuration !== null) {
411
+ this._resolveInitialization(configuration, identity, entityName, false);
412
+ }
413
+ }
414
+ /**
415
+ * User identity.
416
+ */
417
+ get identity() { return this.state.identity; }
418
+ set identity(identity) { this.state.identity = identity; }
419
+ set entityName(name) { this.state.entityName = name; }
420
+ /**
421
+ * Custom attributes of the user.
422
+ */
423
+ get attributes() { return this.state.attributes; }
424
+ /**
425
+ * Friendly name of the user, null if not set.
426
+ */
427
+ get friendlyName() { return this.state.friendlyName; }
428
+ /**
429
+ * Status of the real-time conversation connection of the user.
430
+ */
431
+ get isOnline() { return this.state.online; }
432
+ /**
433
+ * User push notification registration status.
434
+ */
435
+ get isNotifiable() { return this.state.notifiable; }
436
+ /**
437
+ * True if this user is receiving real-time status updates.
438
+ */
439
+ get isSubscribed() { return this.subscribed == 'subscribed'; }
440
+ // Handles service updates
441
+ async _update(key, value) {
442
+ await this._initializationPromise;
443
+ let updateReasons = [];
444
+ log$8.debug('User for', this.state.identity, 'updated:', key, value);
445
+ switch (key) {
446
+ case 'friendlyName':
447
+ if (this.state.friendlyName !== value.value) {
448
+ updateReasons.push('friendlyName');
449
+ this.state.friendlyName = value.value;
450
+ }
451
+ break;
452
+ case 'attributes':
453
+ const updateAttributes = parseAttributes(value.value, `Retrieved malformed attributes from the server for user: ${this.state.identity}`, log$8);
454
+ if (!isEqual__default['default'](this.state.attributes, updateAttributes)) {
455
+ this.state.attributes = updateAttributes;
456
+ updateReasons.push('attributes');
457
+ }
458
+ break;
459
+ case 'reachability':
460
+ if (this.state.online !== value.online) {
461
+ this.state.online = value.online;
462
+ updateReasons.push('reachabilityOnline');
463
+ }
464
+ if (this.state.notifiable !== value.notifiable) {
465
+ this.state.notifiable = value.notifiable;
466
+ updateReasons.push('reachabilityNotifiable');
467
+ }
468
+ break;
469
+ default:
470
+ return;
471
+ }
472
+ if (updateReasons.length > 0) {
473
+ this.emit('updated', { user: this, updateReasons: updateReasons });
474
+ }
475
+ }
476
+ // Fetch reachability info
477
+ async _updateReachabilityInfo(map, update) {
478
+ await this._initializationPromise;
479
+ if (!this.configuration.reachabilityEnabled) {
480
+ return Promise.resolve();
481
+ }
482
+ return map.get('reachability')
483
+ .then(update)
484
+ .catch(err => { log$8.warn('Failed to get reachability info for ', this.state.identity, err); });
485
+ }
486
+ // Fetch user
487
+ async _fetch() {
488
+ await this._initializationPromise;
489
+ if (!this.state.entityName) {
490
+ return this;
491
+ }
492
+ this.promiseToFetch = this.services.syncClient.map({
493
+ id: this.state.entityName,
494
+ mode: 'open_existing',
495
+ includeItems: true
496
+ })
497
+ .then(map => {
498
+ this.entity = map;
499
+ map.on('itemUpdated', args => {
500
+ log$8.debug(this.state.entityName + ' (' + this.state.identity + ') itemUpdated: ' + args.item.key);
501
+ return this._update(args.item.key, args.item.data);
502
+ });
503
+ return Promise.all([
504
+ map.get('friendlyName')
505
+ .then(item => this._update(item.key, item.data)),
506
+ map.get('attributes')
507
+ .then(item => this._update(item.key, item.data)),
508
+ this._updateReachabilityInfo(map, item => this._update(item.key, item.data))
509
+ ]);
510
+ })
511
+ .then(() => {
512
+ log$8.debug('Fetched for', this.identity);
513
+ this.subscribed = 'subscribed';
514
+ this.emit('userSubscribed', this);
515
+ return this;
516
+ })
517
+ .catch(err => {
518
+ this.promiseToFetch = null;
519
+ throw err;
520
+ });
521
+ return this.promiseToFetch;
522
+ }
523
+ async _ensureFetched() {
524
+ await this._initializationPromise;
525
+ return this.promiseToFetch || this._fetch();
526
+ }
527
+ /**
528
+ * Edit user attributes.
529
+ * @param attributes New attributes.
530
+ */
531
+ async updateAttributes(attributes) {
532
+ await this._initializationPromise;
533
+ if (this.subscribed == 'unsubscribed') {
534
+ throw new Error('Can\'t modify unsubscribed object');
535
+ }
536
+ await this.services.commandExecutor.mutateResource('post', this.links.self, {
537
+ attributes: JSON.stringify(attributes)
538
+ });
539
+ return this;
540
+ }
541
+ /**
542
+ * Update the friendly name of the user.
543
+ * @param friendlyName New friendly name.
544
+ */
545
+ async updateFriendlyName(friendlyName) {
546
+ await this._initializationPromise;
547
+ if (this.subscribed == 'unsubscribed') {
548
+ throw new Error('Can\'t modify unsubscribed object');
549
+ }
550
+ await this.services.commandExecutor.mutateResource('post', this.links.self, {
551
+ friendly_name: friendlyName
552
+ });
553
+ return this;
554
+ }
555
+ /**
556
+ * Remove the user from the subscription list.
557
+ * @return A promise of completion.
558
+ */
559
+ async unsubscribe() {
560
+ await this._initializationPromise;
561
+ if (this.promiseToFetch) {
562
+ await this.promiseToFetch;
563
+ this.entity.close();
564
+ this.promiseToFetch = null;
565
+ this.subscribed = 'unsubscribed';
566
+ this.emit('userUnsubscribed', this);
567
+ }
568
+ }
569
+ _resolveInitialization(configuration, identity, entityName, emitUpdated) {
570
+ this.configuration = configuration;
571
+ this.identity = identity;
572
+ this.entityName = entityName;
573
+ this.links = {
574
+ self: `${this.configuration.links.users}/${this.identity}`
575
+ };
576
+ this._resolveInitializationPromise();
577
+ if (emitUpdated) {
578
+ this.emit('updated', {
579
+ user: this,
580
+ updateReasons: [
581
+ 'friendlyName',
582
+ 'attributes',
583
+ 'reachabilityOnline',
584
+ 'reachabilityNotifiable'
585
+ ]
586
+ });
587
+ }
588
+ }
589
+ }
590
+ __decorate([
591
+ declarativeTypeValidator.validateTypesAsync(['string', 'number', 'boolean', 'object', declarativeTypeValidator.literal(null)]),
592
+ __metadata("design:type", Function),
593
+ __metadata("design:paramtypes", [Object]),
594
+ __metadata("design:returntype", Promise)
595
+ ], User.prototype, "updateAttributes", null);
596
+ __decorate([
597
+ declarativeTypeValidator.validateTypesAsync(['string']),
598
+ __metadata("design:type", Function),
599
+ __metadata("design:paramtypes", [String]),
600
+ __metadata("design:returntype", Promise)
601
+ ], User.prototype, "updateFriendlyName", null);
602
+
757
603
  class Network {
758
604
  constructor(configuration, services) {
759
605
  this.configuration = configuration;
@@ -823,94 +669,20 @@ class Network {
823
669
  }
824
670
  }
825
671
 
826
- class NotificationTypes {
827
- }
828
- NotificationTypes.TYPING_INDICATOR = 'twilio.ipmsg.typing_indicator';
829
- NotificationTypes.NEW_MESSAGE = 'twilio.conversations.new_message';
830
- NotificationTypes.ADDED_TO_CONVERSATION = 'twilio.conversations.added_to_conversation';
831
- // static readonly INVITED_TO_CHANNEL = 'twilio.channel.invited_to_channel';
832
- NotificationTypes.REMOVED_FROM_CONVERSATION = 'twilio.conversations.removed_from_conversation';
833
- NotificationTypes.CONSUMPTION_UPDATE = 'twilio.channel.consumption_update';
834
-
835
- /**
836
- * Checks if objects are equal
837
- */
838
- function isDeepEqual(o1, o2) {
839
- return JsonDiff__namespace.createPatch(o1, o2).length === 0;
840
- }
841
- /**
842
- * Deep-clone an object. Note that this does not work on object containing
843
- * functions.
844
- * @param {object} obj - the object to deep-clone
845
- * @returns {object}
846
- */
847
- function deepClone(obj) {
848
- return JSON.parse(JSON.stringify(obj));
849
- }
850
- function parseToNumber(value) {
851
- if (typeof value !== 'undefined' && !isNaN(Number(value))) {
852
- return Number(value);
853
- }
854
- return null;
855
- }
856
- // timeString cannot be typed `string` because in member.ts
857
- // call to parseTime(data.lastReadTimestamp) uses number not a string for timestamp.
858
- function parseTime$1(timeString) {
859
- try {
860
- return new Date(timeString);
861
- }
862
- catch (e) {
863
- return null;
864
- }
865
- }
866
- function parseAttributes(rawAttributes, warningMessage, log) {
867
- let attributes = {};
868
- if (rawAttributes) {
869
- try {
870
- attributes = JSON.parse(rawAttributes);
871
- }
872
- catch (e) {
873
- log.warn(warningMessage, e);
874
- }
875
- }
876
- return attributes;
877
- }
878
- /**
879
- * Construct URI with query parameters
880
- */
881
- class UriBuilder {
882
- constructor(base) {
883
- this.base = base.replace(/\/$/, '');
884
- this.args = [];
885
- this.paths = [];
886
- }
887
- arg(name, value) {
888
- if (typeof value !== 'undefined') {
889
- this.args.push(encodeURIComponent(name) + '=' + encodeURIComponent(value));
890
- }
891
- return this;
892
- }
893
- path(name) {
894
- this.paths.push(encodeURIComponent(name));
895
- return this;
896
- }
897
- build() {
898
- let result = this.base;
899
- if (this.paths.length) {
900
- result += '/' + this.paths.join('/');
901
- }
902
- if (this.args.length) {
903
- result += '?' + this.args.join('&');
904
- }
905
- return result;
906
- }
672
+ class NotificationTypes {
907
673
  }
674
+ NotificationTypes.TYPING_INDICATOR = 'twilio.ipmsg.typing_indicator';
675
+ NotificationTypes.NEW_MESSAGE = 'twilio.conversations.new_message';
676
+ NotificationTypes.ADDED_TO_CONVERSATION = 'twilio.conversations.added_to_conversation';
677
+ // static readonly INVITED_TO_CHANNEL = 'twilio.channel.invited_to_channel';
678
+ NotificationTypes.REMOVED_FROM_CONVERSATION = 'twilio.conversations.removed_from_conversation';
679
+ NotificationTypes.CONSUMPTION_UPDATE = 'twilio.channel.consumption_update';
908
680
 
909
- const log$8 = Logger.scope('Participant');
681
+ const log$7 = Logger.scope('Participant');
910
682
  /**
911
683
  * A participant represents a remote client in a conversation.
912
684
  */
913
- class Participant extends EventEmitter {
685
+ class Participant extends replayEventEmitter.ReplayEventEmitter {
914
686
  /**
915
687
  * @internal
916
688
  */
@@ -920,7 +692,7 @@ class Participant extends EventEmitter {
920
692
  this.links = links;
921
693
  this.services = services;
922
694
  this.state = {
923
- attributes: parseAttributes(data.attributes, 'Retrieved malformed attributes from the server for participant: ' + sid, log$8),
695
+ attributes: parseAttributes(data.attributes, 'Retrieved malformed attributes from the server for participant: ' + sid, log$7),
924
696
  dateCreated: data.dateCreated ? parseTime$1(data.dateCreated) : null,
925
697
  dateUpdated: data.dateCreated ? parseTime$1(data.dateUpdated) : null,
926
698
  sid: sid,
@@ -1009,8 +781,8 @@ class Participant extends EventEmitter {
1009
781
  */
1010
782
  _update(data) {
1011
783
  let updateReasons = [];
1012
- let updateAttributes = parseAttributes(data.attributes, 'Retrieved malformed attributes from the server for participant: ' + this.state.sid, log$8);
1013
- if (data.attributes && !isDeepEqual(this.state.attributes, updateAttributes)) {
784
+ let updateAttributes = parseAttributes(data.attributes, 'Retrieved malformed attributes from the server for participant: ' + this.state.sid, log$7);
785
+ if (data.attributes && !isEqual__default['default'](this.state.attributes, updateAttributes)) {
1014
786
  this.state.attributes = updateAttributes;
1015
787
  updateReasons.push('attributes');
1016
788
  }
@@ -1107,14 +879,14 @@ __decorate([
1107
879
  __metadata("design:returntype", Promise)
1108
880
  ], Participant.prototype, "updateAttributes", null);
1109
881
 
1110
- const log$7 = Logger.scope('Participants');
882
+ const log$6 = Logger.scope('Participants');
1111
883
  /**
1112
884
  * @classdesc Represents the collection of participants for the conversation
1113
885
  * @fires Participants#participantJoined
1114
886
  * @fires Participants#participantLeft
1115
887
  * @fires Participants#participantUpdated
1116
888
  */
1117
- class Participants extends EventEmitter {
889
+ class Participants extends replayEventEmitter.ReplayEventEmitter {
1118
890
  constructor(conversation, participants, links, configuration, services) {
1119
891
  super();
1120
892
  this.conversation = conversation;
@@ -1135,14 +907,14 @@ class Participants extends EventEmitter {
1135
907
  || this.services.syncClient.map({ id: rosterObjectName, mode: 'open_existing' })
1136
908
  .then(rosterMap => {
1137
909
  rosterMap.on('itemAdded', args => {
1138
- log$7.debug(this.conversation.sid + ' itemAdded: ' + args.item.key);
910
+ log$6.debug(this.conversation.sid + ' itemAdded: ' + args.item.key);
1139
911
  this.upsertParticipant(args.item.key, args.item.data)
1140
912
  .then(participant => {
1141
913
  this.emit('participantJoined', participant);
1142
914
  });
1143
915
  });
1144
916
  rosterMap.on('itemRemoved', args => {
1145
- log$7.debug(this.conversation.sid + ' itemRemoved: ' + args.key);
917
+ log$6.debug(this.conversation.sid + ' itemRemoved: ' + args.key);
1146
918
  let participantSid = args.key;
1147
919
  if (!this.participants.has(participantSid)) {
1148
920
  return;
@@ -1152,7 +924,7 @@ class Participants extends EventEmitter {
1152
924
  this.emit('participantLeft', leftParticipant);
1153
925
  });
1154
926
  rosterMap.on('itemUpdated', args => {
1155
- log$7.debug(this.conversation.sid + ' itemUpdated: ' + args.item.key);
927
+ log$6.debug(this.conversation.sid + ' itemUpdated: ' + args.item.key);
1156
928
  this.upsertParticipant(args.item.key, args.item.data);
1157
929
  });
1158
930
  let participantsPromises = [];
@@ -1170,9 +942,9 @@ class Participants extends EventEmitter {
1170
942
  .catch(err => {
1171
943
  this.rosterEntityPromise = null;
1172
944
  if (this.services.syncClient.connectionState != 'disconnected') {
1173
- log$7.error('Failed to get roster object for conversation', this.conversation.sid, err);
945
+ log$6.error('Failed to get roster object for conversation', this.conversation.sid, err);
1174
946
  }
1175
- log$7.debug('ERROR: Failed to get roster object for conversation', this.conversation.sid, err);
947
+ log$6.debug('ERROR: Failed to get roster object for conversation', this.conversation.sid, err);
1176
948
  throw err;
1177
949
  });
1178
950
  }
@@ -1248,9 +1020,9 @@ class Participants extends EventEmitter {
1248
1020
  * @param attributes
1249
1021
  * @returns {Promise<any>}
1250
1022
  */
1251
- addNonChatParticipant(proxyAddress, address, attributes = {}) {
1023
+ addNonChatParticipant(proxyAddress, address, attributes) {
1252
1024
  return this.services.commandExecutor.mutateResource('post', this.links.participants, {
1253
- attributes: JSON.stringify(attributes),
1025
+ attributes: typeof attributes !== 'undefined' ? JSON.stringify(attributes) : undefined,
1254
1026
  messaging_binding: {
1255
1027
  address,
1256
1028
  proxy_address: proxyAddress
@@ -1320,7 +1092,7 @@ class Media {
1320
1092
  */
1321
1093
  get size() { return this.state.size; }
1322
1094
  /**
1323
- * Media category, can be one of the {MediaCategory} values.
1095
+ * Media category, can be one of the {@link MediaCategory} values.
1324
1096
  */
1325
1097
  get category() { return this.state.category; }
1326
1098
  /**
@@ -1513,11 +1285,11 @@ class DetailedDeliveryReceipt {
1513
1285
  }
1514
1286
  }
1515
1287
 
1516
- const log$6 = Logger.scope('Message');
1288
+ const log$5 = Logger.scope('Message');
1517
1289
  /**
1518
1290
  * A message in a conversation.
1519
1291
  */
1520
- class Message extends EventEmitter {
1292
+ class Message extends replayEventEmitter.ReplayEventEmitter {
1521
1293
  /**
1522
1294
  * @internal
1523
1295
  */
@@ -1537,7 +1309,7 @@ class Message extends EventEmitter {
1537
1309
  timestamp: data.timestamp ? new Date(data.timestamp) : null,
1538
1310
  dateUpdated: data.dateUpdated ? new Date(data.dateUpdated) : null,
1539
1311
  lastUpdatedBy: (_c = data.lastUpdatedBy) !== null && _c !== void 0 ? _c : null,
1540
- attributes: parseAttributes(data.attributes, `Got malformed attributes for the message ${data.sid}`, log$6),
1312
+ attributes: parseAttributes(data.attributes, `Got malformed attributes for the message ${data.sid}`, log$5),
1541
1313
  type: (_d = data.type) !== null && _d !== void 0 ? _d : 'text',
1542
1314
  media: (data.type && data.type === 'media' && data.media)
1543
1315
  ? new Media(data.media, this.services) : null,
@@ -1652,8 +1424,8 @@ class Message extends EventEmitter {
1652
1424
  this.state.timestamp = new Date(data.timestamp);
1653
1425
  updateReasons.push('dateCreated');
1654
1426
  }
1655
- let updatedAttributes = parseAttributes(data.attributes, `Got malformed attributes for the message ${this.sid}`, log$6);
1656
- if (!isDeepEqual(this.state.attributes, updatedAttributes)) {
1427
+ let updatedAttributes = parseAttributes(data.attributes, `Got malformed attributes for the message ${this.sid}`, log$5);
1428
+ if (!isEqual__default['default'](this.state.attributes, updatedAttributes)) {
1657
1429
  this.state.attributes = updatedAttributes;
1658
1430
  updateReasons.push('attributes');
1659
1431
  }
@@ -1684,14 +1456,14 @@ class Message extends EventEmitter {
1684
1456
  if (this.state.participantSid) {
1685
1457
  participant = await this.conversation.getParticipantBySid(this.participantSid)
1686
1458
  .catch(() => {
1687
- log$6.debug(`Participant with sid "${this.participantSid}" not found for message ${this.sid}`);
1459
+ log$5.debug(`Participant with sid "${this.participantSid}" not found for message ${this.sid}`);
1688
1460
  return null;
1689
1461
  });
1690
1462
  }
1691
1463
  if (!participant && this.state.author) {
1692
1464
  participant = await this.conversation.getParticipantByIdentity(this.state.author)
1693
1465
  .catch(() => {
1694
- log$6.debug(`Participant with identity "${this.author}" not found for message ${this.sid}`);
1466
+ log$5.debug(`Participant with identity "${this.author}" not found for message ${this.sid}`);
1695
1467
  return null;
1696
1468
  });
1697
1469
  }
@@ -1814,11 +1586,11 @@ __decorate([
1814
1586
  __metadata("design:returntype", Promise)
1815
1587
  ], Message.prototype, "attachTemporaryUrlsFor", null);
1816
1588
 
1817
- const log$5 = Logger.scope('Messages');
1589
+ const log$4 = Logger.scope('Messages');
1818
1590
  /**
1819
1591
  * Represents the collection of messages in a conversation
1820
1592
  */
1821
- class Messages extends EventEmitter {
1593
+ class Messages extends replayEventEmitter.ReplayEventEmitter {
1822
1594
  constructor(conversation, configuration, services) {
1823
1595
  super();
1824
1596
  this.conversation = conversation;
@@ -1842,7 +1614,7 @@ class Messages extends EventEmitter {
1842
1614
  try {
1843
1615
  const list = await this.messagesListPromise;
1844
1616
  list.on('itemAdded', (args) => {
1845
- log$5.debug(`${this.conversation.sid} itemAdded: ${args.item.index}`);
1617
+ log$4.debug(`${this.conversation.sid} itemAdded: ${args.item.index}`);
1846
1618
  const links = {
1847
1619
  self: `${this.conversation.links.messages}/${args.item.data.sid}`,
1848
1620
  conversation: this.conversation.links.self,
@@ -1850,7 +1622,7 @@ class Messages extends EventEmitter {
1850
1622
  };
1851
1623
  const message = new Message(args.item.index, args.item.data, this.conversation, links, this.configuration, this.services);
1852
1624
  if (this.messagesByIndex.has(message.index)) {
1853
- log$5.debug('Message arrived, but is already known and ignored', this.conversation.sid, message.index);
1625
+ log$4.debug('Message arrived, but is already known and ignored', this.conversation.sid, message.index);
1854
1626
  return;
1855
1627
  }
1856
1628
  this.messagesByIndex.set(message.index, message);
@@ -1858,7 +1630,7 @@ class Messages extends EventEmitter {
1858
1630
  this.emit('messageAdded', message);
1859
1631
  });
1860
1632
  list.on('itemRemoved', (args) => {
1861
- log$5.debug(`#{this.conversation.sid} itemRemoved: ${args.index}`);
1633
+ log$4.debug(`#{this.conversation.sid} itemRemoved: ${args.index}`);
1862
1634
  const index = args.index;
1863
1635
  if (this.messagesByIndex.has(index)) {
1864
1636
  let message = this.messagesByIndex.get(index);
@@ -1868,7 +1640,7 @@ class Messages extends EventEmitter {
1868
1640
  }
1869
1641
  });
1870
1642
  list.on('itemUpdated', (args) => {
1871
- log$5.debug(`${this.conversation.sid} itemUpdated: ${args.item.index}`);
1643
+ log$4.debug(`${this.conversation.sid} itemUpdated: ${args.item.index}`);
1872
1644
  const message = this.messagesByIndex.get(args.item.index);
1873
1645
  if (message) {
1874
1646
  message._update(args.item.data);
@@ -1879,9 +1651,9 @@ class Messages extends EventEmitter {
1879
1651
  catch (err) {
1880
1652
  this.messagesListPromise = null;
1881
1653
  if (this.services.syncClient.connectionState !== 'disconnected') {
1882
- log$5.error('Failed to get messages object for conversation', this.conversation.sid, err);
1654
+ log$4.error('Failed to get messages object for conversation', this.conversation.sid, err);
1883
1655
  }
1884
- log$5.debug('ERROR: Failed to get messages object for conversation', this.conversation.sid, err);
1656
+ log$4.debug('ERROR: Failed to get messages object for conversation', this.conversation.sid, err);
1885
1657
  throw err;
1886
1658
  }
1887
1659
  }
@@ -1900,10 +1672,10 @@ class Messages extends EventEmitter {
1900
1672
  */
1901
1673
  async sendV2(message) {
1902
1674
  var _a;
1903
- log$5.debug('Sending message V2', message.mediaContent, message.attributes, message.emailOptions);
1675
+ log$4.debug('Sending message V2', message.mediaContent, message.attributes, message.emailOptions);
1904
1676
  const media = [];
1905
1677
  for (const [category, mediaContent] of message.mediaContent) {
1906
- log$5.debug(`Adding media to a message as ${mediaContent instanceof FormData ? 'FormData' : 'SendMediaOptions'}`, mediaContent);
1678
+ log$4.debug(`Adding media to a message as ${mediaContent instanceof FormData ? 'FormData' : 'SendMediaOptions'}`, mediaContent);
1907
1679
  media.push(mediaContent instanceof FormData
1908
1680
  ? await this.services.mcsClient.postFormData(mediaContent, category)
1909
1681
  : await this.services.mcsClient.post(mediaContent.contentType, mediaContent.media, category, mediaContent.filename));
@@ -1925,7 +1697,7 @@ class Messages extends EventEmitter {
1925
1697
  * @returns Returns promise which can fail
1926
1698
  */
1927
1699
  async send(message, attributes = {}, emailOptions) {
1928
- log$5.debug('Sending text message', message, attributes, emailOptions);
1700
+ log$4.debug('Sending text message', message, attributes, emailOptions);
1929
1701
  return await this.services.commandExecutor.mutateResource('post', this.conversation.links.messages, {
1930
1702
  body: message !== null && message !== void 0 ? message : '',
1931
1703
  attributes: typeof attributes !== 'undefined'
@@ -1942,8 +1714,8 @@ class Messages extends EventEmitter {
1942
1714
  * @returns Returns promise which can fail
1943
1715
  */
1944
1716
  async sendMedia(mediaContent, attributes = {}, emailOptions) {
1945
- log$5.debug('Sending media message', mediaContent, attributes, emailOptions);
1946
- log$5.debug(`Sending media message as ${mediaContent instanceof FormData ? 'FormData' : 'SendMediaOptions'}`, mediaContent, attributes);
1717
+ log$4.debug('Sending media message', mediaContent, attributes, emailOptions);
1718
+ log$4.debug(`Sending media message as ${mediaContent instanceof FormData ? 'FormData' : 'SendMediaOptions'}`, mediaContent, attributes);
1947
1719
  const media = mediaContent instanceof FormData
1948
1720
  ? await this.services.mcsClient.postFormData(mediaContent)
1949
1721
  : await this.services.mcsClient.post(mediaContent.contentType, mediaContent.media, 'media', mediaContent.filename);
@@ -2017,7 +1789,13 @@ class Messages extends EventEmitter {
2017
1789
  }
2018
1790
  }
2019
1791
 
1792
+ /**
1793
+ * An unsent message. Returned from {@link MessageBuilder.build}.
1794
+ */
2020
1795
  class UnsentMessage {
1796
+ /**
1797
+ * @internal
1798
+ */
2021
1799
  constructor(messagesEntity) {
2022
1800
  this.messagesEntity = messagesEntity;
2023
1801
  this.attributes = {};
@@ -2026,35 +1804,72 @@ class UnsentMessage {
2026
1804
  }
2027
1805
  /**
2028
1806
  * Send the prepared message to the conversation.
2029
- * @returns {Promise<number>} new Message's index in the Conversation's messages list
1807
+ * @returns Index of the new message in the conversation.
2030
1808
  */
2031
1809
  async send() {
2032
1810
  const response = await this.messagesEntity.sendV2(this);
2033
- return parseToNumber(response.messageId);
1811
+ return parseToNumber(response.index);
2034
1812
  }
2035
1813
  }
2036
1814
 
1815
+ /**
1816
+ * Message builder. Allows the message to be built and sent via method chaining.
1817
+ *
1818
+ * Example:
1819
+ *
1820
+ * ```ts
1821
+ * await testConversation.prepareMessage()
1822
+ * .setBody('Hello!')
1823
+ * .setAttributes({foo: 'bar'})
1824
+ * .addMedia(media1)
1825
+ * .addMedia(media2)
1826
+ * .build()
1827
+ * .send();
1828
+ * ```
1829
+ */
2037
1830
  class MessageBuilder {
1831
+ /**
1832
+ * @internal
1833
+ */
2038
1834
  constructor(limits, messagesEntity) {
2039
1835
  this.limits = limits;
2040
1836
  this.message = new UnsentMessage(messagesEntity);
2041
1837
  }
1838
+ /**
1839
+ * Sets the message body.
1840
+ * @param text Contents of the body.
1841
+ */
2042
1842
  setBody(text) {
2043
1843
  this.message.text = text;
2044
1844
  return this;
2045
1845
  }
1846
+ /**
1847
+ * Sets the message subject.
1848
+ * @param subject Contents of the subject.
1849
+ */
2046
1850
  setSubject(subject) {
2047
1851
  this.message.emailOptions.subject = subject;
2048
1852
  return this;
2049
1853
  }
1854
+ /**
1855
+ * Sets the message attributes.
1856
+ * @param attributes Message attributes.
1857
+ */
2050
1858
  setAttributes(attributes) {
2051
1859
  this.message.attributes = attributes;
2052
1860
  return this;
2053
1861
  }
1862
+ /**
1863
+ * Adds media to the message.
1864
+ * @param payload Media to add.
1865
+ */
2054
1866
  addMedia(payload) {
2055
1867
  this.message.mediaContent.push(['media', payload]);
2056
1868
  return this;
2057
1869
  }
1870
+ /**
1871
+ * Builds the message, making it ready to be sent.
1872
+ */
2058
1873
  build() {
2059
1874
  if (this.message.mediaContent.length > this.limits.mediaAttachmentsCountLimit) {
2060
1875
  throw new Error(`Too many media attachments in the message (${this.message.mediaContent.length} > ${this.limits.mediaAttachmentsCountLimit})`);
@@ -2070,7 +1885,7 @@ class MessageBuilder {
2070
1885
  }
2071
1886
  }
2072
1887
 
2073
- const log$4 = Logger.scope('Conversation');
1888
+ const log$3 = Logger.scope('Conversation');
2074
1889
  const fieldMappings = {
2075
1890
  lastMessage: 'lastMessage',
2076
1891
  attributes: 'attributes',
@@ -2096,7 +1911,7 @@ function parseTime(timeString) {
2096
1911
  /**
2097
1912
  * A conversation represents communication between multiple Conversations clients
2098
1913
  */
2099
- class Conversation extends EventEmitter {
1914
+ class Conversation extends replayEventEmitter.ReplayEventEmitter {
2100
1915
  /**
2101
1916
  * @internal
2102
1917
  */
@@ -2210,9 +2025,9 @@ class Conversation extends EventEmitter {
2210
2025
  this.entity = null;
2211
2026
  this.entityPromise = null;
2212
2027
  if (this.services.syncClient.connectionState != 'disconnected') {
2213
- log$4.error('Failed to get conversation object', err);
2028
+ log$3.error('Failed to get conversation object', err);
2214
2029
  }
2215
- log$4.debug('ERROR: Failed to get conversation object', err);
2030
+ log$3.debug('ERROR: Failed to get conversation object', err);
2216
2031
  throw err;
2217
2032
  });
2218
2033
  }
@@ -2225,7 +2040,7 @@ class Conversation extends EventEmitter {
2225
2040
  async _subscribeStreams() {
2226
2041
  try {
2227
2042
  await this._subscribe();
2228
- log$4.trace('_subscribeStreams, this.entity.data=', this.entity.data);
2043
+ log$3.trace('_subscribeStreams, this.entity.data=', this.entity.data);
2229
2044
  const messagesObjectName = this.entity.data.messages;
2230
2045
  const rosterObjectName = this.entity.data.roster;
2231
2046
  await Promise.all([
@@ -2235,9 +2050,9 @@ class Conversation extends EventEmitter {
2235
2050
  }
2236
2051
  catch (err) {
2237
2052
  if (this.services.syncClient.connectionState !== 'disconnected') {
2238
- log$4.error('Failed to subscribe on conversation objects', this.sid, err);
2053
+ log$3.error('Failed to subscribe on conversation objects', this.sid, err);
2239
2054
  }
2240
- log$4.debug('ERROR: Failed to subscribe on conversation objects', this.sid, err);
2055
+ log$3.debug('ERROR: Failed to subscribe on conversation objects', this.sid, err);
2241
2056
  throw err;
2242
2057
  }
2243
2058
  }
@@ -2269,7 +2084,7 @@ class Conversation extends EventEmitter {
2269
2084
  if (status === 'joined') {
2270
2085
  this._subscribeStreams()
2271
2086
  .catch(err => {
2272
- log$4.debug('ERROR while setting conversation status ' + status, err);
2087
+ log$3.debug('ERROR while setting conversation status ' + status, err);
2273
2088
  if (this.services.syncClient.connectionState !== 'disconnected') {
2274
2089
  throw err;
2275
2090
  }
@@ -2277,7 +2092,7 @@ class Conversation extends EventEmitter {
2277
2092
  }
2278
2093
  else if (this.entityPromise) {
2279
2094
  this._unsubscribe().catch(err => {
2280
- log$4.debug('ERROR while setting conversation status ' + status, err);
2095
+ log$3.debug('ERROR while setting conversation status ' + status, err);
2281
2096
  if (this.services.syncClient.connectionState !== 'disconnected') {
2282
2097
  throw err;
2283
2098
  }
@@ -2301,7 +2116,7 @@ class Conversation extends EventEmitter {
2301
2116
  }
2302
2117
  }
2303
2118
  catch (e) {
2304
- log$4.warn('Retrieved malformed attributes from the server for conversation: ' + conversationSid);
2119
+ log$3.warn('Retrieved malformed attributes from the server for conversation: ' + conversationSid);
2305
2120
  update.attributes = {};
2306
2121
  }
2307
2122
  try {
@@ -2310,7 +2125,7 @@ class Conversation extends EventEmitter {
2310
2125
  }
2311
2126
  }
2312
2127
  catch (e) {
2313
- log$4.warn('Retrieved malformed dateCreated from the server for conversation: ' + conversationSid);
2128
+ log$3.warn('Retrieved malformed dateCreated from the server for conversation: ' + conversationSid);
2314
2129
  delete update.dateCreated;
2315
2130
  }
2316
2131
  try {
@@ -2319,7 +2134,7 @@ class Conversation extends EventEmitter {
2319
2134
  }
2320
2135
  }
2321
2136
  catch (e) {
2322
- log$4.warn('Retrieved malformed dateUpdated from the server for conversation: ' + conversationSid);
2137
+ log$3.warn('Retrieved malformed dateUpdated from the server for conversation: ' + conversationSid);
2323
2138
  delete update.dateUpdated;
2324
2139
  }
2325
2140
  try {
@@ -2328,7 +2143,7 @@ class Conversation extends EventEmitter {
2328
2143
  }
2329
2144
  }
2330
2145
  catch (e) {
2331
- log$4.warn('Retrieved malformed lastMessage.timestamp from the server for conversation: ' + conversationSid);
2146
+ log$3.warn('Retrieved malformed lastMessage.timestamp from the server for conversation: ' + conversationSid);
2332
2147
  delete update.lastMessage.timestamp;
2333
2148
  }
2334
2149
  }
@@ -2338,7 +2153,7 @@ class Conversation extends EventEmitter {
2338
2153
  */
2339
2154
  _update(update) {
2340
2155
  var _a, _b, _c, _d, _e;
2341
- log$4.trace('_update', update);
2156
+ log$3.trace('_update', update);
2342
2157
  Conversation.preprocessUpdate(update, this.sid);
2343
2158
  const updateReasons = new Set();
2344
2159
  for (const key of Object.keys(update)) {
@@ -2356,7 +2171,7 @@ class Conversation extends EventEmitter {
2356
2171
  updateReasons.add(localKey);
2357
2172
  break;
2358
2173
  case fieldMappings.attributes:
2359
- if (isDeepEqual(this.channelState.attributes, update.attributes)) {
2174
+ if (isEqual__default['default'](this.channelState.attributes, update.attributes)) {
2360
2175
  break;
2361
2176
  }
2362
2177
  this.channelState.attributes = update.attributes;
@@ -2387,7 +2202,7 @@ class Conversation extends EventEmitter {
2387
2202
  this.channelState.lastMessage.dateCreated = update.lastMessage.timestamp;
2388
2203
  updateReasons.add(localKey);
2389
2204
  }
2390
- if (isDeepEqual(this.channelState.lastMessage, {})) {
2205
+ if (isEqual__default['default'](this.channelState.lastMessage, {})) {
2391
2206
  delete this.channelState.lastMessage;
2392
2207
  }
2393
2208
  break;
@@ -2396,7 +2211,7 @@ class Conversation extends EventEmitter {
2396
2211
  if (state !== undefined) {
2397
2212
  state.dateUpdated = new Date(state.dateUpdated);
2398
2213
  }
2399
- if (isDeepEqual(this.channelState.state, state)) {
2214
+ if (isEqual__default['default'](this.channelState.state, state)) {
2400
2215
  break;
2401
2216
  }
2402
2217
  this.channelState.state = state;
@@ -2449,8 +2264,8 @@ class Conversation extends EventEmitter {
2449
2264
  * @param address User address of the participant.
2450
2265
  * @param attributes Attributes to be attached to the participant.
2451
2266
  */
2452
- async addNonChatParticipant(proxyAddress, address, attributes = {}) {
2453
- return this.participantsEntity.addNonChatParticipant(proxyAddress, address, attributes !== null && attributes !== void 0 ? attributes : {});
2267
+ async addNonChatParticipant(proxyAddress, address, attributes) {
2268
+ return this.participantsEntity.addNonChatParticipant(proxyAddress, address, attributes);
2454
2269
  }
2455
2270
  /**
2456
2271
  * Advance the conversation's last read message index to the current read horizon.
@@ -2595,8 +2410,9 @@ class Conversation extends EventEmitter {
2595
2410
  return this;
2596
2411
  }
2597
2412
  /**
2598
- * Remove a participant from the conversation. When a string is passed as the argument, it will assume that the string is an identity.
2599
- * @param participant Identity or the participant object to remove.
2413
+ * Remove a participant from the conversation. When a string is passed as the
2414
+ * argument, it will assume that the string is an identity or SID.
2415
+ * @param participant Identity, SID or the participant object to remove.
2600
2416
  */
2601
2417
  async removeParticipant(participant) {
2602
2418
  await this.participantsEntity.remove(typeof participant === 'string'
@@ -2606,7 +2422,7 @@ class Conversation extends EventEmitter {
2606
2422
  /**
2607
2423
  * Send a message to the conversation.
2608
2424
  * @param message Message body for the text message,
2609
- * `FormData` or {@link Conversation.MediaOptions) for media content. Sending FormData is supported only with the browser engine.
2425
+ * `FormData` or {@link SendMediaOptions} for media content. Sending FormData is supported only with the browser engine.
2610
2426
  * @param messageAttributes Attributes for the message.
2611
2427
  * @param emailOptions Email options for the message.
2612
2428
  * @return Index of the new message.
@@ -2622,7 +2438,6 @@ class Conversation extends EventEmitter {
2622
2438
  /**
2623
2439
  * New interface to prepare for sending a message.
2624
2440
  * Use instead of `sendMessage`.
2625
- * @return {MessageBuilder} [description]
2626
2441
  */
2627
2442
  prepareMessage() {
2628
2443
  return new MessageBuilder(this.limits, this.messagesEntity);
@@ -2802,7 +2617,7 @@ __decorate([
2802
2617
  __metadata("design:returntype", Promise)
2803
2618
  ], Conversation.prototype, "add", null);
2804
2619
  __decorate([
2805
- declarativeTypeValidator.validateTypesAsync(declarativeTypeValidator.nonEmptyString, declarativeTypeValidator.nonEmptyString, [declarativeTypeValidator.pureObject, 'undefined']),
2620
+ declarativeTypeValidator.validateTypesAsync(declarativeTypeValidator.nonEmptyString, declarativeTypeValidator.nonEmptyString, ['undefined', 'string', 'number', 'boolean', 'object', declarativeTypeValidator.literal(null)]),
2806
2621
  __metadata("design:type", Function),
2807
2622
  __metadata("design:paramtypes", [String, String, Object]),
2808
2623
  __metadata("design:returntype", Promise)
@@ -2876,7 +2691,7 @@ __decorate([
2876
2691
  __metadata("design:returntype", Promise)
2877
2692
  ], Conversation.prototype, "updateAttributes", null);
2878
2693
  __decorate([
2879
- declarativeTypeValidator.validateTypesAsync(['string', declarativeTypeValidator.literal(null)]),
2694
+ declarativeTypeValidator.validateTypesAsync(['string']),
2880
2695
  __metadata("design:type", Function),
2881
2696
  __metadata("design:paramtypes", [String]),
2882
2697
  __metadata("design:returntype", Promise)
@@ -2914,12 +2729,12 @@ class Deferred {
2914
2729
  }
2915
2730
  }
2916
2731
 
2917
- const log$3 = Logger.scope('Conversations');
2732
+ const log$2 = Logger.scope('Conversations');
2918
2733
  /**
2919
2734
  * Represents conversations collection
2920
2735
  * {@see Conversation}
2921
2736
  */
2922
- class Conversations extends EventEmitter {
2737
+ class Conversations extends replayEventEmitter.ReplayEventEmitter {
2923
2738
  constructor(configuration, services) {
2924
2739
  super();
2925
2740
  this.conversations = new Map();
@@ -2971,11 +2786,11 @@ class Conversations extends EventEmitter {
2971
2786
  try {
2972
2787
  const map = await this._getMap();
2973
2788
  map.on('itemAdded', args => {
2974
- log$3.debug(`itemAdded: ${args.item.key}`);
2789
+ log$2.debug(`itemAdded: ${args.item.key}`);
2975
2790
  this._upsertConversation('sync', args.item.key, args.item.data);
2976
2791
  });
2977
2792
  map.on('itemRemoved', args => {
2978
- log$3.debug(`itemRemoved: ${args.key}`);
2793
+ log$2.debug(`itemRemoved: ${args.key}`);
2979
2794
  const sid = args.key;
2980
2795
  if (!this.myConversationsFetched) {
2981
2796
  this.tombstones.add(sid);
@@ -2993,7 +2808,7 @@ class Conversations extends EventEmitter {
2993
2808
  conversation.emit('removed', conversation);
2994
2809
  });
2995
2810
  map.on('itemUpdated', args => {
2996
- log$3.debug(`itemUpdated: ${args.item.key}`);
2811
+ log$2.debug(`itemUpdated: ${args.item.key}`);
2997
2812
  this._upsertConversation('sync', args.item.key, args.item.data);
2998
2813
  });
2999
2814
  const myConversations = await this._fetchMyConversations();
@@ -3005,15 +2820,15 @@ class Conversations extends EventEmitter {
3005
2820
  await Promise.all(upserts);
3006
2821
  this.myConversationsFetched = true;
3007
2822
  this.tombstones.clear();
3008
- log$3.debug('The conversations list has been successfully fetched');
2823
+ log$2.debug('The conversations list has been successfully fetched');
3009
2824
  return this;
3010
2825
  }
3011
2826
  catch (error) {
3012
2827
  const errorMessage = 'Failed to fetch the conversations list';
3013
2828
  if (this.services.syncClient.connectionState !== 'disconnected') {
3014
- log$3.error(errorMessage, error);
2829
+ log$2.error(errorMessage, error);
3015
2830
  }
3016
- log$3.debug(`ERROR: ${errorMessage}`, error);
2831
+ log$2.debug(`ERROR: ${errorMessage}`, error);
3017
2832
  throw error;
3018
2833
  }
3019
2834
  }
@@ -3057,9 +2872,6 @@ class Conversations extends EventEmitter {
3057
2872
  .build();
3058
2873
  const response = await this.services.network.get(url);
3059
2874
  const body = response.body;
3060
- if (body.type !== 'private') {
3061
- return null;
3062
- }
3063
2875
  const data = {
3064
2876
  entityName: null,
3065
2877
  // lastConsumedMessageIndex: body.last_read_message_index,
@@ -3096,7 +2908,7 @@ class Conversations extends EventEmitter {
3096
2908
  const areSourcesDifferent = conversation._statusSource() !== undefined && source !== conversation._statusSource();
3097
2909
  const isChannelSourceSync = source !== 'rest' || conversation._statusSource() === 'sync';
3098
2910
  if (areSourcesDifferent && isChannelSourceSync && source !== 'sync') {
3099
- log$3.trace('upsertConversation: conversation is known from sync and came from chat, ignoring', {
2911
+ log$2.trace('upsertConversation: conversation is known from sync and came from chat, ignoring', {
3100
2912
  sid: conversation.sid,
3101
2913
  data: data.status,
3102
2914
  conversation: conversation.status
@@ -3112,7 +2924,7 @@ class Conversations extends EventEmitter {
3112
2924
  if (typeof data.lastConsumedMessageIndex !== 'undefined') {
3113
2925
  updateData.lastConsumedMessageIndex = data.lastConsumedMessageIndex;
3114
2926
  }
3115
- if (!isDeepEqual(updateData, {})) {
2927
+ if (!isEqual__default['default'](updateData, {})) {
3116
2928
  conversation._update(updateData);
3117
2929
  }
3118
2930
  conversation._subscribe().then(() => {
@@ -3134,11 +2946,11 @@ class Conversations extends EventEmitter {
3134
2946
  conversation._update(data);
3135
2947
  }
3136
2948
  async _upsertConversation(source, sid, data) {
3137
- log$3.trace(`upsertConversation called for ${sid}`, data);
2949
+ log$2.trace(`upsertConversation called for ${sid}`, data);
3138
2950
  const conversation = this.conversations.get(sid);
3139
2951
  // If the channel is known, update it
3140
2952
  if (conversation) {
3141
- log$3.trace(`upsertConversation: the conversation ${conversation.sid} is known;` +
2953
+ log$2.trace(`upsertConversation: the conversation ${conversation.sid} is known;` +
3142
2954
  `its status is known from the source ${conversation._statusSource()} ` +
3143
2955
  `and the update came from the source ${source}`, conversation);
3144
2956
  await this._updateConversation(source, conversation, data);
@@ -3147,11 +2959,11 @@ class Conversations extends EventEmitter {
3147
2959
  }
3148
2960
  // If the conversations is deleted, ignore it
3149
2961
  if (['chat', 'rest'].includes(source) && this.tombstones.has(sid)) {
3150
- log$3.trace('upsertChannel: the channel is deleted but reappeared again from chat, ignoring', sid);
2962
+ log$2.trace('upsertChannel: the channel is deleted but reappeared again from chat, ignoring', sid);
3151
2963
  return;
3152
2964
  }
3153
2965
  // If the conversation is unknown, fetch it
3154
- log$3.trace('upsertConversation: creating a local conversation object with sid ' + sid, data);
2966
+ log$2.trace('upsertConversation: creating a local conversation object with sid ' + sid, data);
3155
2967
  const baseLink = `${this.configuration.links.conversations}/${sid}`;
3156
2968
  const links = {
3157
2969
  self: baseLink,
@@ -3214,231 +3026,16 @@ class Conversations extends EventEmitter {
3214
3026
  }
3215
3027
  }
3216
3028
 
3217
- const log$2 = Logger.scope('User');
3218
- /**
3219
- * Extended user information.
3220
- * Note that `isOnline` and `isNotifiable` properties are eligible
3221
- * for use only if the reachability function is enabled.
3222
- * You may check if it is enabled by reading the value of {@link Client.reachabilityEnabled}.
3223
- */
3224
- class User extends EventEmitter {
3225
- /**
3226
- * @internal
3227
- */
3228
- constructor(identity, entityName, links, configuration, services) {
3229
- super();
3230
- /**
3231
- * Fired when the properties or the reachability status of the message has been updated.
3232
- *
3233
- * Parameters:
3234
- * 1. object `data` - info object provided with the event. It has the following properties:
3235
- * * {@link User} user - the user in question
3236
- * * {@link UserUpdateReason}[] updateReasons - array of reasons for the update
3237
- * @event
3238
- */
3239
- this.updated = 'updated';
3240
- /**
3241
- * Fired when the client has subscribed to the user.
3242
- *
3243
- * Parameters:
3244
- * 1. {@link User} `user` - the user in question
3245
- * @event
3246
- */
3247
- this.userSubscribed = 'userSubscribed';
3248
- /**
3249
- * Fired when the client has unsubscribed from the user.
3250
- *
3251
- * Parameters:
3252
- * 1. {@link User} `user` - the user in question
3253
- * @event
3254
- */
3255
- this.userUnsubscribed = 'userUnsubscribed';
3256
- this.links = links;
3257
- this.configuration = configuration;
3258
- this.services = services;
3259
- this.subscribed = 'initializing';
3260
- this.setMaxListeners(0);
3261
- this.state = {
3262
- identity,
3263
- entityName,
3264
- friendlyName: null,
3265
- attributes: {},
3266
- online: null,
3267
- notifiable: null
3268
- };
3269
- }
3270
- /**
3271
- * User identity.
3272
- */
3273
- get identity() { return this.state.identity; }
3274
- set identity(identity) { this.state.identity = identity; }
3275
- set entityName(name) { this.state.entityName = name; }
3276
- /**
3277
- * Custom attributes of the user.
3278
- */
3279
- get attributes() { return this.state.attributes; }
3280
- /**
3281
- * Friendly name of the user, null if not set.
3282
- */
3283
- get friendlyName() { return this.state.friendlyName; }
3284
- /**
3285
- * Status of the real-time conversation connection of the user.
3286
- */
3287
- get isOnline() { return this.state.online; }
3288
- /**
3289
- * User push notification registration status.
3290
- */
3291
- get isNotifiable() { return this.state.notifiable; }
3292
- /**
3293
- * True if this user is receiving real-time status updates.
3294
- */
3295
- get isSubscribed() { return this.subscribed == 'subscribed'; }
3296
- // Handles service updates
3297
- _update(key, value) {
3298
- let updateReasons = [];
3299
- log$2.debug('User for', this.state.identity, 'updated:', key, value);
3300
- switch (key) {
3301
- case 'friendlyName':
3302
- if (this.state.friendlyName !== value.value) {
3303
- updateReasons.push('friendlyName');
3304
- this.state.friendlyName = value.value;
3305
- }
3306
- break;
3307
- case 'attributes':
3308
- const updateAttributes = parseAttributes(value.value, `Retrieved malformed attributes from the server for user: ${this.state.identity}`, log$2);
3309
- if (!isDeepEqual(this.state.attributes, updateAttributes)) {
3310
- this.state.attributes = updateAttributes;
3311
- updateReasons.push('attributes');
3312
- }
3313
- break;
3314
- case 'reachability':
3315
- if (this.state.online !== value.online) {
3316
- this.state.online = value.online;
3317
- updateReasons.push('reachabilityOnline');
3318
- }
3319
- if (this.state.notifiable !== value.notifiable) {
3320
- this.state.notifiable = value.notifiable;
3321
- updateReasons.push('reachabilityNotifiable');
3322
- }
3323
- break;
3324
- default:
3325
- return;
3326
- }
3327
- if (updateReasons.length > 0) {
3328
- this.emit('updated', { user: this, updateReasons: updateReasons });
3329
- }
3330
- }
3331
- // Fetch reachability info
3332
- async _updateReachabilityInfo(map, update) {
3333
- if (!this.configuration.reachabilityEnabled) {
3334
- return Promise.resolve();
3335
- }
3336
- return map.get('reachability')
3337
- .then(update)
3338
- .catch(err => { log$2.warn('Failed to get reachability info for ', this.state.identity, err); });
3339
- }
3340
- // Fetch user
3341
- async _fetch() {
3342
- if (!this.state.entityName) {
3343
- return this;
3344
- }
3345
- this.promiseToFetch = this.services.syncClient.map({ id: this.state.entityName, mode: 'open_existing', includeItems: true })
3346
- .then(map => {
3347
- this.entity = map;
3348
- map.on('itemUpdated', args => {
3349
- log$2.debug(this.state.entityName + ' (' + this.state.identity + ') itemUpdated: ' + args.item.key);
3350
- return this._update(args.item.key, args.item.data);
3351
- });
3352
- return Promise.all([
3353
- map.get('friendlyName')
3354
- .then(item => this._update(item.key, item.data)),
3355
- map.get('attributes')
3356
- .then(item => this._update(item.key, item.data)),
3357
- this._updateReachabilityInfo(map, item => this._update(item.key, item.data))
3358
- ]);
3359
- })
3360
- .then(() => {
3361
- log$2.debug('Fetched for', this.identity);
3362
- this.subscribed = 'subscribed';
3363
- this.emit('userSubscribed', this);
3364
- return this;
3365
- })
3366
- .catch(err => {
3367
- this.promiseToFetch = null;
3368
- throw err;
3369
- });
3370
- return this.promiseToFetch;
3371
- }
3372
- _ensureFetched() {
3373
- return this.promiseToFetch || this._fetch();
3374
- }
3375
- /**
3376
- * Edit user attributes.
3377
- * @param attributes New attributes.
3378
- */
3379
- async updateAttributes(attributes) {
3380
- if (this.subscribed == 'unsubscribed') {
3381
- throw new Error('Can\'t modify unsubscribed object');
3382
- }
3383
- await this.services.commandExecutor.mutateResource('post', this.links.self, {
3384
- attributes: JSON.stringify(attributes)
3385
- });
3386
- return this;
3387
- }
3388
- /**
3389
- * Update the friendly name of the user.
3390
- * @param friendlyName New friendly name.
3391
- */
3392
- async updateFriendlyName(friendlyName) {
3393
- if (this.subscribed == 'unsubscribed') {
3394
- throw new Error('Can\'t modify unsubscribed object');
3395
- }
3396
- await this.services.commandExecutor.mutateResource('post', this.links.self, {
3397
- friendly_name: friendlyName
3398
- });
3399
- return this;
3400
- }
3401
- /**
3402
- * Remove the user from the subscription list.
3403
- * @return A promise of completion.
3404
- */
3405
- async unsubscribe() {
3406
- if (this.promiseToFetch) {
3407
- await this.promiseToFetch;
3408
- this.entity.close();
3409
- this.promiseToFetch = null;
3410
- this.subscribed = 'unsubscribed';
3411
- this.emit('userUnsubscribed', this);
3412
- }
3413
- }
3414
- }
3415
- __decorate([
3416
- declarativeTypeValidator.validateTypesAsync(['string', 'number', 'boolean', 'object', declarativeTypeValidator.literal(null)]),
3417
- __metadata("design:type", Function),
3418
- __metadata("design:paramtypes", [Object]),
3419
- __metadata("design:returntype", Promise)
3420
- ], User.prototype, "updateAttributes", null);
3421
- __decorate([
3422
- declarativeTypeValidator.validateTypesAsync(['string']),
3423
- __metadata("design:type", Function),
3424
- __metadata("design:paramtypes", [String]),
3425
- __metadata("design:returntype", Promise)
3426
- ], User.prototype, "updateFriendlyName", null);
3427
-
3428
3029
  /**
3429
- * @classdesc Container for known users
3430
- * @fires Users#userUpdated
3030
+ * Container for known users
3431
3031
  */
3432
- class Users extends EventEmitter {
3433
- constructor(configuration, services) {
3032
+ class Users extends replayEventEmitter.ReplayEventEmitter {
3033
+ constructor(myself, configuration, services) {
3434
3034
  super();
3435
- const links = {
3436
- self: `${configuration.links.users}/${configuration.userIdentity}`
3437
- };
3438
3035
  this.configuration = configuration;
3439
3036
  this.services = services;
3440
3037
  this.fifoStack = [];
3441
- this.myself = new User(this.configuration.userIdentity, this.configuration.userInfo, links, this.configuration, this.services);
3038
+ this.myself = myself;
3442
3039
  this.myself.on('updated', (args) => this.emit('userUpdated', args));
3443
3040
  this.myself.on('userSubscribed', () => this.emit('userSubscribed', this.myself));
3444
3041
  this.myself.on('userUnsubscribed', () => {
@@ -3490,10 +3087,7 @@ class Users extends EventEmitter {
3490
3087
  if (!entityName) {
3491
3088
  entityName = await this.getSyncUniqueName(identity);
3492
3089
  }
3493
- const links = {
3494
- self: `${this.configuration.links.users}/${identity}`
3495
- };
3496
- user = new User(identity, entityName, links, this.configuration, this.services);
3090
+ user = new User(identity, entityName, this.configuration, this.services);
3497
3091
  user.on('updated', (args) => this.emit('userUpdated', args));
3498
3092
  user.on('userSubscribed', () => this.handleSubscribeUser(user));
3499
3093
  user.on('userUnsubscribed', () => this.handleUnsubscribeUser(user));
@@ -3638,7 +3232,7 @@ class PushNotification {
3638
3232
  }
3639
3233
  }
3640
3234
 
3641
- var version = "2.0.0-rc.1";
3235
+ var version = "2.0.1-rc.1";
3642
3236
 
3643
3237
  const trimSlashes = (url) => url.replace(/(^\/+|\/+$)/g, '');
3644
3238
  const isMutationConflictResponse = (response) => response.status.code === 202;
@@ -3714,7 +3308,7 @@ class ClientServices {
3714
3308
  /**
3715
3309
  * A client is the starting point to the Twilio Conversations functionality.
3716
3310
  */
3717
- exports.Client = Client_1 = class Client extends EventEmitter {
3311
+ exports.Client = Client_1 = class Client extends replayEventEmitter.ReplayEventEmitter {
3718
3312
  /**
3719
3313
  * Returned Conversations instance is not yet fully initialized. Calling any operations will block until it is.
3720
3314
  * Use connection events to monitor when client becomes fully available (connectionStateChanged with state
@@ -3773,6 +3367,7 @@ exports.Client = Client_1 = class Client extends EventEmitter {
3773
3367
  throw new Error('A valid Twilio token should be provided');
3774
3368
  }
3775
3369
  this.services = new ClientServices();
3370
+ this._myself = new User('', '', null, this.services);
3776
3371
  const startTwilsock = !this.options.twilsockClient;
3777
3372
  // Create default init registrations if none were provided.
3778
3373
  // Otherwise, the outside party have to list all the init registrations they
@@ -3847,6 +3442,13 @@ exports.Client = Client_1 = class Client extends EventEmitter {
3847
3442
  * The factory method will automatically trigger connection.
3848
3443
  * Do not use it if you need finer-grained control.
3849
3444
  *
3445
+ * Since this method returns an already-initialized client, some of the events
3446
+ * will be lost because they happen *before* the initialization. It is
3447
+ * recommended that `client.onWithReplay` is used as opposed to `client.on`
3448
+ * for subscribing to client events. The `client.onWithReplay` will re-emit
3449
+ * the most recent value for a given event if it emitted before the
3450
+ * subscription.
3451
+ *
3850
3452
  * @param token Access token.
3851
3453
  * @param options Options to customize the client.
3852
3454
  * @returns Returns a fully initialized client.
@@ -3868,13 +3470,23 @@ exports.Client = Client_1 = class Client extends EventEmitter {
3868
3470
  return client;
3869
3471
  }
3870
3472
  /**
3871
- * Information of the logged-in user.
3473
+ * Information of the logged-in user. Before client initialization, returns an
3474
+ * uninitialized user. Will trigger a {@link Client.userUpdated} event after
3475
+ * initialization.
3872
3476
  */
3873
- get user() { return this.services.users.myself; }
3477
+ get user() { return this._myself; }
3874
3478
  /**
3875
- * Client reachability state.
3479
+ * Client reachability state. Throws if accessed before the client
3480
+ * initialization was completed.
3876
3481
  */
3877
- get reachabilityEnabled() { return this.configuration.reachabilityEnabled; }
3482
+ get reachabilityEnabled() {
3483
+ if (!this.configuration) {
3484
+ throw new Error('Reachability information could not yet be accessed as the client ' +
3485
+ "has not yet been initialized. Subscribe to the 'stateChanged' event " +
3486
+ 'to properly react to the client initialization.');
3487
+ }
3488
+ return this.configuration.reachabilityEnabled;
3489
+ }
3878
3490
  get token() { return this.fpaToken; }
3879
3491
  _subscribeToPushNotifications(channelType) {
3880
3492
  [NotificationTypes.NEW_MESSAGE,
@@ -3899,9 +3511,10 @@ exports.Client = Client_1 = class Client extends EventEmitter {
3899
3511
  async _initialize() {
3900
3512
  const configurationResponse = await this.services.commandExecutor.fetchResource('Client/v2/Configuration');
3901
3513
  this.configuration = new Configuration(this.options, configurationResponse, log);
3514
+ this._myself._resolveInitialization(this.configuration, this.configuration.userIdentity, this.configuration.userInfo, true);
3902
3515
  this.services.typingIndicator = new TypingIndicator(this.getConversationBySid.bind(this), this.configuration, this.services);
3903
3516
  this.services.network = new Network(this.configuration, this.services);
3904
- this.services.users = new Users(this.configuration, this.services);
3517
+ this.services.users = new Users(this._myself, this.configuration, this.services);
3905
3518
  this.services.users.on('userSubscribed', this.emit.bind(this, 'userSubscribed'));
3906
3519
  this.services.users.on('userUpdated', (args) => this.emit('userUpdated', args));
3907
3520
  this.services.users.on('userUnsubscribed', this.emit.bind(this, 'userUnsubscribed'));
@@ -4007,6 +3620,7 @@ exports.Client = Client_1 = class Client extends EventEmitter {
4007
3620
  */
4008
3621
  async setPushRegistrationId(channelType, registrationId) {
4009
3622
  await this._ensureReady;
3623
+ this._subscribeToPushNotifications(channelType);
4010
3624
  this.services.notificationClient.setPushRegistrationId(channelType, registrationId);
4011
3625
  await this.services.notificationClient.commitChanges(); // Committing before this point is useless because we have no push id
4012
3626
  }
@@ -4173,7 +3787,7 @@ exports.Client.conversationLeft = 'conversationLeft';
4173
3787
  exports.Client.conversationRemoved = 'conversationRemoved';
4174
3788
  /**
4175
3789
  * Fired when the attributes or the metadata of a conversation have been updated.
4176
- * During conversation's {@link Client.create| creation and initialization}, this event might be fired multiple times
3790
+ * During conversation's creation and initialization, this event might be fired multiple times
4177
3791
  * for same joined or created conversation as new data is arriving from different sources.
4178
3792
  *
4179
3793
  * Parameters:
@@ -4183,14 +3797,6 @@ exports.Client.conversationRemoved = 'conversationRemoved';
4183
3797
  * @event
4184
3798
  */
4185
3799
  exports.Client.conversationUpdated = 'conversationUpdated';
4186
- /**
4187
- * Fired when the connection state of the client has been changed.
4188
- *
4189
- * Parameters:
4190
- * 1. {@link Conversation} `conversation` - the conversation in question
4191
- * @event
4192
- */
4193
- exports.Client.conversationStateChanged = 'connectionStateChanged';
4194
3800
  /**
4195
3801
  * Fired when a participant has joined a conversation.
4196
3802
  *
@@ -4245,6 +3851,8 @@ exports.Client.messageRemoved = 'messageRemoved';
4245
3851
  exports.Client.messageUpdated = 'messageUpdated';
4246
3852
  /**
4247
3853
  * Fired when the token is about to expire and needs to be updated.
3854
+ * * Parameters:
3855
+ * 1. number `message` - token's time to live
4248
3856
  * @event
4249
3857
  */
4250
3858
  exports.Client.tokenAboutToExpire = 'tokenAboutToExpire';
@@ -4303,6 +3911,22 @@ exports.Client.userUnsubscribed = 'userUnsubscribed';
4303
3911
  * @event
4304
3912
  */
4305
3913
  exports.Client.userUpdated = 'userUpdated';
3914
+ /**
3915
+ * Fired when the state of the client has been changed.
3916
+ *
3917
+ * Parameters:
3918
+ * 1. {@link State} `state` - the new client state
3919
+ * @event
3920
+ */
3921
+ exports.Client.stateChanged = 'stateChanged';
3922
+ /**
3923
+ * Fired when the connection state of the client has been changed.
3924
+ *
3925
+ * Paremeters:
3926
+ * 1. {@link ConnectionState} `state` - the new connection state
3927
+ * @event
3928
+ */
3929
+ exports.Client.connectionStateChanged = 'connectionStateChanged';
4306
3930
  /**
4307
3931
  * Fired when the connection is interrupted for an unexpected reason.
4308
3932
  *
@@ -4391,22 +4015,21 @@ __decorate([
4391
4015
  exports.Client = Client_1 = __decorate([
4392
4016
  declarativeTypeValidator.validateConstructorTypes(declarativeTypeValidator.nonEmptyString, [
4393
4017
  declarativeTypeValidator.pureObject,
4394
- 'undefined',
4395
- declarativeTypeValidator.literal(null),
4018
+ 'undefined'
4396
4019
  ]),
4397
4020
  __metadata("design:paramtypes", [String, Object])
4398
4021
  ], exports.Client);
4399
4022
 
4400
- var Client = exports.Client;
4401
-
4402
4023
  exports.AggregatedDeliveryReceipt = AggregatedDeliveryReceipt;
4403
4024
  exports.Conversation = Conversation;
4404
4025
  exports.DetailedDeliveryReceipt = DetailedDeliveryReceipt;
4405
4026
  exports.Media = Media;
4406
4027
  exports.Message = Message;
4028
+ exports.MessageBuilder = MessageBuilder;
4029
+ exports.NotificationTypes = NotificationTypes;
4407
4030
  exports.Participant = Participant;
4408
4031
  exports.PushNotification = PushNotification;
4409
4032
  exports.RestPaginator = RestPaginator;
4033
+ exports.UnsentMessage = UnsentMessage;
4410
4034
  exports.User = User;
4411
- exports.default = Client;
4412
4035
  //# sourceMappingURL=react-native.js.map