@twilio/conversations 2.0.1-rc.3 → 2.0.1-rc.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/{dist → builds}/browser.js +2 -2
- package/builds/browser.js.map +1 -0
- package/{dist → builds}/lib.d.ts +0 -0
- package/{dist → builds}/lib.js +2 -2
- package/builds/lib.js.map +1 -0
- package/{dist → builds}/twilio-conversations.js +5 -5
- package/{dist → builds}/twilio-conversations.min.js +2 -2
- package/dist/aggregated-delivery-receipt.js +227 -0
- package/dist/aggregated-delivery-receipt.js.map +1 -0
- package/dist/client.js +872 -0
- package/dist/client.js.map +1 -0
- package/dist/command-executor.js +203 -0
- package/dist/command-executor.js.map +1 -0
- package/dist/configuration.js +196 -0
- package/dist/configuration.js.map +1 -0
- package/dist/conversation.js +973 -0
- package/dist/conversation.js.map +1 -0
- package/dist/data/conversations.js +443 -0
- package/dist/data/conversations.js.map +1 -0
- package/dist/data/messages.js +341 -0
- package/dist/data/messages.js.map +1 -0
- package/dist/data/participants.js +313 -0
- package/dist/data/participants.js.map +1 -0
- package/dist/data/users.js +228 -0
- package/dist/data/users.js.map +1 -0
- package/dist/detailed-delivery-receipt.js +154 -0
- package/dist/detailed-delivery-receipt.js.map +1 -0
- package/dist/index.js +167 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/notification-types.js +143 -0
- package/dist/interfaces/notification-types.js.map +1 -0
- package/dist/logger.js +190 -0
- package/dist/logger.js.map +1 -0
- package/dist/media.js +213 -0
- package/dist/media.js.map +1 -0
- package/dist/message-builder.js +209 -0
- package/dist/message-builder.js.map +1 -0
- package/dist/message.js +450 -0
- package/dist/message.js.map +1 -0
- package/dist/node_modules/tslib/tslib.es6.js +161 -0
- package/dist/node_modules/tslib/tslib.es6.js.map +1 -0
- package/dist/packages/conversations/package.json.js +136 -0
- package/dist/packages/conversations/package.json.js.map +1 -0
- package/dist/participant.js +346 -0
- package/dist/participant.js.map +1 -0
- package/dist/push-notification.js +152 -0
- package/dist/push-notification.js.map +1 -0
- package/dist/rest-paginator.js +175 -0
- package/dist/rest-paginator.js.map +1 -0
- package/dist/services/network.js +205 -0
- package/dist/services/network.js.map +1 -0
- package/dist/services/typing-indicator.js +235 -0
- package/dist/services/typing-indicator.js.map +1 -0
- package/dist/unsent-message.js +159 -0
- package/dist/unsent-message.js.map +1 -0
- package/dist/user.js +392 -0
- package/dist/user.js.map +1 -0
- package/dist/util/deferred.js +154 -0
- package/dist/util/deferred.js.map +1 -0
- package/dist/util/index.js +206 -0
- package/dist/util/index.js.map +1 -0
- package/{dist/docs → docs}/assets/css/main.css +0 -0
- package/{dist/docs → docs}/assets/images/icons.png +0 -0
- package/{dist/docs → docs}/assets/images/icons@2x.png +0 -0
- package/{dist/docs → docs}/assets/images/widgets.png +0 -0
- package/{dist/docs → docs}/assets/images/widgets@2x.png +0 -0
- package/{dist/docs → docs}/assets/js/main.js +0 -0
- package/{dist/docs → docs}/assets/js/search.js +0 -0
- package/{dist/docs → docs}/classes/AggregatedDeliveryReceipt.html +0 -0
- package/{dist/docs → docs}/classes/Client.html +0 -0
- package/{dist/docs → docs}/classes/Conversation.html +0 -0
- package/{dist/docs → docs}/classes/DetailedDeliveryReceipt.html +0 -0
- package/{dist/docs → docs}/classes/Media.html +0 -0
- package/{dist/docs → docs}/classes/Message.html +0 -0
- package/{dist/docs → docs}/classes/MessageBuilder.html +0 -0
- package/{dist/docs → docs}/classes/Participant.html +0 -0
- package/{dist/docs → docs}/classes/PushNotification.html +0 -0
- package/{dist/docs → docs}/classes/RestPaginator.html +0 -0
- package/{dist/docs → docs}/classes/UnsentMessage.html +0 -0
- package/{dist/docs → docs}/classes/User.html +0 -0
- package/{dist/docs → docs}/index.html +0 -0
- package/{dist/docs → docs}/interfaces/ClientOptions.html +0 -0
- package/{dist/docs → docs}/interfaces/ConversationState.html +0 -0
- package/{dist/docs → docs}/interfaces/CreateConversationOptions.html +0 -0
- package/{dist/docs → docs}/interfaces/LastMessage.html +0 -0
- package/{dist/docs → docs}/interfaces/Paginator.html +0 -0
- package/{dist/docs → docs}/interfaces/PushNotificationData.html +0 -0
- package/{dist/docs → docs}/interfaces/SendEmailOptions.html +0 -0
- package/{dist/docs → docs}/interfaces/SendMediaOptions.html +0 -0
- package/{dist/docs → docs}/modules.html +0 -0
- package/package.json +23 -24
- package/dist/browser.js.map +0 -1
- package/dist/lib.js.map +0 -1
- package/dist/post-install.js +0 -29
- package/dist/react-native.js +0 -4035
- package/dist/react-native.js.map +0 -1
package/dist/react-native.js
DELETED
@@ -1,4035 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
@license
|
3
|
-
The following license applies to all parts of this software except as
|
4
|
-
documented below.
|
5
|
-
|
6
|
-
Copyright (c) 2019, Twilio, inc.
|
7
|
-
All rights reserved.
|
8
|
-
|
9
|
-
Redistribution and use in source and binary forms, with or without
|
10
|
-
modification, are permitted provided that the following conditions are
|
11
|
-
met:
|
12
|
-
|
13
|
-
1. Redistributions of source code must retain the above copyright
|
14
|
-
notice, this list of conditions and the following disclaimer.
|
15
|
-
|
16
|
-
2. Redistributions in binary form must reproduce the above copyright
|
17
|
-
notice, this list of conditions and the following disclaimer in
|
18
|
-
the documentation and/or other materials provided with the
|
19
|
-
distribution.
|
20
|
-
|
21
|
-
3. Neither the name of Twilio nor the names of its contributors may
|
22
|
-
be used to endorse or promote products derived from this software
|
23
|
-
without specific prior written permission.
|
24
|
-
|
25
|
-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
26
|
-
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
27
|
-
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
28
|
-
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
29
|
-
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
30
|
-
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
31
|
-
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
32
|
-
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
33
|
-
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
34
|
-
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
35
|
-
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
36
|
-
|
37
|
-
This software includes javascript-state-machine under the following license.
|
38
|
-
|
39
|
-
Copyright (c) 2012, 2013, 2014, 2015, Jake Gordon and contributors
|
40
|
-
|
41
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
42
|
-
of this software and associated documentation files (the "Software"), to deal
|
43
|
-
in the Software without restriction, including without limitation the rights
|
44
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
45
|
-
copies of the Software, and to permit persons to whom the Software is
|
46
|
-
furnished to do so, subject to the following conditions:
|
47
|
-
|
48
|
-
The above copyright notice and this permission notice shall be included in all
|
49
|
-
copies or substantial portions of the Software.
|
50
|
-
|
51
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
52
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
53
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
54
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
55
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
56
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
57
|
-
|
58
|
-
This software includes loglevel under the following license.
|
59
|
-
|
60
|
-
Copyright (c) 2013 Tim Perry
|
61
|
-
|
62
|
-
Permission is hereby granted, free of charge, to any person
|
63
|
-
obtaining a copy of this software and associated documentation
|
64
|
-
files (the "Software"), to deal in the Software without
|
65
|
-
restriction, including without limitation the rights to use,
|
66
|
-
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
67
|
-
copies of the Software, and to permit persons to whom the
|
68
|
-
Software is furnished to do so, subject to the following
|
69
|
-
conditions:
|
70
|
-
|
71
|
-
The above copyright notice and this permission notice shall be
|
72
|
-
included in all copies or substantial portions of the Software.
|
73
|
-
|
74
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
75
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
76
|
-
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
77
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
78
|
-
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
79
|
-
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
80
|
-
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
81
|
-
OTHER DEALINGS IN THE SOFTWARE.
|
82
|
-
|
83
|
-
This software includes q under the following license.
|
84
|
-
|
85
|
-
Copyright 2009–2014 Kristopher Michael Kowal. All rights reserved.
|
86
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
87
|
-
of this software and associated documentation files (the "Software"), to
|
88
|
-
deal in the Software without restriction, including without limitation the
|
89
|
-
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
90
|
-
sell copies of the Software, and to permit persons to whom the Software is
|
91
|
-
furnished to do so, subject to the following conditions:
|
92
|
-
|
93
|
-
The above copyright notice and this permission notice shall be included in
|
94
|
-
all copies or substantial portions of the Software.
|
95
|
-
|
96
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
97
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
98
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
99
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
100
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
101
|
-
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
102
|
-
IN THE SOFTWARE.
|
103
|
-
|
104
|
-
This software includes platform.js under the following license.
|
105
|
-
|
106
|
-
Copyright 2014 Benjamin Tan <https://d10.github.io/>
|
107
|
-
Copyright 2011-2015 John-David Dalton <http://allyoucanleet.com/>
|
108
|
-
|
109
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
110
|
-
a copy of this software and associated documentation files (the
|
111
|
-
"Software"), to deal in the Software without restriction, including
|
112
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
113
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
114
|
-
permit persons to whom the Software is furnished to do so, subject to
|
115
|
-
the following conditions:
|
116
|
-
|
117
|
-
The above copyright notice and this permission notice shall be
|
118
|
-
included in all copies or substantial portions of the Software.
|
119
|
-
|
120
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
121
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
122
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
123
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
124
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
125
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
126
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
127
|
-
|
128
|
-
*/
|
129
|
-
'use strict';
|
130
|
-
|
131
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
132
|
-
|
133
|
-
var loglevelLog = require('loglevel');
|
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');
|
138
|
-
var operationRetrier = require('@twilio/operation-retrier');
|
139
|
-
var twilsock = require('twilsock');
|
140
|
-
var notifications = require('@twilio/notifications');
|
141
|
-
var twilioSync = require('twilio-sync');
|
142
|
-
var mcsClient = require('@twilio/mcs-client');
|
143
|
-
var uuid = require('uuid');
|
144
|
-
|
145
|
-
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
146
|
-
|
147
|
-
function _interopNamespace(e) {
|
148
|
-
if (e && e.__esModule) return e;
|
149
|
-
var n = Object.create(null);
|
150
|
-
if (e) {
|
151
|
-
Object.keys(e).forEach(function (k) {
|
152
|
-
if (k !== 'default') {
|
153
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
154
|
-
Object.defineProperty(n, k, d.get ? d : {
|
155
|
-
enumerable: true,
|
156
|
-
get: function () {
|
157
|
-
return e[k];
|
158
|
-
}
|
159
|
-
});
|
160
|
-
}
|
161
|
-
});
|
162
|
-
}
|
163
|
-
n['default'] = e;
|
164
|
-
return Object.freeze(n);
|
165
|
-
}
|
166
|
-
|
167
|
-
var loglevelLog__namespace = /*#__PURE__*/_interopNamespace(loglevelLog);
|
168
|
-
var isEqual__default = /*#__PURE__*/_interopDefaultLegacy(isEqual);
|
169
|
-
|
170
|
-
/*! *****************************************************************************
|
171
|
-
Copyright (c) Microsoft Corporation.
|
172
|
-
|
173
|
-
Permission to use, copy, modify, and/or distribute this software for any
|
174
|
-
purpose with or without fee is hereby granted.
|
175
|
-
|
176
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
177
|
-
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
178
|
-
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
179
|
-
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
180
|
-
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
181
|
-
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
182
|
-
PERFORMANCE OF THIS SOFTWARE.
|
183
|
-
***************************************************************************** */
|
184
|
-
|
185
|
-
function __decorate(decorators, target, key, desc) {
|
186
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
187
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
188
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
189
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
190
|
-
}
|
191
|
-
|
192
|
-
function __metadata(metadataKey, metadataValue) {
|
193
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
|
194
|
-
}
|
195
|
-
|
196
|
-
function prepareLine(prefix, args) {
|
197
|
-
return [`${new Date().toISOString()} Conversations ${prefix}:`].concat(Array.from(args));
|
198
|
-
}
|
199
|
-
const log$9 = loglevelLog__namespace.getLogger('twilio-conversations'); // twilio-conversations is used by Flex SDK. Please DO NOT change
|
200
|
-
class Logger {
|
201
|
-
constructor(prefix) {
|
202
|
-
this.prefix = '';
|
203
|
-
this.prefix = prefix !== null && prefix !== undefined && prefix.length > 0
|
204
|
-
? prefix + ' '
|
205
|
-
: '';
|
206
|
-
}
|
207
|
-
static scope(prefix) {
|
208
|
-
return new Logger(prefix);
|
209
|
-
}
|
210
|
-
setLevel(level) {
|
211
|
-
log$9.setLevel(level);
|
212
|
-
}
|
213
|
-
static setLevel(level) {
|
214
|
-
log$9.setLevel(level);
|
215
|
-
}
|
216
|
-
trace(...args) { log$9.trace.apply(null, prepareLine(this.prefix + 'T', args)); }
|
217
|
-
debug(...args) { log$9.debug.apply(null, prepareLine(this.prefix + 'D', args)); }
|
218
|
-
info(...args) { log$9.info.apply(null, prepareLine(this.prefix + 'I', args)); }
|
219
|
-
warn(...args) { log$9.warn.apply(null, prepareLine(this.prefix + 'W', args)); }
|
220
|
-
error(...args) { log$9.error.apply(null, prepareLine(this.prefix + 'E', args)); }
|
221
|
-
static trace(...args) { log$9.trace.apply(null, prepareLine('T', args)); }
|
222
|
-
static debug(...args) { log$9.debug.apply(null, prepareLine('D', args)); }
|
223
|
-
static info(...args) { log$9.info.apply(null, prepareLine('I', args)); }
|
224
|
-
static warn(...args) { log$9.warn.apply(null, prepareLine('W', args)); }
|
225
|
-
static error(...args) { log$9.error.apply(null, prepareLine('E', args)); }
|
226
|
-
}
|
227
|
-
|
228
|
-
const TYPING_TIMEOUT = 5;
|
229
|
-
const HTTP_CACHE_LIFETIME = 'PT5S';
|
230
|
-
const CONSUMPTION_HORIZON_SENDING_INTERVAL = 'PT5S';
|
231
|
-
const USER_INFOS_TO_SUBSCRIBE = 100;
|
232
|
-
const MINIMUM_RETRY_DELAY = 1000;
|
233
|
-
const MAXIMUM_RETRY_DELAY = 4000;
|
234
|
-
const MAXIMUM_ATTEMPTS_COUNT = 3;
|
235
|
-
const RETRY_WHEN_THROTTLED = true;
|
236
|
-
class Configuration {
|
237
|
-
constructor(options = {}, configurationResponse, logger) {
|
238
|
-
var _a, _b, _c, _d, _e, _f;
|
239
|
-
this.typingIndicatorTimeoutDefault = TYPING_TIMEOUT * 1000;
|
240
|
-
const constructorOptions = options.Chat || options.IPMessaging || options || {};
|
241
|
-
this.productId = constructorOptions.productId;
|
242
|
-
this.links = {
|
243
|
-
myConversations: configurationResponse.links.my_conversations,
|
244
|
-
conversations: configurationResponse.links.conversations,
|
245
|
-
users: configurationResponse.links.users,
|
246
|
-
currentUser: configurationResponse.links.current_user,
|
247
|
-
typing: configurationResponse.links.typing,
|
248
|
-
mediaService: configurationResponse.links.media_service,
|
249
|
-
mediaSetService: configurationResponse.links.media_set_service,
|
250
|
-
messagesReceipts: configurationResponse.links.messages_receipts
|
251
|
-
};
|
252
|
-
this.limits = {
|
253
|
-
mediaAttachmentsCountLimit: configurationResponse.options.media_attachments_count_limit,
|
254
|
-
mediaAttachmentSizeLimitInMb: configurationResponse.options.media_attachment_size_limit_in_mb,
|
255
|
-
mediaAttachmentsTotalSizeLimitInMb: configurationResponse.options.media_attachments_total_size_limit_in_mb,
|
256
|
-
emailHistoriesAllowedMimeTypes: configurationResponse.options.email_histories_allowed_mime_types,
|
257
|
-
emailBodiesAllowedMimeTypes: configurationResponse.options.email_bodies_allowed_mime_types
|
258
|
-
};
|
259
|
-
this.typingIndicatorTimeoutOverride = constructorOptions.typingIndicatorTimeoutOverride;
|
260
|
-
this.backoffConfiguration = Object.assign({ min: MINIMUM_RETRY_DELAY, max: MAXIMUM_RETRY_DELAY, maxAttemptsCount: MAXIMUM_ATTEMPTS_COUNT }, constructorOptions.backoffConfigOverride);
|
261
|
-
this.retryWhenThrottled = constructorOptions.retryWhenThrottledOverride !== undefined
|
262
|
-
? constructorOptions.retryWhenThrottledOverride
|
263
|
-
: RETRY_WHEN_THROTTLED;
|
264
|
-
this.userInfosToSubscribe = (_b = (_a = constructorOptions.userInfosToSubscribeOverride) !== null && _a !== void 0 ? _a : configurationResponse.options.user_infos_to_subscribe) !== null && _b !== void 0 ? _b : USER_INFOS_TO_SUBSCRIBE;
|
265
|
-
this.reachabilityEnabled = configurationResponse.options.reachability_enabled;
|
266
|
-
this.userIdentity = configurationResponse.identity;
|
267
|
-
this.userInfo = configurationResponse.sync_objects.my_user_info;
|
268
|
-
this.myConversations = configurationResponse.sync_objects.my_conversations;
|
269
|
-
const httpCacheInterval = (_d = (_c = constructorOptions.httpCacheIntervalOverride) !== null && _c !== void 0 ? _c : configurationResponse.options.http_cache_interval) !== null && _d !== void 0 ? _d : HTTP_CACHE_LIFETIME;
|
270
|
-
try {
|
271
|
-
this.httpCacheInterval = iso8601Duration.toSeconds(iso8601Duration.parse(httpCacheInterval));
|
272
|
-
}
|
273
|
-
catch (_g) {
|
274
|
-
logger.error(`Failed to parse http cache interval ${httpCacheInterval}, using default value ${HTTP_CACHE_LIFETIME}`);
|
275
|
-
this.httpCacheInterval = iso8601Duration.toSeconds(iso8601Duration.parse(HTTP_CACHE_LIFETIME));
|
276
|
-
}
|
277
|
-
const consumptionReportInterval = (_f = (_e = constructorOptions.consumptionReportIntervalOverride) !== null && _e !== void 0 ? _e : configurationResponse.options.consumption_report_interval) !== null && _f !== void 0 ? _f : CONSUMPTION_HORIZON_SENDING_INTERVAL;
|
278
|
-
try {
|
279
|
-
this.consumptionReportInterval = iso8601Duration.toSeconds(iso8601Duration.parse(consumptionReportInterval));
|
280
|
-
}
|
281
|
-
catch (_h) {
|
282
|
-
logger.error(`Failed to parse consumption report interval ${consumptionReportInterval}, using default value ${CONSUMPTION_HORIZON_SENDING_INTERVAL}`);
|
283
|
-
this.consumptionReportInterval = iso8601Duration.toSeconds(iso8601Duration.parse(CONSUMPTION_HORIZON_SENDING_INTERVAL));
|
284
|
-
}
|
285
|
-
}
|
286
|
-
}
|
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
|
-
|
603
|
-
class Network {
|
604
|
-
constructor(configuration, services) {
|
605
|
-
this.configuration = configuration;
|
606
|
-
this.services = services;
|
607
|
-
this.cache = new Map();
|
608
|
-
this.cacheLifetime = this.configuration.httpCacheInterval * 100;
|
609
|
-
this.cleanupCache();
|
610
|
-
}
|
611
|
-
isExpired(timestamp) {
|
612
|
-
return !this.cacheLifetime || (Date.now() - timestamp) > this.cacheLifetime;
|
613
|
-
}
|
614
|
-
cleanupCache() {
|
615
|
-
for (let [k, v] of this.cache) {
|
616
|
-
if (this.isExpired(v.timestamp)) {
|
617
|
-
this.cache.delete(k);
|
618
|
-
}
|
619
|
-
}
|
620
|
-
if (this.cache.size === 0) {
|
621
|
-
clearInterval(this.timer);
|
622
|
-
}
|
623
|
-
}
|
624
|
-
pokeTimer() {
|
625
|
-
this.timer = this.timer || setInterval(() => this.cleanupCache(), this.cacheLifetime * 2);
|
626
|
-
}
|
627
|
-
executeWithRetry(request, retryWhenThrottled = false) {
|
628
|
-
return new Promise((resolve, reject) => {
|
629
|
-
let codesToRetryOn = [502, 503, 504];
|
630
|
-
if (retryWhenThrottled) {
|
631
|
-
codesToRetryOn.push(429);
|
632
|
-
}
|
633
|
-
let retrier = new operationRetrier.Retrier(this.configuration.backoffConfiguration);
|
634
|
-
retrier.on('attempt', () => {
|
635
|
-
request()
|
636
|
-
.then(result => retrier.succeeded(result))
|
637
|
-
.catch(err => {
|
638
|
-
if (codesToRetryOn.indexOf(err.status) > -1) {
|
639
|
-
retrier.failed(err);
|
640
|
-
}
|
641
|
-
else if (err.message === 'Twilsock disconnected') {
|
642
|
-
// Ugly hack. We must make a proper exceptions for twilsock
|
643
|
-
retrier.failed(err);
|
644
|
-
}
|
645
|
-
else {
|
646
|
-
// Fatal error
|
647
|
-
retrier.removeAllListeners();
|
648
|
-
retrier.cancel();
|
649
|
-
reject(err);
|
650
|
-
}
|
651
|
-
});
|
652
|
-
});
|
653
|
-
retrier.on('succeeded', result => { resolve(result); });
|
654
|
-
retrier.on('cancelled', err => reject(err));
|
655
|
-
retrier.on('failed', err => reject(err));
|
656
|
-
retrier.start();
|
657
|
-
});
|
658
|
-
}
|
659
|
-
async get(url) {
|
660
|
-
let cacheEntry = this.cache.get(url);
|
661
|
-
if (cacheEntry && !this.isExpired(cacheEntry.timestamp)) {
|
662
|
-
return cacheEntry.response;
|
663
|
-
}
|
664
|
-
const headers = {};
|
665
|
-
let response = await this.executeWithRetry(() => this.services.transport.get(url, headers, this.configuration.productId), this.configuration.retryWhenThrottled);
|
666
|
-
this.cache.set(url, { response, timestamp: Date.now() });
|
667
|
-
this.pokeTimer();
|
668
|
-
return response;
|
669
|
-
}
|
670
|
-
}
|
671
|
-
|
672
|
-
class NotificationTypes {
|
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';
|
680
|
-
|
681
|
-
const log$7 = Logger.scope('Participant');
|
682
|
-
/**
|
683
|
-
* A participant represents a remote client in a conversation.
|
684
|
-
*/
|
685
|
-
class Participant extends replayEventEmitter.ReplayEventEmitter {
|
686
|
-
/**
|
687
|
-
* @internal
|
688
|
-
*/
|
689
|
-
constructor(data, sid, conversation, links, services) {
|
690
|
-
super();
|
691
|
-
this.conversation = conversation;
|
692
|
-
this.links = links;
|
693
|
-
this.services = services;
|
694
|
-
this.state = {
|
695
|
-
attributes: parseAttributes(data.attributes, 'Retrieved malformed attributes from the server for participant: ' + sid, log$7),
|
696
|
-
dateCreated: data.dateCreated ? parseTime$1(data.dateCreated) : null,
|
697
|
-
dateUpdated: data.dateCreated ? parseTime$1(data.dateUpdated) : null,
|
698
|
-
sid: sid,
|
699
|
-
typingTimeout: null,
|
700
|
-
isTyping: false,
|
701
|
-
identity: data.identity || null,
|
702
|
-
roleSid: data.roleSid || null,
|
703
|
-
lastReadMessageIndex: Number.isInteger(data.lastConsumedMessageIndex) ? data.lastConsumedMessageIndex : null,
|
704
|
-
lastReadTimestamp: data.lastConsumptionTimestamp ? parseTime$1(data.lastConsumptionTimestamp) : null,
|
705
|
-
type: data.type || 'chat',
|
706
|
-
userInfo: data.userInfo
|
707
|
-
};
|
708
|
-
if (!data.identity && !data.type) {
|
709
|
-
throw new Error('Received invalid Participant object from server: Missing identity or type of Participant.');
|
710
|
-
}
|
711
|
-
}
|
712
|
-
/**
|
713
|
-
* The server-assigned unique identifier for the participant.
|
714
|
-
*/
|
715
|
-
get sid() { return this.state.sid; }
|
716
|
-
/**
|
717
|
-
* Custom attributes of the participant.
|
718
|
-
*/
|
719
|
-
get attributes() { return this.state.attributes; }
|
720
|
-
/**
|
721
|
-
* Date this participant was created on.
|
722
|
-
*/
|
723
|
-
get dateCreated() { return this.state.dateCreated; }
|
724
|
-
/**
|
725
|
-
* Date this participant was last updated on.
|
726
|
-
*/
|
727
|
-
get dateUpdated() { return this.state.dateUpdated; }
|
728
|
-
/**
|
729
|
-
* Identity of the participant.
|
730
|
-
*/
|
731
|
-
get identity() { return this.state.identity; }
|
732
|
-
/**
|
733
|
-
* Indicates whether the participant is currently typing.
|
734
|
-
*/
|
735
|
-
get isTyping() { return this.state.isTyping; }
|
736
|
-
/**
|
737
|
-
* The index of the last read message by the participant.
|
738
|
-
* Note that retrieving messages on a client endpoint does not mean that messages are read,
|
739
|
-
* please consider reading about the [Read Horizon feature](https://www.twilio.com/docs/api/chat/guides/consumption-horizon)
|
740
|
-
* to find out about the proper way to mark messages as read.
|
741
|
-
*/
|
742
|
-
get lastReadMessageIndex() { return this.state.lastReadMessageIndex; }
|
743
|
-
/**
|
744
|
-
* Date of the most recent read horizon update.
|
745
|
-
*/
|
746
|
-
get lastReadTimestamp() { return this.state.lastReadTimestamp; }
|
747
|
-
get roleSid() { return this.state.roleSid; }
|
748
|
-
/**
|
749
|
-
* Message type of the participant.
|
750
|
-
*/
|
751
|
-
get type() { return this.state.type; }
|
752
|
-
/**
|
753
|
-
* Internal method used to start or reset the typing indicator timeout (with event emitting).
|
754
|
-
* @internal
|
755
|
-
*/
|
756
|
-
_startTyping(timeout) {
|
757
|
-
clearTimeout(this.state.typingTimeout);
|
758
|
-
this.state.isTyping = true;
|
759
|
-
this.emit('typingStarted', this);
|
760
|
-
this.conversation.emit('typingStarted', this);
|
761
|
-
this.state.typingTimeout = setTimeout(() => this._endTyping(), timeout);
|
762
|
-
return this;
|
763
|
-
}
|
764
|
-
/**
|
765
|
-
* Internal method function used to stop the typing indicator timeout (with event emitting).
|
766
|
-
* @internal
|
767
|
-
*/
|
768
|
-
_endTyping() {
|
769
|
-
if (!this.state.typingTimeout) {
|
770
|
-
return;
|
771
|
-
}
|
772
|
-
this.state.isTyping = false;
|
773
|
-
this.emit('typingEnded', this);
|
774
|
-
this.conversation.emit('typingEnded', this);
|
775
|
-
clearInterval(this.state.typingTimeout);
|
776
|
-
this.state.typingTimeout = null;
|
777
|
-
}
|
778
|
-
/**
|
779
|
-
* Internal method function used update local object's property roleSid with a new value.
|
780
|
-
* @internal
|
781
|
-
*/
|
782
|
-
_update(data) {
|
783
|
-
let updateReasons = [];
|
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)) {
|
786
|
-
this.state.attributes = updateAttributes;
|
787
|
-
updateReasons.push('attributes');
|
788
|
-
}
|
789
|
-
let updatedDateUpdated = parseTime$1(data.dateUpdated);
|
790
|
-
if (data.dateUpdated &&
|
791
|
-
updatedDateUpdated.getTime() !== (this.state.dateUpdated && this.state.dateUpdated.getTime())) {
|
792
|
-
this.state.dateUpdated = updatedDateUpdated;
|
793
|
-
updateReasons.push('dateUpdated');
|
794
|
-
}
|
795
|
-
let updatedDateCreated = parseTime$1(data.dateCreated);
|
796
|
-
if (data.dateCreated &&
|
797
|
-
updatedDateCreated.getTime() !== (this.state.dateCreated && this.state.dateCreated.getTime())) {
|
798
|
-
this.state.dateCreated = updatedDateCreated;
|
799
|
-
updateReasons.push('dateCreated');
|
800
|
-
}
|
801
|
-
if (data.roleSid && this.state.roleSid !== data.roleSid) {
|
802
|
-
this.state.roleSid = data.roleSid;
|
803
|
-
updateReasons.push('roleSid');
|
804
|
-
}
|
805
|
-
if ((Number.isInteger(data.lastConsumedMessageIndex) || data.lastConsumedMessageIndex === null)
|
806
|
-
&& this.state.lastReadMessageIndex !== data.lastConsumedMessageIndex) {
|
807
|
-
this.state.lastReadMessageIndex = data.lastConsumedMessageIndex;
|
808
|
-
updateReasons.push('lastReadMessageIndex');
|
809
|
-
}
|
810
|
-
if (data.lastConsumptionTimestamp) {
|
811
|
-
let lastReadTimestamp = new Date(data.lastConsumptionTimestamp);
|
812
|
-
if (!this.state.lastReadTimestamp ||
|
813
|
-
this.state.lastReadTimestamp.getTime() !== lastReadTimestamp.getTime()) {
|
814
|
-
this.state.lastReadTimestamp = lastReadTimestamp;
|
815
|
-
updateReasons.push('lastReadTimestamp');
|
816
|
-
}
|
817
|
-
}
|
818
|
-
if (updateReasons.length > 0) {
|
819
|
-
this.emit('updated', { participant: this, updateReasons: updateReasons });
|
820
|
-
}
|
821
|
-
return this;
|
822
|
-
}
|
823
|
-
/**
|
824
|
-
* Get the user for this participant and subscribes to it. Supported only for participants of type `chat`.
|
825
|
-
*/
|
826
|
-
async getUser() {
|
827
|
-
if (this.type != 'chat') {
|
828
|
-
throw new Error('Getting User is not supported for this Participant type: ' + this.type);
|
829
|
-
}
|
830
|
-
return this.services.users.getUser(this.state.identity, this.state.userInfo);
|
831
|
-
}
|
832
|
-
/**
|
833
|
-
* Remove the participant from the conversation.
|
834
|
-
*/
|
835
|
-
async remove() {
|
836
|
-
return this.conversation.removeParticipant(this);
|
837
|
-
}
|
838
|
-
/**
|
839
|
-
* Update the attributes of the participant.
|
840
|
-
* @param attributes New attributes.
|
841
|
-
*/
|
842
|
-
async updateAttributes(attributes) {
|
843
|
-
await this.services.commandExecutor.mutateResource('post', this.links.self, {
|
844
|
-
attributes: JSON.stringify(attributes)
|
845
|
-
});
|
846
|
-
return this;
|
847
|
-
}
|
848
|
-
}
|
849
|
-
/**
|
850
|
-
* Fired when the participant has started typing.
|
851
|
-
*
|
852
|
-
* Parameters:
|
853
|
-
* 1. {@link Participant} `participant` - the participant in question
|
854
|
-
* @event
|
855
|
-
*/
|
856
|
-
Participant.typingStarted = 'typingStarted';
|
857
|
-
/**
|
858
|
-
* Fired when the participant has stopped typing.
|
859
|
-
*
|
860
|
-
* Parameters:
|
861
|
-
* 1. {@link Participant} `participant` - the participant in question
|
862
|
-
* @event
|
863
|
-
*/
|
864
|
-
Participant.typingEnded = 'typingEnded';
|
865
|
-
/**
|
866
|
-
* Fired when the fields of the participant have been updated.
|
867
|
-
*
|
868
|
-
* Parameters:
|
869
|
-
* 1. object `data` - info object provided with the event. It has the following properties:
|
870
|
-
* * {@link Participant} participant - the participant in question
|
871
|
-
* * {@link ParticipantUpdateReason}[] updateReasons - array of reasons for the update
|
872
|
-
* @event
|
873
|
-
*/
|
874
|
-
Participant.updated = 'updated';
|
875
|
-
__decorate([
|
876
|
-
declarativeTypeValidator.validateTypesAsync(['string', 'number', 'boolean', 'object', declarativeTypeValidator.literal(null)]),
|
877
|
-
__metadata("design:type", Function),
|
878
|
-
__metadata("design:paramtypes", [Object]),
|
879
|
-
__metadata("design:returntype", Promise)
|
880
|
-
], Participant.prototype, "updateAttributes", null);
|
881
|
-
|
882
|
-
const log$6 = Logger.scope('Participants');
|
883
|
-
/**
|
884
|
-
* @classdesc Represents the collection of participants for the conversation
|
885
|
-
* @fires Participants#participantJoined
|
886
|
-
* @fires Participants#participantLeft
|
887
|
-
* @fires Participants#participantUpdated
|
888
|
-
*/
|
889
|
-
class Participants extends replayEventEmitter.ReplayEventEmitter {
|
890
|
-
constructor(conversation, participants, links, configuration, services) {
|
891
|
-
super();
|
892
|
-
this.conversation = conversation;
|
893
|
-
this.participants = participants;
|
894
|
-
this.links = links;
|
895
|
-
this.configuration = configuration;
|
896
|
-
this.services = services;
|
897
|
-
}
|
898
|
-
async unsubscribe() {
|
899
|
-
if (this.rosterEntityPromise) {
|
900
|
-
let entity = await this.rosterEntityPromise;
|
901
|
-
entity.close();
|
902
|
-
this.rosterEntityPromise = null;
|
903
|
-
}
|
904
|
-
}
|
905
|
-
subscribe(rosterObjectName) {
|
906
|
-
return this.rosterEntityPromise = this.rosterEntityPromise
|
907
|
-
|| this.services.syncClient.map({ id: rosterObjectName, mode: 'open_existing' })
|
908
|
-
.then(rosterMap => {
|
909
|
-
rosterMap.on('itemAdded', args => {
|
910
|
-
log$6.debug(this.conversation.sid + ' itemAdded: ' + args.item.key);
|
911
|
-
this.upsertParticipant(args.item.key, args.item.data)
|
912
|
-
.then(participant => {
|
913
|
-
this.emit('participantJoined', participant);
|
914
|
-
});
|
915
|
-
});
|
916
|
-
rosterMap.on('itemRemoved', args => {
|
917
|
-
log$6.debug(this.conversation.sid + ' itemRemoved: ' + args.key);
|
918
|
-
let participantSid = args.key;
|
919
|
-
if (!this.participants.has(participantSid)) {
|
920
|
-
return;
|
921
|
-
}
|
922
|
-
let leftParticipant = this.participants.get(participantSid);
|
923
|
-
this.participants.delete(participantSid);
|
924
|
-
this.emit('participantLeft', leftParticipant);
|
925
|
-
});
|
926
|
-
rosterMap.on('itemUpdated', args => {
|
927
|
-
log$6.debug(this.conversation.sid + ' itemUpdated: ' + args.item.key);
|
928
|
-
this.upsertParticipant(args.item.key, args.item.data);
|
929
|
-
});
|
930
|
-
let participantsPromises = [];
|
931
|
-
let that = this;
|
932
|
-
const rosterMapHandler = function (paginator) {
|
933
|
-
paginator.items.forEach(item => { participantsPromises.push(that.upsertParticipant(item.key, item.data)); });
|
934
|
-
return paginator.hasNextPage ? paginator.nextPage().then(rosterMapHandler) : null;
|
935
|
-
};
|
936
|
-
return rosterMap
|
937
|
-
.getItems()
|
938
|
-
.then(rosterMapHandler)
|
939
|
-
.then(() => Promise.all(participantsPromises))
|
940
|
-
.then(() => rosterMap);
|
941
|
-
})
|
942
|
-
.catch(err => {
|
943
|
-
this.rosterEntityPromise = null;
|
944
|
-
if (this.services.syncClient.connectionState != 'disconnected') {
|
945
|
-
log$6.error('Failed to get roster object for conversation', this.conversation.sid, err);
|
946
|
-
}
|
947
|
-
log$6.debug('ERROR: Failed to get roster object for conversation', this.conversation.sid, err);
|
948
|
-
throw err;
|
949
|
-
});
|
950
|
-
}
|
951
|
-
async upsertParticipant(participantSid, data) {
|
952
|
-
let participant = this.participants.get(participantSid);
|
953
|
-
if (participant) {
|
954
|
-
return participant._update(data);
|
955
|
-
}
|
956
|
-
const links = {
|
957
|
-
self: `${this.links.participants}/${participantSid}`
|
958
|
-
};
|
959
|
-
participant = new Participant(data, participantSid, this.conversation, links, this.services);
|
960
|
-
this.participants.set(participantSid, participant);
|
961
|
-
participant.on('updated', (args) => this.emit('participantUpdated', args));
|
962
|
-
return participant;
|
963
|
-
}
|
964
|
-
/**
|
965
|
-
* @returns {Promise<Array<Participant>>} returns list of participants {@see Participant}
|
966
|
-
*/
|
967
|
-
getParticipants() {
|
968
|
-
return this.rosterEntityPromise.then(() => {
|
969
|
-
let participants = [];
|
970
|
-
this.participants.forEach(participant => participants.push(participant));
|
971
|
-
return participants;
|
972
|
-
});
|
973
|
-
}
|
974
|
-
/**
|
975
|
-
* Get participant by SID from conversation
|
976
|
-
* @returns {Promise<Participant>}
|
977
|
-
*/
|
978
|
-
async getParticipantBySid(participantSid) {
|
979
|
-
return this.rosterEntityPromise.then(() => {
|
980
|
-
let participant = this.participants.get(participantSid);
|
981
|
-
if (!participant) {
|
982
|
-
throw new Error('Participant with SID ' + participantSid + ' was not found');
|
983
|
-
}
|
984
|
-
return participant;
|
985
|
-
});
|
986
|
-
}
|
987
|
-
/**
|
988
|
-
* Get participant by identity from conversation
|
989
|
-
* @returns {Promise<Participant>}
|
990
|
-
*/
|
991
|
-
async getParticipantByIdentity(identity) {
|
992
|
-
let foundParticipant = null;
|
993
|
-
return this.rosterEntityPromise.then(() => {
|
994
|
-
this.participants.forEach(participant => {
|
995
|
-
if (participant.identity === identity) {
|
996
|
-
foundParticipant = participant;
|
997
|
-
}
|
998
|
-
});
|
999
|
-
if (!foundParticipant) {
|
1000
|
-
throw new Error('Participant with identity ' + identity + ' was not found');
|
1001
|
-
}
|
1002
|
-
return foundParticipant;
|
1003
|
-
});
|
1004
|
-
}
|
1005
|
-
/**
|
1006
|
-
* Add a chat participant to the conversation
|
1007
|
-
* @returns {Promise<any>}
|
1008
|
-
*/
|
1009
|
-
async add(identity, attributes) {
|
1010
|
-
return await this.services.commandExecutor.mutateResource('post', this.links.participants, {
|
1011
|
-
identity,
|
1012
|
-
attributes: typeof attributes !== 'undefined' ? JSON.stringify(attributes) : undefined
|
1013
|
-
});
|
1014
|
-
}
|
1015
|
-
/**
|
1016
|
-
* Add a non-chat participant to the conversation.
|
1017
|
-
*
|
1018
|
-
* @param proxyAddress
|
1019
|
-
* @param address
|
1020
|
-
* @param attributes
|
1021
|
-
* @returns {Promise<any>}
|
1022
|
-
*/
|
1023
|
-
addNonChatParticipant(proxyAddress, address, attributes) {
|
1024
|
-
return this.services.commandExecutor.mutateResource('post', this.links.participants, {
|
1025
|
-
attributes: typeof attributes !== 'undefined' ? JSON.stringify(attributes) : undefined,
|
1026
|
-
messaging_binding: {
|
1027
|
-
address,
|
1028
|
-
proxy_address: proxyAddress
|
1029
|
-
}
|
1030
|
-
});
|
1031
|
-
}
|
1032
|
-
/**
|
1033
|
-
* Remove the participant with a given identity from a conversation.
|
1034
|
-
*/
|
1035
|
-
remove(identity) {
|
1036
|
-
return this.services.commandExecutor.mutateResource('delete', `${this.links.participants}/${identity}`);
|
1037
|
-
}
|
1038
|
-
}
|
1039
|
-
/**
|
1040
|
-
* Fired when participant joined conversation
|
1041
|
-
* @event Participants#participantJoined
|
1042
|
-
* @type {Participant}
|
1043
|
-
*/
|
1044
|
-
/**
|
1045
|
-
* Fired when participant left conversation
|
1046
|
-
* @event Participants#participantLeft
|
1047
|
-
* @type {Participant}
|
1048
|
-
*/
|
1049
|
-
/**
|
1050
|
-
* Fired when participant updated
|
1051
|
-
* @event Participants#participantUpdated
|
1052
|
-
* @type {Object}
|
1053
|
-
* @property {Participant} participant - Updated Participant
|
1054
|
-
* @property {Participant#UpdateReason[]} updateReasons - Array of Participant's updated event reasons
|
1055
|
-
*/
|
1056
|
-
|
1057
|
-
/**
|
1058
|
-
* Represents a media information for a message in a conversation.
|
1059
|
-
*/
|
1060
|
-
class Media {
|
1061
|
-
/**
|
1062
|
-
* @internal
|
1063
|
-
*/
|
1064
|
-
constructor(data, services) {
|
1065
|
-
this.mcsMedia = null;
|
1066
|
-
this.services = services;
|
1067
|
-
if (data instanceof mcsClient.McsMedia) {
|
1068
|
-
this.mcsMedia = data;
|
1069
|
-
}
|
1070
|
-
this.state = {
|
1071
|
-
sid: data.sid,
|
1072
|
-
category: data.category,
|
1073
|
-
filename: data.filename,
|
1074
|
-
contentType: data.contentType,
|
1075
|
-
size: data.size
|
1076
|
-
};
|
1077
|
-
}
|
1078
|
-
/**
|
1079
|
-
* Server-assigned unique identifier for the media.
|
1080
|
-
*/
|
1081
|
-
get sid() { return this.state.sid; }
|
1082
|
-
/**
|
1083
|
-
* File name. Null if absent.
|
1084
|
-
*/
|
1085
|
-
get filename() { return this.state.filename; }
|
1086
|
-
/**
|
1087
|
-
* Content type of the media.
|
1088
|
-
*/
|
1089
|
-
get contentType() { return this.state.contentType; }
|
1090
|
-
/**
|
1091
|
-
* Size of the media in bytes.
|
1092
|
-
*/
|
1093
|
-
get size() { return this.state.size; }
|
1094
|
-
/**
|
1095
|
-
* Media category, can be one of the {@link MediaCategory} values.
|
1096
|
-
*/
|
1097
|
-
get category() { return this.state.category; }
|
1098
|
-
/**
|
1099
|
-
* Returns the direct content URL for the media.
|
1100
|
-
*
|
1101
|
-
* This URL is impermanent, it will expire in several minutes and cannot be cached.
|
1102
|
-
* If the URL becomes expired, you need to request a new one.
|
1103
|
-
* Each call to this function produces a new temporary URL.
|
1104
|
-
*/
|
1105
|
-
async getContentTemporaryUrl() {
|
1106
|
-
await this._fetchMcsMedia();
|
1107
|
-
return this.mcsMedia.getContentUrl();
|
1108
|
-
}
|
1109
|
-
/**
|
1110
|
-
* Returns cached direct content URL for the media.
|
1111
|
-
*
|
1112
|
-
* This URL will expire in several minutes. This function does not refresh the URL and can be used to query it several times
|
1113
|
-
* without causing network traffic.
|
1114
|
-
* If the URL becomes expired, you need to request a new one using getContentTemporaryUrl().
|
1115
|
-
*
|
1116
|
-
* @returns {Promise<String>}
|
1117
|
-
*/
|
1118
|
-
async getCachedTemporaryUrl() {
|
1119
|
-
await this._fetchMcsMedia();
|
1120
|
-
return this.mcsMedia.getCachedContentUrl();
|
1121
|
-
}
|
1122
|
-
async _fetchMcsMedia() {
|
1123
|
-
if (!this.mcsMedia) {
|
1124
|
-
if (this.services.mcsClient) {
|
1125
|
-
this.mcsMedia = await this.services.mcsClient.get(this.state.sid);
|
1126
|
-
}
|
1127
|
-
else {
|
1128
|
-
throw new Error('Media Content Service is unavailable');
|
1129
|
-
}
|
1130
|
-
}
|
1131
|
-
}
|
1132
|
-
}
|
1133
|
-
|
1134
|
-
/**
|
1135
|
-
* Contains aggregated information about delivery statuses of a message across all participants
|
1136
|
-
* of a conversation.
|
1137
|
-
*
|
1138
|
-
* At any moment during the message delivery to a participant, the message can have zero or more of following
|
1139
|
-
* delivery statuses:
|
1140
|
-
* * Message is considered as **sent** to a participant if the nearest upstream carrier accepted the message.
|
1141
|
-
* * Message is considered as **delivered** to a participant if Twilio has received confirmation of message
|
1142
|
-
* delivery from the upstream carrier, and, where available, the destination handset.
|
1143
|
-
* * Message considered as **undelivered** to a participant if Twilio has received a delivery receipt
|
1144
|
-
* indicating that the message was not delivered. This can happen for many reasons including carrier content
|
1145
|
-
* filtering and the availability of the destination handset.
|
1146
|
-
* * Message considered as **read** by a participant if the message has been delivered and opened by the
|
1147
|
-
* recipient in a conversation. The recipient must have enabled the read receipts.
|
1148
|
-
* * Message considered as **failed** to be delivered to a participant if the message could not be sent.
|
1149
|
-
* This can happen for various reasons including queue overflows, account suspensions and media
|
1150
|
-
* errors (in the case of MMS for instance).
|
1151
|
-
*
|
1152
|
-
* {@link AggregatedDeliveryReceipt} class contains an aggregated value {@link DeliveryAmount} for each delivery status.
|
1153
|
-
*/
|
1154
|
-
class AggregatedDeliveryReceipt {
|
1155
|
-
/**
|
1156
|
-
* @internal
|
1157
|
-
*/
|
1158
|
-
constructor(data) {
|
1159
|
-
this.state = data;
|
1160
|
-
}
|
1161
|
-
/**
|
1162
|
-
* Maximum number of delivery events expected for the message.
|
1163
|
-
*/
|
1164
|
-
get total() {
|
1165
|
-
return this.state.total;
|
1166
|
-
}
|
1167
|
-
/**
|
1168
|
-
* Message is considered as **sent** to a participant if the nearest upstream carrier accepted the message.
|
1169
|
-
*
|
1170
|
-
* @return Amount of participants that have the **sent** delivery status for the message.
|
1171
|
-
*/
|
1172
|
-
get sent() {
|
1173
|
-
return this.state.sent;
|
1174
|
-
}
|
1175
|
-
/**
|
1176
|
-
* Message is considered as **delivered** to a participant if Twilio has received confirmation of message
|
1177
|
-
* delivery from the upstream carrier, and, where available, the destination handset.
|
1178
|
-
*
|
1179
|
-
* @return Amount of participants that have the **delivered** delivery status for the message.
|
1180
|
-
*/
|
1181
|
-
get delivered() {
|
1182
|
-
return this.state.delivered;
|
1183
|
-
}
|
1184
|
-
/**
|
1185
|
-
* Message is considered as **read** by a participant, if the message has been delivered and opened by the
|
1186
|
-
* recipient in a conversation. The recipient must have enabled the read receipts.
|
1187
|
-
*
|
1188
|
-
* @return Amount of participants that have the **read** delivery status for the message.
|
1189
|
-
*/
|
1190
|
-
get read() {
|
1191
|
-
return this.state.read;
|
1192
|
-
}
|
1193
|
-
/**
|
1194
|
-
* Message is considered as **undelivered** to a participant if Twilio has received a delivery receipt
|
1195
|
-
* indicating that the message was not delivered. This can happen for many reasons including carrier content
|
1196
|
-
* filtering and the availability of the destination handset.
|
1197
|
-
*
|
1198
|
-
* @return Ammount of participants that have the **undelivered** delivery status for the message.
|
1199
|
-
*/
|
1200
|
-
get undelivered() {
|
1201
|
-
return this.state.undelivered;
|
1202
|
-
}
|
1203
|
-
/**
|
1204
|
-
* Message is considered as **failed** to be delivered to a participant if the message could not be sent.
|
1205
|
-
* This can happen for various reasons including queue overflows, account suspensions and media
|
1206
|
-
* errors (in the case of MMS for instance). Twilio does not charge you for failed messages.
|
1207
|
-
*
|
1208
|
-
* @return Amount of participants that have the **failed** delivery status for the message.
|
1209
|
-
*/
|
1210
|
-
get failed() {
|
1211
|
-
return this.state.failed;
|
1212
|
-
}
|
1213
|
-
_update(data) {
|
1214
|
-
this.state = data;
|
1215
|
-
}
|
1216
|
-
_isEquals(data) {
|
1217
|
-
const isTotalSame = this.total === data.total;
|
1218
|
-
const isSentSame = this.sent === data.sent;
|
1219
|
-
const isDeliveredSame = this.delivered === data.delivered;
|
1220
|
-
const isReadSame = this.read === data.read;
|
1221
|
-
const isUndeliveredSame = this.undelivered === data.undelivered;
|
1222
|
-
const isFailedSame = this.failed === data.failed;
|
1223
|
-
return isTotalSame && isSentSame && isDeliveredSame && isReadSame && isUndeliveredSame && isFailedSame;
|
1224
|
-
}
|
1225
|
-
}
|
1226
|
-
|
1227
|
-
/**
|
1228
|
-
* Pagination helper class.
|
1229
|
-
*/
|
1230
|
-
class RestPaginator {
|
1231
|
-
/**
|
1232
|
-
* @internal
|
1233
|
-
*/
|
1234
|
-
constructor(items, source, prevToken, nextToken) {
|
1235
|
-
this.state = {
|
1236
|
-
prevToken,
|
1237
|
-
nextToken,
|
1238
|
-
source,
|
1239
|
-
items
|
1240
|
-
};
|
1241
|
-
}
|
1242
|
-
/**
|
1243
|
-
* Indicates the existence of the next page.
|
1244
|
-
*/
|
1245
|
-
get hasNextPage() { return !!this.state.nextToken; }
|
1246
|
-
/**
|
1247
|
-
* Indicates the existence of the previous page
|
1248
|
-
*/
|
1249
|
-
get hasPrevPage() { return !!this.state.prevToken; }
|
1250
|
-
/**
|
1251
|
-
* Array of elements on the current page.
|
1252
|
-
*/
|
1253
|
-
get items() { return this.state.items; }
|
1254
|
-
/**
|
1255
|
-
* Request the next page. Does not modify the existing object.
|
1256
|
-
*/
|
1257
|
-
nextPage() {
|
1258
|
-
return this.hasNextPage ? this.state.source(this.state.nextToken) : Promise.reject(new Error('No next page'));
|
1259
|
-
}
|
1260
|
-
/**
|
1261
|
-
* Request the previous page. Does not modify the existing object.
|
1262
|
-
*/
|
1263
|
-
prevPage() {
|
1264
|
-
return this.hasPrevPage ? this.state.source(this.state.prevToken) : Promise.reject(new Error('No previous page'));
|
1265
|
-
}
|
1266
|
-
}
|
1267
|
-
|
1268
|
-
/**
|
1269
|
-
* Represents a delivery receipt of a message.
|
1270
|
-
*/
|
1271
|
-
class DetailedDeliveryReceipt {
|
1272
|
-
/**
|
1273
|
-
* @internal
|
1274
|
-
*/
|
1275
|
-
constructor(descriptor) {
|
1276
|
-
this.sid = descriptor.sid;
|
1277
|
-
this.messageSid = descriptor.message_sid;
|
1278
|
-
this.conversationSid = descriptor.conversation_sid;
|
1279
|
-
this.channelMessageSid = descriptor.channel_message_sid;
|
1280
|
-
this.participantSid = descriptor.participant_sid;
|
1281
|
-
this.status = descriptor.status || 'queued';
|
1282
|
-
this.errorCode = descriptor.error_code || 0;
|
1283
|
-
this.dateCreated = descriptor.date_created;
|
1284
|
-
this.dateUpdated = descriptor.date_updated;
|
1285
|
-
}
|
1286
|
-
}
|
1287
|
-
|
1288
|
-
const log$5 = Logger.scope('Message');
|
1289
|
-
/**
|
1290
|
-
* A message in a conversation.
|
1291
|
-
*/
|
1292
|
-
class Message extends replayEventEmitter.ReplayEventEmitter {
|
1293
|
-
/**
|
1294
|
-
* @internal
|
1295
|
-
*/
|
1296
|
-
constructor(index, data, conversation, links, configuration, services) {
|
1297
|
-
var _a, _b, _c, _d, _e;
|
1298
|
-
super();
|
1299
|
-
this.conversation = conversation;
|
1300
|
-
this.links = links;
|
1301
|
-
this.configuration = configuration;
|
1302
|
-
this.services = services;
|
1303
|
-
this.state = {
|
1304
|
-
sid: data.sid,
|
1305
|
-
index: index,
|
1306
|
-
author: (_a = data.author) !== null && _a !== void 0 ? _a : null,
|
1307
|
-
subject: (_b = data.subject) !== null && _b !== void 0 ? _b : null,
|
1308
|
-
body: data.text,
|
1309
|
-
timestamp: data.timestamp ? new Date(data.timestamp) : null,
|
1310
|
-
dateUpdated: data.dateUpdated ? new Date(data.dateUpdated) : null,
|
1311
|
-
lastUpdatedBy: (_c = data.lastUpdatedBy) !== null && _c !== void 0 ? _c : null,
|
1312
|
-
attributes: parseAttributes(data.attributes, `Got malformed attributes for the message ${data.sid}`, log$5),
|
1313
|
-
type: (_d = data.type) !== null && _d !== void 0 ? _d : 'text',
|
1314
|
-
media: (data.type && data.type === 'media' && data.media)
|
1315
|
-
? new Media(data.media, this.services) : null,
|
1316
|
-
medias: (data.type && data.type === 'media' && data.medias)
|
1317
|
-
? data.medias.map((m) => new Media(m, this.services)) : null,
|
1318
|
-
participantSid: (_e = data.memberSid) !== null && _e !== void 0 ? _e : null,
|
1319
|
-
aggregatedDeliveryReceipt: data.delivery ? new AggregatedDeliveryReceipt(data.delivery) : null
|
1320
|
-
};
|
1321
|
-
}
|
1322
|
-
/**
|
1323
|
-
* The server-assigned unique identifier for the message.
|
1324
|
-
*/
|
1325
|
-
get sid() { return this.state.sid; }
|
1326
|
-
/**
|
1327
|
-
* Name of the user that sent the message.
|
1328
|
-
*/
|
1329
|
-
get author() { return this.state.author; }
|
1330
|
-
/**
|
1331
|
-
* Message subject. Used only in email conversations.
|
1332
|
-
*/
|
1333
|
-
get subject() { return this.state.subject; }
|
1334
|
-
/**
|
1335
|
-
* Body of the message.
|
1336
|
-
*/
|
1337
|
-
get body() { return this.state.body; }
|
1338
|
-
/**
|
1339
|
-
* Date this message was last updated on.
|
1340
|
-
*/
|
1341
|
-
get dateUpdated() { return this.state.dateUpdated; }
|
1342
|
-
/**
|
1343
|
-
* Index of the message in the conversation's messages list.
|
1344
|
-
* By design of the Conversations system, the message indices may have arbitrary gaps between them,
|
1345
|
-
* that does not necessarily mean they were deleted or otherwise modified - just that
|
1346
|
-
* messages may have some non-contiguous indices even if they are being sent immediately one after another.
|
1347
|
-
*
|
1348
|
-
* Trying to use indices for some calculations is going to be unreliable.
|
1349
|
-
*
|
1350
|
-
* To calculate the number of unread messages it is better to use the read horizon API.
|
1351
|
-
* See {@link Conversation.getUnreadMessagesCount} for details.
|
1352
|
-
*/
|
1353
|
-
get index() { return this.state.index; }
|
1354
|
-
/**
|
1355
|
-
* Identity of the last user that updated the message.
|
1356
|
-
*/
|
1357
|
-
get lastUpdatedBy() { return this.state.lastUpdatedBy; }
|
1358
|
-
/**
|
1359
|
-
* Date this message was created on.
|
1360
|
-
*/
|
1361
|
-
get dateCreated() { return this.state.timestamp; }
|
1362
|
-
/**
|
1363
|
-
* Custom attributes of the message.
|
1364
|
-
*/
|
1365
|
-
get attributes() { return this.state.attributes; }
|
1366
|
-
/**
|
1367
|
-
* Push notification type of the message.
|
1368
|
-
*/
|
1369
|
-
get type() { return this.state.type; }
|
1370
|
-
/**
|
1371
|
-
* One of the attached media.
|
1372
|
-
* @deprecated Use attachedMedia instead. Note that the latter is now an array.
|
1373
|
-
*/
|
1374
|
-
get media() { return this.state.media; }
|
1375
|
-
/**
|
1376
|
-
* Return all media attachments, except email body/history attachments, without temporary urls.
|
1377
|
-
*/
|
1378
|
-
get attachedMedia() { return this.getMediaByCategory(['media']); }
|
1379
|
-
/**
|
1380
|
-
* The server-assigned unique identifier of the authoring participant.
|
1381
|
-
*/
|
1382
|
-
get participantSid() { return this.state.participantSid; }
|
1383
|
-
/**
|
1384
|
-
* Aggregated information about the message delivery statuses across all participants of a conversation..
|
1385
|
-
*/
|
1386
|
-
get aggregatedDeliveryReceipt() {
|
1387
|
-
return this.state.aggregatedDeliveryReceipt;
|
1388
|
-
}
|
1389
|
-
/**
|
1390
|
-
* Return a (possibly empty) array of media matching a specific set of categories.
|
1391
|
-
* Allowed category is so far only 'media'.
|
1392
|
-
* @param categories Array of categories to match.
|
1393
|
-
* @returns Array of media descriptors matching given categories.
|
1394
|
-
*/
|
1395
|
-
getMediaByCategory(categories) {
|
1396
|
-
var _a;
|
1397
|
-
return (_a = this.state.medias) === null || _a === void 0 ? void 0 : _a.filter((m) => categories.includes(m.category));
|
1398
|
-
}
|
1399
|
-
_update(data) {
|
1400
|
-
let updateReasons = [];
|
1401
|
-
if ((data.text || ((typeof data.text) === 'string')) && data.text !== this.state.body) {
|
1402
|
-
this.state.body = data.text;
|
1403
|
-
updateReasons.push('body');
|
1404
|
-
}
|
1405
|
-
if (data.subject && data.subject !== this.state.subject) {
|
1406
|
-
this.state.subject = data.subject;
|
1407
|
-
updateReasons.push('subject');
|
1408
|
-
}
|
1409
|
-
if (data.lastUpdatedBy && data.lastUpdatedBy !== this.state.lastUpdatedBy) {
|
1410
|
-
this.state.lastUpdatedBy = data.lastUpdatedBy;
|
1411
|
-
updateReasons.push('lastUpdatedBy');
|
1412
|
-
}
|
1413
|
-
if (data.author && data.author !== this.state.author) {
|
1414
|
-
this.state.author = data.author;
|
1415
|
-
updateReasons.push('author');
|
1416
|
-
}
|
1417
|
-
if (data.dateUpdated &&
|
1418
|
-
new Date(data.dateUpdated).getTime() !== (this.state.dateUpdated && this.state.dateUpdated.getTime())) {
|
1419
|
-
this.state.dateUpdated = new Date(data.dateUpdated);
|
1420
|
-
updateReasons.push('dateUpdated');
|
1421
|
-
}
|
1422
|
-
if (data.timestamp &&
|
1423
|
-
new Date(data.timestamp).getTime() !== (this.state.timestamp && this.state.timestamp.getTime())) {
|
1424
|
-
this.state.timestamp = new Date(data.timestamp);
|
1425
|
-
updateReasons.push('dateCreated');
|
1426
|
-
}
|
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)) {
|
1429
|
-
this.state.attributes = updatedAttributes;
|
1430
|
-
updateReasons.push('attributes');
|
1431
|
-
}
|
1432
|
-
let updatedAggregatedDelivery = data.delivery;
|
1433
|
-
let currentAggregatedDelivery = this.state.aggregatedDeliveryReceipt;
|
1434
|
-
let isUpdatedAggregateDeliveryValid = !!updatedAggregatedDelivery && !!updatedAggregatedDelivery.total &&
|
1435
|
-
!!updatedAggregatedDelivery.delivered && !!updatedAggregatedDelivery.failed && !!updatedAggregatedDelivery.read &&
|
1436
|
-
!!updatedAggregatedDelivery.sent && !!updatedAggregatedDelivery.undelivered;
|
1437
|
-
if (isUpdatedAggregateDeliveryValid) {
|
1438
|
-
if (!currentAggregatedDelivery) {
|
1439
|
-
this.state.aggregatedDeliveryReceipt = new AggregatedDeliveryReceipt(updatedAggregatedDelivery);
|
1440
|
-
updateReasons.push('deliveryReceipt');
|
1441
|
-
}
|
1442
|
-
else if (!currentAggregatedDelivery._isEquals(updatedAggregatedDelivery)) {
|
1443
|
-
currentAggregatedDelivery._update(updatedAggregatedDelivery);
|
1444
|
-
updateReasons.push('deliveryReceipt');
|
1445
|
-
}
|
1446
|
-
}
|
1447
|
-
if (updateReasons.length > 0) {
|
1448
|
-
this.emit('updated', { message: this, updateReasons: updateReasons });
|
1449
|
-
}
|
1450
|
-
}
|
1451
|
-
/**
|
1452
|
-
* Get the participant who is the author of the message.
|
1453
|
-
*/
|
1454
|
-
async getParticipant() {
|
1455
|
-
let participant = null;
|
1456
|
-
if (this.state.participantSid) {
|
1457
|
-
participant = await this.conversation.getParticipantBySid(this.participantSid)
|
1458
|
-
.catch(() => {
|
1459
|
-
log$5.debug(`Participant with sid "${this.participantSid}" not found for message ${this.sid}`);
|
1460
|
-
return null;
|
1461
|
-
});
|
1462
|
-
}
|
1463
|
-
if (!participant && this.state.author) {
|
1464
|
-
participant = await this.conversation.getParticipantByIdentity(this.state.author)
|
1465
|
-
.catch(() => {
|
1466
|
-
log$5.debug(`Participant with identity "${this.author}" not found for message ${this.sid}`);
|
1467
|
-
return null;
|
1468
|
-
});
|
1469
|
-
}
|
1470
|
-
if (participant) {
|
1471
|
-
return participant;
|
1472
|
-
}
|
1473
|
-
let errorMesage = 'Participant with ';
|
1474
|
-
if (this.state.participantSid) {
|
1475
|
-
errorMesage += 'SID \'' + this.state.participantSid + '\' ';
|
1476
|
-
}
|
1477
|
-
if (this.state.author) {
|
1478
|
-
if (this.state.participantSid) {
|
1479
|
-
errorMesage += 'or ';
|
1480
|
-
}
|
1481
|
-
errorMesage += 'identity \'' + this.state.author + '\' ';
|
1482
|
-
}
|
1483
|
-
if (errorMesage === 'Participant with ') {
|
1484
|
-
errorMesage = 'Participant ';
|
1485
|
-
}
|
1486
|
-
errorMesage += 'was not found';
|
1487
|
-
throw new Error(errorMesage);
|
1488
|
-
}
|
1489
|
-
/**
|
1490
|
-
* Get the delivery receipts of the message.
|
1491
|
-
*/
|
1492
|
-
async getDetailedDeliveryReceipts() {
|
1493
|
-
let paginator = await this._getDetailedDeliveryReceiptsPaginator();
|
1494
|
-
let detailedDeliveryReceipts = [];
|
1495
|
-
while (true) {
|
1496
|
-
detailedDeliveryReceipts = [...detailedDeliveryReceipts, ...paginator.items];
|
1497
|
-
if (!paginator.hasNextPage) {
|
1498
|
-
break;
|
1499
|
-
}
|
1500
|
-
paginator = await paginator.nextPage();
|
1501
|
-
}
|
1502
|
-
return detailedDeliveryReceipts;
|
1503
|
-
}
|
1504
|
-
/**
|
1505
|
-
* Remove the message.
|
1506
|
-
*/
|
1507
|
-
async remove() {
|
1508
|
-
await this.services.commandExecutor.mutateResource('delete', this.links.self);
|
1509
|
-
return this;
|
1510
|
-
}
|
1511
|
-
/**
|
1512
|
-
* Edit the message body.
|
1513
|
-
* @param body New body of the message.
|
1514
|
-
*/
|
1515
|
-
async updateBody(body) {
|
1516
|
-
await this.services.commandExecutor.mutateResource('post', this.links.self, {
|
1517
|
-
body
|
1518
|
-
});
|
1519
|
-
return this;
|
1520
|
-
}
|
1521
|
-
/**
|
1522
|
-
* Edit the message attributes.
|
1523
|
-
* @param attributes New attributes.
|
1524
|
-
*/
|
1525
|
-
async updateAttributes(attributes) {
|
1526
|
-
await this.services.commandExecutor.mutateResource('post', this.links.self, {
|
1527
|
-
attributes: typeof attributes !== 'undefined' ? JSON.stringify(attributes) : undefined
|
1528
|
-
});
|
1529
|
-
return this;
|
1530
|
-
}
|
1531
|
-
/**
|
1532
|
-
* Get content URLs for all media attachments in the given set using single operation.
|
1533
|
-
* @param contentSet Set of media attachments to query for content URL.
|
1534
|
-
*/
|
1535
|
-
async attachTemporaryUrlsFor(contentSet) {
|
1536
|
-
// We ignore existing mcsMedia members of each of the media entries.
|
1537
|
-
// Instead we just collect their sids and pull new descriptors from a mediaSet GET endpoint.
|
1538
|
-
const sids = contentSet.map((m) => m.sid);
|
1539
|
-
if (this.services.mcsClient) {
|
1540
|
-
return (await this.services.mcsClient.mediaSetGet(sids)).map((item) => { return new Media(item, this.services); });
|
1541
|
-
}
|
1542
|
-
else {
|
1543
|
-
throw new Error('Media Content Service is unavailable');
|
1544
|
-
}
|
1545
|
-
}
|
1546
|
-
async _getDetailedDeliveryReceiptsPaginator(options) {
|
1547
|
-
const messagesReceiptsUrl = this.configuration.links.messagesReceipts
|
1548
|
-
.replace('%s', this.conversation.sid)
|
1549
|
-
.replace('%s', this.sid);
|
1550
|
-
const url = new UriBuilder(messagesReceiptsUrl)
|
1551
|
-
.arg('PageToken', options === null || options === void 0 ? void 0 : options.pageToken)
|
1552
|
-
.arg('PageSize', options === null || options === void 0 ? void 0 : options.pageSize)
|
1553
|
-
.build();
|
1554
|
-
const response = await this.services.network.get(url);
|
1555
|
-
return new RestPaginator(response.body.delivery_receipts.map((x) => new DetailedDeliveryReceipt(x)), (pageToken, pageSize) => this._getDetailedDeliveryReceiptsPaginator({ pageToken, pageSize }), response.body.meta.previous_token, response.body.meta.next_token);
|
1556
|
-
}
|
1557
|
-
}
|
1558
|
-
/**
|
1559
|
-
* Fired when the properties or the body of the message has been updated.
|
1560
|
-
*
|
1561
|
-
* Parameters:
|
1562
|
-
* 1. object `data` - info object provided with the event. It has the following properties:
|
1563
|
-
* * {@link Message} message - the message in question
|
1564
|
-
* * {@link MessageUpdateReason}[] updateReasons - array of reasons for the update
|
1565
|
-
*/
|
1566
|
-
Message.updated = 'updated';
|
1567
|
-
__decorate([
|
1568
|
-
declarativeTypeValidator.validateTypesAsync('string'),
|
1569
|
-
__metadata("design:type", Function),
|
1570
|
-
__metadata("design:paramtypes", [String]),
|
1571
|
-
__metadata("design:returntype", Promise)
|
1572
|
-
], Message.prototype, "updateBody", null);
|
1573
|
-
__decorate([
|
1574
|
-
declarativeTypeValidator.validateTypesAsync(['string', 'number', 'boolean', 'object', declarativeTypeValidator.literal(null)]),
|
1575
|
-
__metadata("design:type", Function),
|
1576
|
-
__metadata("design:paramtypes", [Object]),
|
1577
|
-
__metadata("design:returntype", Promise)
|
1578
|
-
], Message.prototype, "updateAttributes", null);
|
1579
|
-
__decorate([
|
1580
|
-
declarativeTypeValidator.validateTypesAsync(declarativeTypeValidator.custom(value => [
|
1581
|
-
value instanceof Array && value.length > 0 && value.reduce((a, c) => a && c instanceof Media),
|
1582
|
-
'a non-empty array of Media'
|
1583
|
-
])),
|
1584
|
-
__metadata("design:type", Function),
|
1585
|
-
__metadata("design:paramtypes", [Array]),
|
1586
|
-
__metadata("design:returntype", Promise)
|
1587
|
-
], Message.prototype, "attachTemporaryUrlsFor", null);
|
1588
|
-
|
1589
|
-
const log$4 = Logger.scope('Messages');
|
1590
|
-
/**
|
1591
|
-
* Represents the collection of messages in a conversation
|
1592
|
-
*/
|
1593
|
-
class Messages extends replayEventEmitter.ReplayEventEmitter {
|
1594
|
-
constructor(conversation, configuration, services) {
|
1595
|
-
super();
|
1596
|
-
this.conversation = conversation;
|
1597
|
-
this.configuration = configuration;
|
1598
|
-
this.services = services;
|
1599
|
-
this.messagesByIndex = new Map();
|
1600
|
-
this.messagesListPromise = null;
|
1601
|
-
}
|
1602
|
-
/**
|
1603
|
-
* Subscribe to the Messages Event Stream
|
1604
|
-
* @param name - The name of Sync object for the Messages resource.
|
1605
|
-
*/
|
1606
|
-
async subscribe(name) {
|
1607
|
-
if (this.messagesListPromise) {
|
1608
|
-
return this.messagesListPromise;
|
1609
|
-
}
|
1610
|
-
this.messagesListPromise = this.services.syncClient.list({
|
1611
|
-
id: name,
|
1612
|
-
mode: 'open_existing',
|
1613
|
-
});
|
1614
|
-
try {
|
1615
|
-
const list = await this.messagesListPromise;
|
1616
|
-
list.on('itemAdded', (args) => {
|
1617
|
-
log$4.debug(`${this.conversation.sid} itemAdded: ${args.item.index}`);
|
1618
|
-
const links = {
|
1619
|
-
self: `${this.conversation.links.messages}/${args.item.data.sid}`,
|
1620
|
-
conversation: this.conversation.links.self,
|
1621
|
-
messages_receipts: `${this.conversation.links.messages}/${args.item.data.sid}/Receipts`,
|
1622
|
-
};
|
1623
|
-
const message = new Message(args.item.index, args.item.data, this.conversation, links, this.configuration, this.services);
|
1624
|
-
if (this.messagesByIndex.has(message.index)) {
|
1625
|
-
log$4.debug('Message arrived, but is already known and ignored', this.conversation.sid, message.index);
|
1626
|
-
return;
|
1627
|
-
}
|
1628
|
-
this.messagesByIndex.set(message.index, message);
|
1629
|
-
message.on('updated', (args) => this.emit('messageUpdated', args));
|
1630
|
-
this.emit('messageAdded', message);
|
1631
|
-
});
|
1632
|
-
list.on('itemRemoved', (args) => {
|
1633
|
-
log$4.debug(`#{this.conversation.sid} itemRemoved: ${args.index}`);
|
1634
|
-
const index = args.index;
|
1635
|
-
if (this.messagesByIndex.has(index)) {
|
1636
|
-
let message = this.messagesByIndex.get(index);
|
1637
|
-
this.messagesByIndex.delete(message.index);
|
1638
|
-
message.removeAllListeners('updated');
|
1639
|
-
this.emit('messageRemoved', message);
|
1640
|
-
}
|
1641
|
-
});
|
1642
|
-
list.on('itemUpdated', (args) => {
|
1643
|
-
log$4.debug(`${this.conversation.sid} itemUpdated: ${args.item.index}`);
|
1644
|
-
const message = this.messagesByIndex.get(args.item.index);
|
1645
|
-
if (message) {
|
1646
|
-
message._update(args.item.data);
|
1647
|
-
}
|
1648
|
-
});
|
1649
|
-
return list;
|
1650
|
-
}
|
1651
|
-
catch (err) {
|
1652
|
-
this.messagesListPromise = null;
|
1653
|
-
if (this.services.syncClient.connectionState !== 'disconnected') {
|
1654
|
-
log$4.error('Failed to get messages object for conversation', this.conversation.sid, err);
|
1655
|
-
}
|
1656
|
-
log$4.debug('ERROR: Failed to get messages object for conversation', this.conversation.sid, err);
|
1657
|
-
throw err;
|
1658
|
-
}
|
1659
|
-
}
|
1660
|
-
async unsubscribe() {
|
1661
|
-
if (!this.messagesListPromise) {
|
1662
|
-
return;
|
1663
|
-
}
|
1664
|
-
const entity = await this.messagesListPromise;
|
1665
|
-
entity.close();
|
1666
|
-
this.messagesListPromise = null;
|
1667
|
-
}
|
1668
|
-
/**
|
1669
|
-
* Send Message to the conversation, message could include both text and multiple media attachments.
|
1670
|
-
* @param message Message to post
|
1671
|
-
* @returns Returns promise which can fail
|
1672
|
-
*/
|
1673
|
-
async sendV2(message) {
|
1674
|
-
var _a;
|
1675
|
-
log$4.debug('Sending message V2', message.mediaContent, message.attributes, message.emailOptions);
|
1676
|
-
const media = [];
|
1677
|
-
for (const [category, mediaContent] of message.mediaContent) {
|
1678
|
-
log$4.debug(`Adding media to a message as ${mediaContent instanceof FormData ? 'FormData' : 'SendMediaOptions'}`, mediaContent);
|
1679
|
-
media.push(mediaContent instanceof FormData
|
1680
|
-
? await this.services.mcsClient.postFormData(mediaContent, category)
|
1681
|
-
: await this.services.mcsClient.post(mediaContent.contentType, mediaContent.media, category, mediaContent.filename));
|
1682
|
-
}
|
1683
|
-
return await this.services.commandExecutor.mutateResource('post', this.conversation.links.messages, {
|
1684
|
-
body: message.text,
|
1685
|
-
subject: (_a = message.emailOptions) === null || _a === void 0 ? void 0 : _a.subject,
|
1686
|
-
media_sids: media.map((m) => m.sid),
|
1687
|
-
attributes: typeof message.attributes !== 'undefined'
|
1688
|
-
? JSON.stringify(message.attributes)
|
1689
|
-
: undefined,
|
1690
|
-
});
|
1691
|
-
}
|
1692
|
-
/**
|
1693
|
-
* Send Message to the conversation
|
1694
|
-
* @param message Message to post
|
1695
|
-
* @param attributes Message attributes
|
1696
|
-
* @param emailOptions Options that modify E-mail integration behaviors.
|
1697
|
-
* @returns Returns promise which can fail
|
1698
|
-
*/
|
1699
|
-
async send(message, attributes = {}, emailOptions) {
|
1700
|
-
log$4.debug('Sending text message', message, attributes, emailOptions);
|
1701
|
-
return await this.services.commandExecutor.mutateResource('post', this.conversation.links.messages, {
|
1702
|
-
body: message !== null && message !== void 0 ? message : '',
|
1703
|
-
attributes: typeof attributes !== 'undefined'
|
1704
|
-
? JSON.stringify(attributes)
|
1705
|
-
: undefined,
|
1706
|
-
subject: emailOptions === null || emailOptions === void 0 ? void 0 : emailOptions.subject,
|
1707
|
-
});
|
1708
|
-
}
|
1709
|
-
/**
|
1710
|
-
* Send Media Message to the conversation
|
1711
|
-
* @param mediaContent Media content to post
|
1712
|
-
* @param attributes Message attributes
|
1713
|
-
* @param emailOptions Email options
|
1714
|
-
* @returns Returns promise which can fail
|
1715
|
-
*/
|
1716
|
-
async sendMedia(mediaContent, attributes = {}, emailOptions) {
|
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);
|
1719
|
-
const media = mediaContent instanceof FormData
|
1720
|
-
? await this.services.mcsClient.postFormData(mediaContent)
|
1721
|
-
: await this.services.mcsClient.post(mediaContent.contentType, mediaContent.media, 'media', mediaContent.filename);
|
1722
|
-
// emailOptions are currently ignored for media messages.
|
1723
|
-
return await this.services.commandExecutor.mutateResource('post', this.conversation.links.messages, {
|
1724
|
-
media_sids: [media.sid],
|
1725
|
-
attributes: typeof attributes !== 'undefined'
|
1726
|
-
? JSON.stringify(attributes)
|
1727
|
-
: undefined,
|
1728
|
-
});
|
1729
|
-
}
|
1730
|
-
/**
|
1731
|
-
* Returns messages from conversation using paginator interface
|
1732
|
-
* @param pageSize Number of messages to return in single chunk. By default it's 30.
|
1733
|
-
* @param anchor Most early message id which is already known, or 'end' by default
|
1734
|
-
* @param direction Pagination order 'backwards' or 'forward', 'forward' by default
|
1735
|
-
* @returns Last page of messages by default
|
1736
|
-
*/
|
1737
|
-
async getMessages(pageSize, anchor, direction = 'backwards') {
|
1738
|
-
return this._getMessages(pageSize, anchor, direction);
|
1739
|
-
}
|
1740
|
-
_wrapPaginator(order, page, op) {
|
1741
|
-
// Due to an inconsistency between Sync and Chat conventions, next and
|
1742
|
-
// previous pages should be swapped.
|
1743
|
-
const shouldReverse = order === 'desc';
|
1744
|
-
const nextPage = () => page.nextPage().then((page) => this._wrapPaginator(order, page, op));
|
1745
|
-
const previousPage = () => page.prevPage().then((page) => this._wrapPaginator(order, page, op));
|
1746
|
-
return op(page.items).then((items) => ({
|
1747
|
-
items: items.sort((x, y) => {
|
1748
|
-
return x.index - y.index;
|
1749
|
-
}),
|
1750
|
-
hasPrevPage: shouldReverse ? page.hasNextPage : page.hasPrevPage,
|
1751
|
-
hasNextPage: shouldReverse ? page.hasPrevPage : page.hasNextPage,
|
1752
|
-
prevPage: shouldReverse ? nextPage : previousPage,
|
1753
|
-
nextPage: shouldReverse ? previousPage : nextPage,
|
1754
|
-
}));
|
1755
|
-
}
|
1756
|
-
_upsertMessage(index, value) {
|
1757
|
-
const cachedMessage = this.messagesByIndex.get(index);
|
1758
|
-
if (cachedMessage) {
|
1759
|
-
return cachedMessage;
|
1760
|
-
}
|
1761
|
-
const links = {
|
1762
|
-
self: `${this.conversation.links.messages}/${value.sid}`,
|
1763
|
-
conversation: this.conversation.links.self,
|
1764
|
-
messages_receipts: `${this.conversation.links.messages}/${value.sid}/Receipts`,
|
1765
|
-
};
|
1766
|
-
const message = new Message(index, value, this.conversation, links, this.configuration, this.services);
|
1767
|
-
this.messagesByIndex.set(message.index, message);
|
1768
|
-
message.on('updated', (args) => this.emit('messageUpdated', args));
|
1769
|
-
return message;
|
1770
|
-
}
|
1771
|
-
/**
|
1772
|
-
* Returns last messages from conversation
|
1773
|
-
* @param {Number} [pageSize] Number of messages to return in single chunk. By default it's 30.
|
1774
|
-
* @param {String} [anchor] Most early message id which is already known, or 'end' by default
|
1775
|
-
* @param {String} [direction] Pagination order 'backwards' or 'forward', or 'forward' by default
|
1776
|
-
* @returns {Promise<SyncPaginator<Message>>} last page of messages by default
|
1777
|
-
* @private
|
1778
|
-
*/
|
1779
|
-
async _getMessages(pageSize = 30, anchor = 'end', direction = 'forward') {
|
1780
|
-
const order = direction === 'backwards' ? 'desc' : 'asc';
|
1781
|
-
const list = await this.messagesListPromise;
|
1782
|
-
const page = await list.getItems({
|
1783
|
-
from: anchor !== 'end' ? anchor : void 0,
|
1784
|
-
pageSize,
|
1785
|
-
order,
|
1786
|
-
limit: pageSize, // @todo Limit equals pageSize by default in Sync. This is probably not ideal.
|
1787
|
-
});
|
1788
|
-
return await this._wrapPaginator(order, page, (items) => Promise.all(items.map((item) => this._upsertMessage(item.index, item.data))));
|
1789
|
-
}
|
1790
|
-
}
|
1791
|
-
|
1792
|
-
/**
|
1793
|
-
* An unsent message. Returned from {@link MessageBuilder.build}.
|
1794
|
-
*/
|
1795
|
-
class UnsentMessage {
|
1796
|
-
/**
|
1797
|
-
* @internal
|
1798
|
-
*/
|
1799
|
-
constructor(messagesEntity) {
|
1800
|
-
this.messagesEntity = messagesEntity;
|
1801
|
-
this.attributes = {};
|
1802
|
-
this.mediaContent = [];
|
1803
|
-
this.emailOptions = {};
|
1804
|
-
}
|
1805
|
-
/**
|
1806
|
-
* Send the prepared message to the conversation.
|
1807
|
-
* @returns Index of the new message in the conversation.
|
1808
|
-
*/
|
1809
|
-
async send() {
|
1810
|
-
const response = await this.messagesEntity.sendV2(this);
|
1811
|
-
return parseToNumber(response.index);
|
1812
|
-
}
|
1813
|
-
}
|
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
|
-
*/
|
1830
|
-
class MessageBuilder {
|
1831
|
-
/**
|
1832
|
-
* @internal
|
1833
|
-
*/
|
1834
|
-
constructor(limits, messagesEntity) {
|
1835
|
-
this.limits = limits;
|
1836
|
-
this.message = new UnsentMessage(messagesEntity);
|
1837
|
-
}
|
1838
|
-
/**
|
1839
|
-
* Sets the message body.
|
1840
|
-
* @param text Contents of the body.
|
1841
|
-
*/
|
1842
|
-
setBody(text) {
|
1843
|
-
this.message.text = text;
|
1844
|
-
return this;
|
1845
|
-
}
|
1846
|
-
/**
|
1847
|
-
* Sets the message subject.
|
1848
|
-
* @param subject Contents of the subject.
|
1849
|
-
*/
|
1850
|
-
setSubject(subject) {
|
1851
|
-
this.message.emailOptions.subject = subject;
|
1852
|
-
return this;
|
1853
|
-
}
|
1854
|
-
/**
|
1855
|
-
* Sets the message attributes.
|
1856
|
-
* @param attributes Message attributes.
|
1857
|
-
*/
|
1858
|
-
setAttributes(attributes) {
|
1859
|
-
this.message.attributes = attributes;
|
1860
|
-
return this;
|
1861
|
-
}
|
1862
|
-
/**
|
1863
|
-
* Adds media to the message.
|
1864
|
-
* @param payload Media to add.
|
1865
|
-
*/
|
1866
|
-
addMedia(payload) {
|
1867
|
-
this.message.mediaContent.push(['media', payload]);
|
1868
|
-
return this;
|
1869
|
-
}
|
1870
|
-
/**
|
1871
|
-
* Builds the message, making it ready to be sent.
|
1872
|
-
*/
|
1873
|
-
build() {
|
1874
|
-
if (this.message.mediaContent.length > this.limits.mediaAttachmentsCountLimit) {
|
1875
|
-
throw new Error(`Too many media attachments in the message (${this.message.mediaContent.length} > ${this.limits.mediaAttachmentsCountLimit})`);
|
1876
|
-
}
|
1877
|
-
// @todo we don't know the sizes of the attachments in FormData
|
1878
|
-
return this.message;
|
1879
|
-
}
|
1880
|
-
getPayloadContentType(payload) {
|
1881
|
-
if (typeof FormData !== 'undefined' && (payload instanceof FormData)) {
|
1882
|
-
return payload.get('Content-Type');
|
1883
|
-
}
|
1884
|
-
return payload.contentType;
|
1885
|
-
}
|
1886
|
-
}
|
1887
|
-
|
1888
|
-
const log$3 = Logger.scope('Conversation');
|
1889
|
-
const fieldMappings = {
|
1890
|
-
lastMessage: 'lastMessage',
|
1891
|
-
attributes: 'attributes',
|
1892
|
-
createdBy: 'createdBy',
|
1893
|
-
dateCreated: 'dateCreated',
|
1894
|
-
dateUpdated: 'dateUpdated',
|
1895
|
-
friendlyName: 'friendlyName',
|
1896
|
-
lastConsumedMessageIndex: 'lastConsumedMessageIndex',
|
1897
|
-
notificationLevel: 'notificationLevel',
|
1898
|
-
sid: 'sid',
|
1899
|
-
status: 'status',
|
1900
|
-
uniqueName: 'uniqueName',
|
1901
|
-
state: 'state'
|
1902
|
-
};
|
1903
|
-
function parseTime(timeString) {
|
1904
|
-
try {
|
1905
|
-
return new Date(timeString);
|
1906
|
-
}
|
1907
|
-
catch (e) {
|
1908
|
-
return null;
|
1909
|
-
}
|
1910
|
-
}
|
1911
|
-
/**
|
1912
|
-
* A conversation represents communication between multiple Conversations clients
|
1913
|
-
*/
|
1914
|
-
class Conversation extends replayEventEmitter.ReplayEventEmitter {
|
1915
|
-
/**
|
1916
|
-
* @internal
|
1917
|
-
*/
|
1918
|
-
constructor(descriptor, sid, links, configuration, services) {
|
1919
|
-
super();
|
1920
|
-
this.sid = sid;
|
1921
|
-
this.links = links;
|
1922
|
-
this.configuration = configuration;
|
1923
|
-
this.services = services;
|
1924
|
-
let attributes = descriptor.attributes || {};
|
1925
|
-
let createdBy = descriptor.createdBy;
|
1926
|
-
let dateCreated = parseTime(descriptor.dateCreated);
|
1927
|
-
let dateUpdated = parseTime(descriptor.dateUpdated);
|
1928
|
-
let friendlyName = descriptor.friendlyName || null;
|
1929
|
-
let lastReadMessageIndex = Number.isInteger(descriptor.lastConsumedMessageIndex) ? descriptor.lastConsumedMessageIndex : null;
|
1930
|
-
let uniqueName = descriptor.uniqueName || null;
|
1931
|
-
try {
|
1932
|
-
JSON.stringify(attributes);
|
1933
|
-
}
|
1934
|
-
catch (e) {
|
1935
|
-
throw new Error('Attributes must be a valid JSON object.');
|
1936
|
-
}
|
1937
|
-
this.entityName = descriptor.channel;
|
1938
|
-
this.channelState = {
|
1939
|
-
uniqueName,
|
1940
|
-
status: 'notParticipating',
|
1941
|
-
attributes,
|
1942
|
-
createdBy,
|
1943
|
-
dateCreated,
|
1944
|
-
dateUpdated,
|
1945
|
-
friendlyName,
|
1946
|
-
lastReadMessageIndex: lastReadMessageIndex
|
1947
|
-
};
|
1948
|
-
if (descriptor.notificationLevel) {
|
1949
|
-
this.channelState.notificationLevel = descriptor.notificationLevel;
|
1950
|
-
}
|
1951
|
-
const participantsLinks = {
|
1952
|
-
participants: this.links.participants
|
1953
|
-
};
|
1954
|
-
this.participants = new Map();
|
1955
|
-
this.participantsEntity = new Participants(this, this.participants, participantsLinks, this.configuration, this.services);
|
1956
|
-
this.participantsEntity.on('participantJoined', this.emit.bind(this, 'participantJoined'));
|
1957
|
-
this.participantsEntity.on('participantLeft', this.emit.bind(this, 'participantLeft'));
|
1958
|
-
this.participantsEntity.on('participantUpdated', (args) => this.emit('participantUpdated', args));
|
1959
|
-
this.messagesEntity = new Messages(this, configuration, services);
|
1960
|
-
this.messagesEntity.on('messageAdded', message => this._onMessageAdded(message));
|
1961
|
-
this.messagesEntity.on('messageUpdated', (args) => this.emit('messageUpdated', args));
|
1962
|
-
this.messagesEntity.on('messageRemoved', this.emit.bind(this, 'messageRemoved'));
|
1963
|
-
}
|
1964
|
-
/**
|
1965
|
-
* Unique name of the conversation.
|
1966
|
-
*/
|
1967
|
-
get uniqueName() { return this.channelState.uniqueName; }
|
1968
|
-
/**
|
1969
|
-
* Status of the conversation.
|
1970
|
-
*/
|
1971
|
-
get status() { return this.channelState.status; }
|
1972
|
-
/**
|
1973
|
-
* Name of the conversation.
|
1974
|
-
*/
|
1975
|
-
get friendlyName() { return this.channelState.friendlyName; }
|
1976
|
-
/**
|
1977
|
-
* Date this conversation was last updated on.
|
1978
|
-
*/
|
1979
|
-
get dateUpdated() { return this.channelState.dateUpdated; }
|
1980
|
-
/**
|
1981
|
-
* Date this conversation was created on.
|
1982
|
-
*/
|
1983
|
-
get dateCreated() { return this.channelState.dateCreated; }
|
1984
|
-
/**
|
1985
|
-
* Identity of the user that created this conversation.
|
1986
|
-
*/
|
1987
|
-
get createdBy() { return this.channelState.createdBy; }
|
1988
|
-
/**
|
1989
|
-
* Custom attributes of the conversation.
|
1990
|
-
*/
|
1991
|
-
get attributes() { return this.channelState.attributes; }
|
1992
|
-
/**
|
1993
|
-
* Index of the last message the user has read in this conversation.
|
1994
|
-
*/
|
1995
|
-
get lastReadMessageIndex() { return this.channelState.lastReadMessageIndex; }
|
1996
|
-
/**
|
1997
|
-
* Last message sent to this conversation.
|
1998
|
-
*/
|
1999
|
-
get lastMessage() { return this.channelState.lastMessage; }
|
2000
|
-
/**
|
2001
|
-
* User notification level for this conversation.
|
2002
|
-
*/
|
2003
|
-
get notificationLevel() { return this.channelState.notificationLevel; }
|
2004
|
-
get limits() { return this.configuration.limits; }
|
2005
|
-
/**
|
2006
|
-
* State of the conversation.
|
2007
|
-
*/
|
2008
|
-
get state() { return this.channelState.state; }
|
2009
|
-
/**
|
2010
|
-
* Load and subscribe to this conversation and do not subscribe to its participants and messages.
|
2011
|
-
* This or _subscribeStreams will need to be called before any events on conversation will fire.
|
2012
|
-
* @internal
|
2013
|
-
*/
|
2014
|
-
_subscribe() {
|
2015
|
-
var _a;
|
2016
|
-
return this.entityPromise = (_a = this.entityPromise) !== null && _a !== void 0 ? _a : this.services.syncClient.document({ id: this.entityName, mode: 'open_existing' })
|
2017
|
-
.then(entity => {
|
2018
|
-
this.entity = entity;
|
2019
|
-
this.entity.on('updated', args => { this._update(args.data); });
|
2020
|
-
this.entity.on('removed', () => this.emit('removed', this));
|
2021
|
-
this._update(this.entity.data);
|
2022
|
-
return entity;
|
2023
|
-
})
|
2024
|
-
.catch(err => {
|
2025
|
-
this.entity = null;
|
2026
|
-
this.entityPromise = null;
|
2027
|
-
if (this.services.syncClient.connectionState != 'disconnected') {
|
2028
|
-
log$3.error('Failed to get conversation object', err);
|
2029
|
-
}
|
2030
|
-
log$3.debug('ERROR: Failed to get conversation object', err);
|
2031
|
-
throw err;
|
2032
|
-
});
|
2033
|
-
}
|
2034
|
-
/**
|
2035
|
-
* Load the attributes of this conversation and instantiate its participants and messages.
|
2036
|
-
* This or _subscribe will need to be called before any events on the conversation will fire.
|
2037
|
-
* This will need to be called before any events on participants or messages will fire
|
2038
|
-
* @internal
|
2039
|
-
*/
|
2040
|
-
async _subscribeStreams() {
|
2041
|
-
try {
|
2042
|
-
await this._subscribe();
|
2043
|
-
log$3.trace('_subscribeStreams, this.entity.data=', this.entity.data);
|
2044
|
-
const messagesObjectName = this.entity.data.messages;
|
2045
|
-
const rosterObjectName = this.entity.data.roster;
|
2046
|
-
await Promise.all([
|
2047
|
-
this.messagesEntity.subscribe(messagesObjectName),
|
2048
|
-
this.participantsEntity.subscribe(rosterObjectName)
|
2049
|
-
]);
|
2050
|
-
}
|
2051
|
-
catch (err) {
|
2052
|
-
if (this.services.syncClient.connectionState !== 'disconnected') {
|
2053
|
-
log$3.error('Failed to subscribe on conversation objects', this.sid, err);
|
2054
|
-
}
|
2055
|
-
log$3.debug('ERROR: Failed to subscribe on conversation objects', this.sid, err);
|
2056
|
-
throw err;
|
2057
|
-
}
|
2058
|
-
}
|
2059
|
-
/**
|
2060
|
-
* Stop listening for and firing events on this conversation.
|
2061
|
-
* @internal
|
2062
|
-
*/
|
2063
|
-
async _unsubscribe() {
|
2064
|
-
if (this.entity) {
|
2065
|
-
await this.entity.close();
|
2066
|
-
this.entity = null;
|
2067
|
-
this.entityPromise = null;
|
2068
|
-
}
|
2069
|
-
return Promise.all([
|
2070
|
-
this.participantsEntity.unsubscribe(),
|
2071
|
-
this.messagesEntity.unsubscribe()
|
2072
|
-
]);
|
2073
|
-
}
|
2074
|
-
/**
|
2075
|
-
* Set conversation status.
|
2076
|
-
* @internal
|
2077
|
-
*/
|
2078
|
-
_setStatus(status, source) {
|
2079
|
-
this.statusSource = source;
|
2080
|
-
if (this.channelState.status === status) {
|
2081
|
-
return;
|
2082
|
-
}
|
2083
|
-
this.channelState.status = status;
|
2084
|
-
if (status === 'joined') {
|
2085
|
-
this._subscribeStreams()
|
2086
|
-
.catch(err => {
|
2087
|
-
log$3.debug('ERROR while setting conversation status ' + status, err);
|
2088
|
-
if (this.services.syncClient.connectionState !== 'disconnected') {
|
2089
|
-
throw err;
|
2090
|
-
}
|
2091
|
-
});
|
2092
|
-
}
|
2093
|
-
else if (this.entityPromise) {
|
2094
|
-
this._unsubscribe().catch(err => {
|
2095
|
-
log$3.debug('ERROR while setting conversation status ' + status, err);
|
2096
|
-
if (this.services.syncClient.connectionState !== 'disconnected') {
|
2097
|
-
throw err;
|
2098
|
-
}
|
2099
|
-
});
|
2100
|
-
}
|
2101
|
-
}
|
2102
|
-
/**
|
2103
|
-
* Get the source of the conversation update.
|
2104
|
-
* @internal
|
2105
|
-
*/
|
2106
|
-
_statusSource() {
|
2107
|
-
return this.statusSource;
|
2108
|
-
}
|
2109
|
-
static preprocessUpdate(update, conversationSid) {
|
2110
|
-
try {
|
2111
|
-
if (typeof update.attributes === 'string') {
|
2112
|
-
update.attributes = JSON.parse(update.attributes);
|
2113
|
-
}
|
2114
|
-
else if (update.attributes) {
|
2115
|
-
JSON.stringify(update.attributes);
|
2116
|
-
}
|
2117
|
-
}
|
2118
|
-
catch (e) {
|
2119
|
-
log$3.warn('Retrieved malformed attributes from the server for conversation: ' + conversationSid);
|
2120
|
-
update.attributes = {};
|
2121
|
-
}
|
2122
|
-
try {
|
2123
|
-
if (update.dateCreated) {
|
2124
|
-
update.dateCreated = new Date(update.dateCreated);
|
2125
|
-
}
|
2126
|
-
}
|
2127
|
-
catch (e) {
|
2128
|
-
log$3.warn('Retrieved malformed dateCreated from the server for conversation: ' + conversationSid);
|
2129
|
-
delete update.dateCreated;
|
2130
|
-
}
|
2131
|
-
try {
|
2132
|
-
if (update.dateUpdated) {
|
2133
|
-
update.dateUpdated = new Date(update.dateUpdated);
|
2134
|
-
}
|
2135
|
-
}
|
2136
|
-
catch (e) {
|
2137
|
-
log$3.warn('Retrieved malformed dateUpdated from the server for conversation: ' + conversationSid);
|
2138
|
-
delete update.dateUpdated;
|
2139
|
-
}
|
2140
|
-
try {
|
2141
|
-
if (update.lastMessage && update.lastMessage.timestamp) {
|
2142
|
-
update.lastMessage.timestamp = new Date(update.lastMessage.timestamp);
|
2143
|
-
}
|
2144
|
-
}
|
2145
|
-
catch (e) {
|
2146
|
-
log$3.warn('Retrieved malformed lastMessage.timestamp from the server for conversation: ' + conversationSid);
|
2147
|
-
delete update.lastMessage.timestamp;
|
2148
|
-
}
|
2149
|
-
}
|
2150
|
-
/**
|
2151
|
-
* Update the local conversation object with new values.
|
2152
|
-
* @internal
|
2153
|
-
*/
|
2154
|
-
_update(update) {
|
2155
|
-
var _a, _b, _c, _d, _e;
|
2156
|
-
log$3.trace('_update', update);
|
2157
|
-
Conversation.preprocessUpdate(update, this.sid);
|
2158
|
-
const updateReasons = new Set();
|
2159
|
-
for (const key of Object.keys(update)) {
|
2160
|
-
const localKey = fieldMappings[key];
|
2161
|
-
if (!localKey) {
|
2162
|
-
continue;
|
2163
|
-
}
|
2164
|
-
switch (localKey) {
|
2165
|
-
case fieldMappings.status:
|
2166
|
-
if (!update.status || update.status === 'unknown'
|
2167
|
-
|| this.channelState.status === update.status) {
|
2168
|
-
break;
|
2169
|
-
}
|
2170
|
-
this.channelState.status = update.status;
|
2171
|
-
updateReasons.add(localKey);
|
2172
|
-
break;
|
2173
|
-
case fieldMappings.attributes:
|
2174
|
-
if (isEqual__default['default'](this.channelState.attributes, update.attributes)) {
|
2175
|
-
break;
|
2176
|
-
}
|
2177
|
-
this.channelState.attributes = update.attributes;
|
2178
|
-
updateReasons.add(localKey);
|
2179
|
-
break;
|
2180
|
-
case fieldMappings.lastConsumedMessageIndex:
|
2181
|
-
if (update.lastConsumedMessageIndex === undefined
|
2182
|
-
|| update.lastConsumedMessageIndex === this.channelState.lastReadMessageIndex) {
|
2183
|
-
break;
|
2184
|
-
}
|
2185
|
-
this.channelState.lastReadMessageIndex = update.lastConsumedMessageIndex;
|
2186
|
-
updateReasons.add('lastReadMessageIndex');
|
2187
|
-
break;
|
2188
|
-
case fieldMappings.lastMessage:
|
2189
|
-
if (this.channelState.lastMessage && !update.lastMessage) {
|
2190
|
-
delete this.channelState.lastMessage;
|
2191
|
-
updateReasons.add(localKey);
|
2192
|
-
break;
|
2193
|
-
}
|
2194
|
-
this.channelState.lastMessage = this.channelState.lastMessage || {};
|
2195
|
-
if (((_a = update.lastMessage) === null || _a === void 0 ? void 0 : _a.index) !== undefined
|
2196
|
-
&& update.lastMessage.index !== this.channelState.lastMessage.index) {
|
2197
|
-
this.channelState.lastMessage.index = update.lastMessage.index;
|
2198
|
-
updateReasons.add(localKey);
|
2199
|
-
}
|
2200
|
-
if (((_b = update.lastMessage) === null || _b === void 0 ? void 0 : _b.timestamp) !== undefined
|
2201
|
-
&& ((_d = (_c = this.channelState.lastMessage) === null || _c === void 0 ? void 0 : _c.dateCreated) === null || _d === void 0 ? void 0 : _d.getTime()) !== update.lastMessage.timestamp.getTime()) {
|
2202
|
-
this.channelState.lastMessage.dateCreated = update.lastMessage.timestamp;
|
2203
|
-
updateReasons.add(localKey);
|
2204
|
-
}
|
2205
|
-
if (isEqual__default['default'](this.channelState.lastMessage, {})) {
|
2206
|
-
delete this.channelState.lastMessage;
|
2207
|
-
}
|
2208
|
-
break;
|
2209
|
-
case fieldMappings.state:
|
2210
|
-
const state = update.state || undefined;
|
2211
|
-
if (state !== undefined) {
|
2212
|
-
state.dateUpdated = new Date(state.dateUpdated);
|
2213
|
-
}
|
2214
|
-
if (isEqual__default['default'](this.channelState.state, state)) {
|
2215
|
-
break;
|
2216
|
-
}
|
2217
|
-
this.channelState.state = state;
|
2218
|
-
updateReasons.add(localKey);
|
2219
|
-
break;
|
2220
|
-
default:
|
2221
|
-
const isDate = update[key] instanceof Date;
|
2222
|
-
const keysMatchAsDates = isDate && ((_e = this.channelState[localKey]) === null || _e === void 0 ? void 0 : _e.getTime()) === update[key].getTime();
|
2223
|
-
const keysMatchAsNonDates = !isDate && this[localKey] === update[key];
|
2224
|
-
if (keysMatchAsDates || keysMatchAsNonDates) {
|
2225
|
-
break;
|
2226
|
-
}
|
2227
|
-
this.channelState[localKey] = update[key];
|
2228
|
-
updateReasons.add(localKey);
|
2229
|
-
}
|
2230
|
-
}
|
2231
|
-
if (updateReasons.size > 0) {
|
2232
|
-
this.emit('updated', { conversation: this, updateReasons: [...updateReasons] });
|
2233
|
-
}
|
2234
|
-
}
|
2235
|
-
/**
|
2236
|
-
* @internal
|
2237
|
-
*/
|
2238
|
-
_onMessageAdded(message) {
|
2239
|
-
for (let participant of this.participants.values()) {
|
2240
|
-
if (participant.identity === message.author) {
|
2241
|
-
participant._endTyping();
|
2242
|
-
break;
|
2243
|
-
}
|
2244
|
-
}
|
2245
|
-
this.emit('messageAdded', message);
|
2246
|
-
}
|
2247
|
-
async _setLastReadMessageIndex(index) {
|
2248
|
-
const result = await this.services.commandExecutor.mutateResource('post', `${this.configuration.links.myConversations}/${this.sid}`, {
|
2249
|
-
last_read_message_index: index
|
2250
|
-
});
|
2251
|
-
return result.unread_messages_count;
|
2252
|
-
}
|
2253
|
-
/**
|
2254
|
-
* Add a participant to the conversation by its identity.
|
2255
|
-
* @param identity Identity of the Client to add.
|
2256
|
-
* @param attributes Attributes to be attached to the participant.
|
2257
|
-
*/
|
2258
|
-
async add(identity, attributes) {
|
2259
|
-
return this.participantsEntity.add(identity, attributes);
|
2260
|
-
}
|
2261
|
-
/**
|
2262
|
-
* Add a non-chat participant to the conversation.
|
2263
|
-
* @param proxyAddress Proxy (Twilio) address of the participant.
|
2264
|
-
* @param address User address of the participant.
|
2265
|
-
* @param attributes Attributes to be attached to the participant.
|
2266
|
-
*/
|
2267
|
-
async addNonChatParticipant(proxyAddress, address, attributes) {
|
2268
|
-
return this.participantsEntity.addNonChatParticipant(proxyAddress, address, attributes);
|
2269
|
-
}
|
2270
|
-
/**
|
2271
|
-
* Advance the conversation's last read message index to the current read horizon.
|
2272
|
-
* Rejects if the user is not a participant of the conversation.
|
2273
|
-
* Last read message index is updated only if the new index value is higher than the previous.
|
2274
|
-
* @param index Message index to advance to.
|
2275
|
-
* @return Resulting unread messages count in the conversation.
|
2276
|
-
*/
|
2277
|
-
async advanceLastReadMessageIndex(index) {
|
2278
|
-
await this._subscribeStreams();
|
2279
|
-
if (index < this.lastReadMessageIndex) {
|
2280
|
-
return await this._setLastReadMessageIndex(this.lastReadMessageIndex);
|
2281
|
-
}
|
2282
|
-
return await this._setLastReadMessageIndex(index);
|
2283
|
-
}
|
2284
|
-
/**
|
2285
|
-
* Delete the conversation and unsubscribe from its events.
|
2286
|
-
*/
|
2287
|
-
async delete() {
|
2288
|
-
await this.services.commandExecutor.mutateResource('delete', this.links.self);
|
2289
|
-
return this;
|
2290
|
-
}
|
2291
|
-
/**
|
2292
|
-
* Get the custom attributes of this Conversation.
|
2293
|
-
*/
|
2294
|
-
async getAttributes() {
|
2295
|
-
await this._subscribe();
|
2296
|
-
return this.attributes;
|
2297
|
-
}
|
2298
|
-
/**
|
2299
|
-
* Returns messages from the conversation using the paginator interface.
|
2300
|
-
* @param pageSize Number of messages to return in a single chunk. Default is 30.
|
2301
|
-
* @param anchor Index of the newest message to fetch. Default is from the end.
|
2302
|
-
* @param direction Query direction. By default it queries backwards
|
2303
|
-
* from newer to older. The `"forward"` value will query in the opposite direction.
|
2304
|
-
* @return A page of messages.
|
2305
|
-
*/
|
2306
|
-
async getMessages(pageSize, anchor, direction) {
|
2307
|
-
await this._subscribeStreams();
|
2308
|
-
return this.messagesEntity.getMessages(pageSize, anchor, direction);
|
2309
|
-
}
|
2310
|
-
/**
|
2311
|
-
* Get a list of all the participants who are joined to this conversation.
|
2312
|
-
*/
|
2313
|
-
async getParticipants() {
|
2314
|
-
await this._subscribeStreams();
|
2315
|
-
return this.participantsEntity.getParticipants();
|
2316
|
-
}
|
2317
|
-
/**
|
2318
|
-
* Get conversation participants count.
|
2319
|
-
*
|
2320
|
-
* This method is semi-realtime. This means that this data will be eventually correct,
|
2321
|
-
* but will also be possibly incorrect for a few seconds. The Conversations system does not
|
2322
|
-
* provide real time events for counter values changes.
|
2323
|
-
*
|
2324
|
-
* This is useful for any UI badges, but it is not recommended to build any core application
|
2325
|
-
* logic based on these counters being accurate in real time.
|
2326
|
-
*/
|
2327
|
-
async getParticipantsCount() {
|
2328
|
-
const url = new UriBuilder(this.configuration.links.conversations)
|
2329
|
-
.path(this.sid)
|
2330
|
-
.build();
|
2331
|
-
const response = await this.services.network.get(url);
|
2332
|
-
return response.body.participants_count;
|
2333
|
-
}
|
2334
|
-
/**
|
2335
|
-
* Get a participant by its SID.
|
2336
|
-
* @param participantSid Participant SID.
|
2337
|
-
*/
|
2338
|
-
async getParticipantBySid(participantSid) {
|
2339
|
-
return this.participantsEntity.getParticipantBySid(participantSid);
|
2340
|
-
}
|
2341
|
-
/**
|
2342
|
-
* Get a participant by its identity.
|
2343
|
-
* @param identity Participant identity.
|
2344
|
-
*/
|
2345
|
-
async getParticipantByIdentity(identity) {
|
2346
|
-
return this.participantsEntity.getParticipantByIdentity(identity);
|
2347
|
-
}
|
2348
|
-
/**
|
2349
|
-
* Get the total message count in the conversation.
|
2350
|
-
*
|
2351
|
-
* This method is semi-realtime. This means that this data will be eventually correct,
|
2352
|
-
* but will also be possibly incorrect for a few seconds. The Conversations system does not
|
2353
|
-
* provide real time events for counter values changes.
|
2354
|
-
*
|
2355
|
-
* This is useful for any UI badges, but it is not recommended to build any core application
|
2356
|
-
* logic based on these counters being accurate in real time.
|
2357
|
-
*/
|
2358
|
-
async getMessagesCount() {
|
2359
|
-
const url = new UriBuilder(this.configuration.links.conversations)
|
2360
|
-
.path(this.sid)
|
2361
|
-
.build();
|
2362
|
-
const response = await this.services.network.get(url);
|
2363
|
-
return response.body.messages_count;
|
2364
|
-
}
|
2365
|
-
/**
|
2366
|
-
* Get unread messages count for the user if they are a participant of this conversation.
|
2367
|
-
* Rejects if the user is not a participant of the conversation.
|
2368
|
-
*
|
2369
|
-
* Use this method to obtain the number of unread messages together with
|
2370
|
-
* {@link Conversation.updateLastReadMessageIndex} instead of relying on the
|
2371
|
-
* message indices which may have gaps. See {@link Message.index} for details.
|
2372
|
-
*
|
2373
|
-
* This method is semi-realtime. This means that this data will be eventually correct,
|
2374
|
-
* but will also be possibly incorrect for a few seconds. The Conversations system does not
|
2375
|
-
* provide real time events for counter values changes.
|
2376
|
-
*
|
2377
|
-
* This is useful for any UI badges, but it is not recommended to build any core application
|
2378
|
-
* logic based on these counters being accurate in real time.
|
2379
|
-
*/
|
2380
|
-
async getUnreadMessagesCount() {
|
2381
|
-
const url = new UriBuilder(this.configuration.links.myConversations)
|
2382
|
-
.path(this.sid)
|
2383
|
-
.build();
|
2384
|
-
const response = await this.services.network.get(url);
|
2385
|
-
if (response.body.conversation_sid !== this.sid) {
|
2386
|
-
throw new Error('Conversation was not found in the user conversations list');
|
2387
|
-
}
|
2388
|
-
const unreadMessageCount = response.body.unread_messages_count;
|
2389
|
-
if (typeof unreadMessageCount === 'number') {
|
2390
|
-
return unreadMessageCount;
|
2391
|
-
}
|
2392
|
-
return null;
|
2393
|
-
}
|
2394
|
-
/**
|
2395
|
-
* Join the conversation and subscribe to its events.
|
2396
|
-
*/
|
2397
|
-
async join() {
|
2398
|
-
await this.services.commandExecutor.mutateResource('post', this.links.participants, {
|
2399
|
-
identity: this.configuration.userIdentity
|
2400
|
-
});
|
2401
|
-
return this;
|
2402
|
-
}
|
2403
|
-
/**
|
2404
|
-
* Leave the conversation.
|
2405
|
-
*/
|
2406
|
-
async leave() {
|
2407
|
-
if (this.channelState.status === 'joined') {
|
2408
|
-
await this.services.commandExecutor.mutateResource('delete', `${this.links.participants}/${this.configuration.userIdentity}`);
|
2409
|
-
}
|
2410
|
-
return this;
|
2411
|
-
}
|
2412
|
-
/**
|
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.
|
2416
|
-
*/
|
2417
|
-
async removeParticipant(participant) {
|
2418
|
-
await this.participantsEntity.remove(typeof participant === 'string'
|
2419
|
-
? participant
|
2420
|
-
: participant.sid);
|
2421
|
-
}
|
2422
|
-
/**
|
2423
|
-
* Send a message to the conversation.
|
2424
|
-
* @param message Message body for the text message,
|
2425
|
-
* `FormData` or {@link SendMediaOptions} for media content. Sending FormData is supported only with the browser engine.
|
2426
|
-
* @param messageAttributes Attributes for the message.
|
2427
|
-
* @param emailOptions Email options for the message.
|
2428
|
-
* @return Index of the new message.
|
2429
|
-
*/
|
2430
|
-
async sendMessage(message, messageAttributes, emailOptions) {
|
2431
|
-
if (typeof message === 'string' || message === null) {
|
2432
|
-
let response = await this.messagesEntity.send(message, messageAttributes, emailOptions);
|
2433
|
-
return parseToNumber(response.index);
|
2434
|
-
}
|
2435
|
-
let response = await this.messagesEntity.sendMedia(message, messageAttributes, emailOptions);
|
2436
|
-
return parseToNumber(response.index);
|
2437
|
-
}
|
2438
|
-
/**
|
2439
|
-
* New interface to prepare for sending a message.
|
2440
|
-
* Use instead of `sendMessage`.
|
2441
|
-
*/
|
2442
|
-
prepareMessage() {
|
2443
|
-
return new MessageBuilder(this.limits, this.messagesEntity);
|
2444
|
-
}
|
2445
|
-
/**
|
2446
|
-
* Set last read message index of the conversation to the index of the last known message.
|
2447
|
-
* @return Resulting unread messages count in the conversation.
|
2448
|
-
*/
|
2449
|
-
async setAllMessagesRead() {
|
2450
|
-
await this._subscribeStreams();
|
2451
|
-
let messagesPage = await this.getMessages(1);
|
2452
|
-
if (messagesPage.items.length > 0) {
|
2453
|
-
return this.advanceLastReadMessageIndex(messagesPage.items[0].index);
|
2454
|
-
}
|
2455
|
-
return Promise.resolve(0);
|
2456
|
-
}
|
2457
|
-
/**
|
2458
|
-
* Set all messages in the conversation unread.
|
2459
|
-
* @return Resulting unread messages count in the conversation.
|
2460
|
-
*/
|
2461
|
-
async setAllMessagesUnread() {
|
2462
|
-
await this._subscribeStreams();
|
2463
|
-
return await this._setLastReadMessageIndex(null);
|
2464
|
-
}
|
2465
|
-
/**
|
2466
|
-
* Set user notification level for this conversation.
|
2467
|
-
* @param notificationLevel New user notification level.
|
2468
|
-
*/
|
2469
|
-
async setUserNotificationLevel(notificationLevel) {
|
2470
|
-
await this.services.commandExecutor.mutateResource('post', `${this.configuration.links.myConversations}/${this.sid}`, {
|
2471
|
-
notification_level: notificationLevel
|
2472
|
-
});
|
2473
|
-
}
|
2474
|
-
/**
|
2475
|
-
* Send a notification to the server indicating that this client is currently typing in this conversation.
|
2476
|
-
* Typing ended notification is sent after a while automatically, but by calling this method again you ensure that typing ended is not received.
|
2477
|
-
*/
|
2478
|
-
typing() {
|
2479
|
-
return this.services.typingIndicator.send(this.sid);
|
2480
|
-
}
|
2481
|
-
/**
|
2482
|
-
* Update the attributes of the conversation.
|
2483
|
-
* @param attributes New attributes.
|
2484
|
-
*/
|
2485
|
-
async updateAttributes(attributes) {
|
2486
|
-
await this.services.commandExecutor.mutateResource('post', this.links.self, {
|
2487
|
-
attributes: attributes !== undefined ? JSON.stringify(attributes) : undefined
|
2488
|
-
});
|
2489
|
-
return this;
|
2490
|
-
}
|
2491
|
-
/**
|
2492
|
-
* Update the friendly name of the conversation.
|
2493
|
-
* @param friendlyName New friendly name.
|
2494
|
-
*/
|
2495
|
-
async updateFriendlyName(friendlyName) {
|
2496
|
-
if (this.channelState.friendlyName !== friendlyName) {
|
2497
|
-
await this.services.commandExecutor.mutateResource('post', this.links.self, { friendly_name: friendlyName });
|
2498
|
-
}
|
2499
|
-
return this;
|
2500
|
-
}
|
2501
|
-
/**
|
2502
|
-
* Set the last read message index to the current read horizon.
|
2503
|
-
* @param index Message index to set as last read.
|
2504
|
-
* If null is provided, then the behavior is identical to {@link Conversation.setAllMessagesUnread}.
|
2505
|
-
* @returns Resulting unread messages count in the conversation.
|
2506
|
-
*/
|
2507
|
-
async updateLastReadMessageIndex(index) {
|
2508
|
-
await this._subscribeStreams();
|
2509
|
-
return this._setLastReadMessageIndex(index);
|
2510
|
-
}
|
2511
|
-
/**
|
2512
|
-
* Update the unique name of the conversation.
|
2513
|
-
* @param uniqueName New unique name for the conversation. Setting unique name to null removes it.
|
2514
|
-
*/
|
2515
|
-
async updateUniqueName(uniqueName) {
|
2516
|
-
if (this.channelState.uniqueName !== uniqueName) {
|
2517
|
-
if (!uniqueName) {
|
2518
|
-
uniqueName = '';
|
2519
|
-
}
|
2520
|
-
await this.services.commandExecutor.mutateResource('post', this.links.self, {
|
2521
|
-
unique_name: uniqueName
|
2522
|
-
});
|
2523
|
-
}
|
2524
|
-
return this;
|
2525
|
-
}
|
2526
|
-
}
|
2527
|
-
/**
|
2528
|
-
* Fired when a participant has joined the conversation.
|
2529
|
-
*
|
2530
|
-
* Parameters:
|
2531
|
-
* 1. {@link Participant} `participant` - participant that joined the conversation
|
2532
|
-
* @event
|
2533
|
-
*/
|
2534
|
-
Conversation.participantJoined = 'participantJoined';
|
2535
|
-
/**
|
2536
|
-
* Fired when a participant has left the conversation.
|
2537
|
-
*
|
2538
|
-
* Parameters:
|
2539
|
-
* 1. {@link Participant} `participant` - participant that left the conversation
|
2540
|
-
* @event
|
2541
|
-
*/
|
2542
|
-
Conversation.participantLeft = 'participantLeft';
|
2543
|
-
/**
|
2544
|
-
* Fired when data of a participant has been updated.
|
2545
|
-
*
|
2546
|
-
* Parameters:
|
2547
|
-
* 1. object `data` - info object provided with the event. It has the following properties:
|
2548
|
-
* * {@link Participant} `participant` - participant that has received the update
|
2549
|
-
* * {@link ParticipantUpdateReason}[] `updateReasons` - array of reasons for update
|
2550
|
-
* @event
|
2551
|
-
*/
|
2552
|
-
Conversation.participantUpdated = 'participantUpdated';
|
2553
|
-
/**
|
2554
|
-
* Fired when a new message has been added to the conversation.
|
2555
|
-
*
|
2556
|
-
* Parameters:
|
2557
|
-
* 1. {@link Message} `message` - message that has been added
|
2558
|
-
* @event
|
2559
|
-
*/
|
2560
|
-
Conversation.messageAdded = 'messageAdded';
|
2561
|
-
/**
|
2562
|
-
* Fired when message is removed from the conversation's message list.
|
2563
|
-
*
|
2564
|
-
* Parameters:
|
2565
|
-
* 1. {@link Message} `message` - message that has been removed
|
2566
|
-
* @event
|
2567
|
-
*/
|
2568
|
-
Conversation.messageRemoved = 'messageRemoved';
|
2569
|
-
/**
|
2570
|
-
* Fired when data of a message has been updated.
|
2571
|
-
*
|
2572
|
-
* Parameters:
|
2573
|
-
* 1. object `data` - info object provided with the event. It has the following properties:
|
2574
|
-
* * {@link Message} `message` - message that has received the update
|
2575
|
-
* * {@link MessageUpdateReason}[] `updateReasons` - array of reasons for update
|
2576
|
-
* @event
|
2577
|
-
*/
|
2578
|
-
Conversation.messageUpdated = 'messageUpdated';
|
2579
|
-
/**
|
2580
|
-
* Fired when a participant has stopped typing.
|
2581
|
-
*
|
2582
|
-
* Parameters:
|
2583
|
-
* 1. {@link Participant} `participant` - the participant that has stopped typing
|
2584
|
-
* @event
|
2585
|
-
*/
|
2586
|
-
Conversation.typingEnded = 'typingEnded';
|
2587
|
-
/**
|
2588
|
-
* Fired when a participant has started typing.
|
2589
|
-
*
|
2590
|
-
* Parameters:
|
2591
|
-
* 1. {@link Participant} `participant` - the participant that has started typing
|
2592
|
-
* @event
|
2593
|
-
*/
|
2594
|
-
Conversation.typingStarted = 'typingStarted';
|
2595
|
-
/**
|
2596
|
-
* Fired when the data of the conversation has been updated.
|
2597
|
-
*
|
2598
|
-
* Parameters:
|
2599
|
-
* 1. object `data` - info object provided with the event. It has the following properties:
|
2600
|
-
* * {@link Conversation} `conversation` - conversation that has received the update
|
2601
|
-
* * {@link ConversationUpdateReason}[] `updateReasons` - array of reasons for update
|
2602
|
-
* @event
|
2603
|
-
*/
|
2604
|
-
Conversation.updated = 'updated';
|
2605
|
-
/**
|
2606
|
-
* Fired when the conversation was destroyed or the currently-logged-in user has left private conversation.
|
2607
|
-
*
|
2608
|
-
* Parameters:
|
2609
|
-
* 1. {@link Conversation} `conversation` - conversation that has been removed
|
2610
|
-
* @event
|
2611
|
-
*/
|
2612
|
-
Conversation.removed = 'removed';
|
2613
|
-
__decorate([
|
2614
|
-
declarativeTypeValidator.validateTypesAsync(declarativeTypeValidator.nonEmptyString, ['undefined', 'string', 'number', 'boolean', 'object', declarativeTypeValidator.literal(null)]),
|
2615
|
-
__metadata("design:type", Function),
|
2616
|
-
__metadata("design:paramtypes", [String, Object]),
|
2617
|
-
__metadata("design:returntype", Promise)
|
2618
|
-
], Conversation.prototype, "add", null);
|
2619
|
-
__decorate([
|
2620
|
-
declarativeTypeValidator.validateTypesAsync(declarativeTypeValidator.nonEmptyString, declarativeTypeValidator.nonEmptyString, ['undefined', 'string', 'number', 'boolean', 'object', declarativeTypeValidator.literal(null)]),
|
2621
|
-
__metadata("design:type", Function),
|
2622
|
-
__metadata("design:paramtypes", [String, String, Object]),
|
2623
|
-
__metadata("design:returntype", Promise)
|
2624
|
-
], Conversation.prototype, "addNonChatParticipant", null);
|
2625
|
-
__decorate([
|
2626
|
-
declarativeTypeValidator.validateTypesAsync(declarativeTypeValidator.nonNegativeInteger),
|
2627
|
-
__metadata("design:type", Function),
|
2628
|
-
__metadata("design:paramtypes", [Number]),
|
2629
|
-
__metadata("design:returntype", Promise)
|
2630
|
-
], Conversation.prototype, "advanceLastReadMessageIndex", null);
|
2631
|
-
__decorate([
|
2632
|
-
declarativeTypeValidator.validateTypesAsync(['undefined', declarativeTypeValidator.nonNegativeInteger], ['undefined', declarativeTypeValidator.nonNegativeInteger], ['undefined', declarativeTypeValidator.literal('backwards', 'forward')]),
|
2633
|
-
__metadata("design:type", Function),
|
2634
|
-
__metadata("design:paramtypes", [Number, Number, String]),
|
2635
|
-
__metadata("design:returntype", Promise)
|
2636
|
-
], Conversation.prototype, "getMessages", null);
|
2637
|
-
__decorate([
|
2638
|
-
declarativeTypeValidator.validateTypesAsync(declarativeTypeValidator.nonEmptyString),
|
2639
|
-
__metadata("design:type", Function),
|
2640
|
-
__metadata("design:paramtypes", [String]),
|
2641
|
-
__metadata("design:returntype", Promise)
|
2642
|
-
], Conversation.prototype, "getParticipantBySid", null);
|
2643
|
-
__decorate([
|
2644
|
-
declarativeTypeValidator.validateTypesAsync(declarativeTypeValidator.nonEmptyString),
|
2645
|
-
__metadata("design:type", Function),
|
2646
|
-
__metadata("design:paramtypes", [String]),
|
2647
|
-
__metadata("design:returntype", Promise)
|
2648
|
-
], Conversation.prototype, "getParticipantByIdentity", null);
|
2649
|
-
__decorate([
|
2650
|
-
declarativeTypeValidator.validateTypesAsync([declarativeTypeValidator.nonEmptyString, Participant]),
|
2651
|
-
__metadata("design:type", Function),
|
2652
|
-
__metadata("design:paramtypes", [Object]),
|
2653
|
-
__metadata("design:returntype", Promise)
|
2654
|
-
], Conversation.prototype, "removeParticipant", null);
|
2655
|
-
__decorate([
|
2656
|
-
declarativeTypeValidator.validateTypesAsync([
|
2657
|
-
'string',
|
2658
|
-
declarativeTypeValidator.literal(null),
|
2659
|
-
// Wrapping it into a custom rule is necessary because the FormData class is not available on initialization.
|
2660
|
-
declarativeTypeValidator.custom((value) => [value instanceof FormData, 'an instance of FormData']),
|
2661
|
-
declarativeTypeValidator.objectSchema('media options', {
|
2662
|
-
contentType: declarativeTypeValidator.nonEmptyString,
|
2663
|
-
media: declarativeTypeValidator.custom((value) => {
|
2664
|
-
let isValid = (typeof value === 'string' && value.length > 0) || value instanceof Uint8Array || value instanceof ArrayBuffer;
|
2665
|
-
if (typeof Blob === 'function') {
|
2666
|
-
isValid = isValid || value instanceof Blob;
|
2667
|
-
}
|
2668
|
-
return [
|
2669
|
-
isValid,
|
2670
|
-
'a non-empty string, an instance of Buffer or an instance of Blob'
|
2671
|
-
];
|
2672
|
-
})
|
2673
|
-
})
|
2674
|
-
], ['undefined', 'string', 'number', 'boolean', 'object', declarativeTypeValidator.literal(null)], ['undefined', declarativeTypeValidator.literal(null), declarativeTypeValidator.objectSchema('email attributes', {
|
2675
|
-
subject: [declarativeTypeValidator.nonEmptyString, 'undefined']
|
2676
|
-
})]),
|
2677
|
-
__metadata("design:type", Function),
|
2678
|
-
__metadata("design:paramtypes", [Object, Object, Object]),
|
2679
|
-
__metadata("design:returntype", Promise)
|
2680
|
-
], Conversation.prototype, "sendMessage", null);
|
2681
|
-
__decorate([
|
2682
|
-
declarativeTypeValidator.validateTypesAsync(declarativeTypeValidator.literal('default', 'muted')),
|
2683
|
-
__metadata("design:type", Function),
|
2684
|
-
__metadata("design:paramtypes", [String]),
|
2685
|
-
__metadata("design:returntype", Promise)
|
2686
|
-
], Conversation.prototype, "setUserNotificationLevel", null);
|
2687
|
-
__decorate([
|
2688
|
-
declarativeTypeValidator.validateTypesAsync(['string', 'number', 'boolean', 'object', declarativeTypeValidator.literal(null)]),
|
2689
|
-
__metadata("design:type", Function),
|
2690
|
-
__metadata("design:paramtypes", [Object]),
|
2691
|
-
__metadata("design:returntype", Promise)
|
2692
|
-
], Conversation.prototype, "updateAttributes", null);
|
2693
|
-
__decorate([
|
2694
|
-
declarativeTypeValidator.validateTypesAsync(['string']),
|
2695
|
-
__metadata("design:type", Function),
|
2696
|
-
__metadata("design:paramtypes", [String]),
|
2697
|
-
__metadata("design:returntype", Promise)
|
2698
|
-
], Conversation.prototype, "updateFriendlyName", null);
|
2699
|
-
__decorate([
|
2700
|
-
declarativeTypeValidator.validateTypesAsync([declarativeTypeValidator.literal(null), declarativeTypeValidator.nonNegativeInteger]),
|
2701
|
-
__metadata("design:type", Function),
|
2702
|
-
__metadata("design:paramtypes", [Number]),
|
2703
|
-
__metadata("design:returntype", Promise)
|
2704
|
-
], Conversation.prototype, "updateLastReadMessageIndex", null);
|
2705
|
-
__decorate([
|
2706
|
-
declarativeTypeValidator.validateTypesAsync(['string', declarativeTypeValidator.literal(null)]),
|
2707
|
-
__metadata("design:type", Function),
|
2708
|
-
__metadata("design:paramtypes", [String]),
|
2709
|
-
__metadata("design:returntype", Promise)
|
2710
|
-
], Conversation.prototype, "updateUniqueName", null);
|
2711
|
-
|
2712
|
-
class Deferred {
|
2713
|
-
constructor() {
|
2714
|
-
this._promise = new Promise((resolve, reject) => {
|
2715
|
-
this._resolve = resolve;
|
2716
|
-
this._reject = reject;
|
2717
|
-
});
|
2718
|
-
}
|
2719
|
-
get promise() { return this._promise; }
|
2720
|
-
update(value) {
|
2721
|
-
this._resolve(value);
|
2722
|
-
}
|
2723
|
-
set(value) {
|
2724
|
-
this.current = value;
|
2725
|
-
this._resolve(value);
|
2726
|
-
}
|
2727
|
-
fail(e) {
|
2728
|
-
this._reject(e);
|
2729
|
-
}
|
2730
|
-
}
|
2731
|
-
|
2732
|
-
const log$2 = Logger.scope('Conversations');
|
2733
|
-
/**
|
2734
|
-
* Represents conversations collection
|
2735
|
-
* {@see Conversation}
|
2736
|
-
*/
|
2737
|
-
class Conversations extends replayEventEmitter.ReplayEventEmitter {
|
2738
|
-
constructor(configuration, services) {
|
2739
|
-
super();
|
2740
|
-
this.conversations = new Map();
|
2741
|
-
this.myConversationsRead = new Deferred();
|
2742
|
-
this.tombstones = new Set();
|
2743
|
-
this.myConversationsFetched = false;
|
2744
|
-
this.configuration = configuration;
|
2745
|
-
this.services = services;
|
2746
|
-
}
|
2747
|
-
async addConversation(options) {
|
2748
|
-
var _a, _b, _c;
|
2749
|
-
const attributes = typeof (options === null || options === void 0 ? void 0 : options.attributes) !== 'undefined'
|
2750
|
-
? options.attributes
|
2751
|
-
: {};
|
2752
|
-
const response = await this.services.commandExecutor.mutateResource('post', this.configuration.links.conversations, {
|
2753
|
-
friendly_name: options.friendlyName,
|
2754
|
-
unique_name: options.uniqueName,
|
2755
|
-
attributes: typeof attributes !== 'undefined' ? JSON.stringify(attributes) : undefined
|
2756
|
-
});
|
2757
|
-
const conversationSid = (_a = response.sid) !== null && _a !== void 0 ? _a : null;
|
2758
|
-
const conversationDocument = (_c = (_b = response.sync_objects) === null || _b === void 0 ? void 0 : _b.conversation) !== null && _c !== void 0 ? _c : null;
|
2759
|
-
const links = Object.assign({ self: response.url }, response.links);
|
2760
|
-
const existingConversation = this.conversations.get(conversationSid);
|
2761
|
-
if (existingConversation) {
|
2762
|
-
await existingConversation._subscribe();
|
2763
|
-
return existingConversation;
|
2764
|
-
}
|
2765
|
-
const conversation = new Conversation({
|
2766
|
-
channel: conversationDocument,
|
2767
|
-
entityName: null,
|
2768
|
-
uniqueName: null,
|
2769
|
-
attributes: null,
|
2770
|
-
createdBy: null,
|
2771
|
-
friendlyName: null,
|
2772
|
-
lastConsumedMessageIndex: null,
|
2773
|
-
dateCreated: null,
|
2774
|
-
dateUpdated: null
|
2775
|
-
}, conversationSid, links, this.configuration, this.services);
|
2776
|
-
this.conversations.set(conversation.sid, conversation);
|
2777
|
-
this._registerForEvents(conversation);
|
2778
|
-
await conversation._subscribe();
|
2779
|
-
this.emit('conversationAdded', conversation);
|
2780
|
-
return conversation;
|
2781
|
-
}
|
2782
|
-
/**
|
2783
|
-
* Fetch conversations list and instantiate all necessary objects
|
2784
|
-
*/
|
2785
|
-
async fetchConversations() {
|
2786
|
-
try {
|
2787
|
-
const map = await this._getMap();
|
2788
|
-
map.on('itemAdded', args => {
|
2789
|
-
log$2.debug(`itemAdded: ${args.item.key}`);
|
2790
|
-
this._upsertConversation('sync', args.item.key, args.item.data);
|
2791
|
-
});
|
2792
|
-
map.on('itemRemoved', args => {
|
2793
|
-
log$2.debug(`itemRemoved: ${args.key}`);
|
2794
|
-
const sid = args.key;
|
2795
|
-
if (!this.myConversationsFetched) {
|
2796
|
-
this.tombstones.add(sid);
|
2797
|
-
}
|
2798
|
-
const conversation = this.conversations.get(sid);
|
2799
|
-
if (!conversation) {
|
2800
|
-
return;
|
2801
|
-
}
|
2802
|
-
if (conversation.status === 'joined') {
|
2803
|
-
conversation._setStatus('notParticipating', 'sync');
|
2804
|
-
this.emit('conversationLeft', conversation);
|
2805
|
-
}
|
2806
|
-
this.conversations.delete(sid);
|
2807
|
-
this.emit('conversationRemoved', conversation);
|
2808
|
-
conversation.emit('removed', conversation);
|
2809
|
-
});
|
2810
|
-
map.on('itemUpdated', args => {
|
2811
|
-
log$2.debug(`itemUpdated: ${args.item.key}`);
|
2812
|
-
this._upsertConversation('sync', args.item.key, args.item.data);
|
2813
|
-
});
|
2814
|
-
const myConversations = await this._fetchMyConversations();
|
2815
|
-
const upserts = [];
|
2816
|
-
for (const conversation of myConversations) {
|
2817
|
-
upserts.push(this._upsertConversation('rest', conversation.channel_sid, conversation));
|
2818
|
-
}
|
2819
|
-
this.myConversationsRead.set(true);
|
2820
|
-
await Promise.all(upserts);
|
2821
|
-
this.myConversationsFetched = true;
|
2822
|
-
this.tombstones.clear();
|
2823
|
-
log$2.debug('The conversations list has been successfully fetched');
|
2824
|
-
return this;
|
2825
|
-
}
|
2826
|
-
catch (error) {
|
2827
|
-
const errorMessage = 'Failed to fetch the conversations list';
|
2828
|
-
if (this.services.syncClient.connectionState !== 'disconnected') {
|
2829
|
-
log$2.error(errorMessage, error);
|
2830
|
-
}
|
2831
|
-
log$2.debug(`ERROR: ${errorMessage}`, error);
|
2832
|
-
throw error;
|
2833
|
-
}
|
2834
|
-
}
|
2835
|
-
async getConversations(args) {
|
2836
|
-
const conversationsMap = await this._getMap();
|
2837
|
-
const page = await conversationsMap.getItems();
|
2838
|
-
return this._wrapPaginator(page, items => Promise.all(items.map((item) => this._upsertConversation('sync', item.key, item.data))));
|
2839
|
-
}
|
2840
|
-
async getConversation(sid) {
|
2841
|
-
const conversationsMap = await this._getMap();
|
2842
|
-
const page = await conversationsMap.getItems({ from: sid });
|
2843
|
-
const items = page.items.map((item) => this._upsertConversation('sync', item.key, item.data));
|
2844
|
-
return items.length > 0 ? items[0] : null;
|
2845
|
-
}
|
2846
|
-
async getConversationByUniqueName(uniqueName) {
|
2847
|
-
const url = new UriBuilder(this.configuration.links.myConversations)
|
2848
|
-
.path(uniqueName)
|
2849
|
-
.build();
|
2850
|
-
const response = await this.services.network.get(url);
|
2851
|
-
const body = response.body;
|
2852
|
-
const sid = body.conversation_sid;
|
2853
|
-
const data = {
|
2854
|
-
entityName: null,
|
2855
|
-
lastConsumedMessageIndex: body.last_read_message_index,
|
2856
|
-
status: (body === null || body === void 0 ? void 0 : body.status) || 'unknown',
|
2857
|
-
friendlyName: body.friendly_name,
|
2858
|
-
dateUpdated: body.date_updated,
|
2859
|
-
dateCreated: body.date_created,
|
2860
|
-
uniqueName: body.unique_name,
|
2861
|
-
createdBy: body.created_by,
|
2862
|
-
attributes: body.attributes,
|
2863
|
-
channel: body.sync_objects.conversation,
|
2864
|
-
notificationLevel: body === null || body === void 0 ? void 0 : body.notification_level,
|
2865
|
-
sid
|
2866
|
-
};
|
2867
|
-
return this._upsertConversation('sync', sid, data);
|
2868
|
-
}
|
2869
|
-
async peekConversation(sid) {
|
2870
|
-
const url = new UriBuilder(this.configuration.links.conversations)
|
2871
|
-
.path(sid)
|
2872
|
-
.build();
|
2873
|
-
const response = await this.services.network.get(url);
|
2874
|
-
const body = response.body;
|
2875
|
-
const data = {
|
2876
|
-
entityName: null,
|
2877
|
-
// lastConsumedMessageIndex: body.last_read_message_index,
|
2878
|
-
status: (body === null || body === void 0 ? void 0 : body.status) || 'unknown',
|
2879
|
-
friendlyName: body.friendly_name,
|
2880
|
-
dateUpdated: body.date_updated,
|
2881
|
-
dateCreated: body.date_created,
|
2882
|
-
uniqueName: body.unique_name,
|
2883
|
-
createdBy: body.created_by,
|
2884
|
-
attributes: body.attributes,
|
2885
|
-
channel: `${sid}.channel`,
|
2886
|
-
// notificationLevel: body?.notification_level,
|
2887
|
-
sid
|
2888
|
-
};
|
2889
|
-
return this._upsertConversation('sync', sid, data);
|
2890
|
-
}
|
2891
|
-
async _getMap() {
|
2892
|
-
return await this.services.syncClient.map({
|
2893
|
-
id: this.configuration.myConversations,
|
2894
|
-
mode: 'open_existing'
|
2895
|
-
});
|
2896
|
-
}
|
2897
|
-
async _wrapPaginator(page, op) {
|
2898
|
-
const items = await op(page.items);
|
2899
|
-
return {
|
2900
|
-
items,
|
2901
|
-
hasNextPage: page.hasNextPage,
|
2902
|
-
hasPrevPage: page.hasPrevPage,
|
2903
|
-
nextPage: () => page.nextPage().then(x => this._wrapPaginator(x, op)),
|
2904
|
-
prevPage: () => page.prevPage().then(x => this._wrapPaginator(x, op))
|
2905
|
-
};
|
2906
|
-
}
|
2907
|
-
async _updateConversation(source, conversation, data) {
|
2908
|
-
const areSourcesDifferent = conversation._statusSource() !== undefined && source !== conversation._statusSource();
|
2909
|
-
const isChannelSourceSync = source !== 'rest' || conversation._statusSource() === 'sync';
|
2910
|
-
if (areSourcesDifferent && isChannelSourceSync && source !== 'sync') {
|
2911
|
-
log$2.trace('upsertConversation: conversation is known from sync and came from chat, ignoring', {
|
2912
|
-
sid: conversation.sid,
|
2913
|
-
data: data.status,
|
2914
|
-
conversation: conversation.status
|
2915
|
-
});
|
2916
|
-
return;
|
2917
|
-
}
|
2918
|
-
if (data.status === 'joined' && conversation.status !== 'joined') {
|
2919
|
-
conversation._setStatus('joined', source);
|
2920
|
-
let updateData = {};
|
2921
|
-
if (typeof data.notificationLevel !== 'undefined') {
|
2922
|
-
updateData.notificationLevel = data.notificationLevel;
|
2923
|
-
}
|
2924
|
-
if (typeof data.lastConsumedMessageIndex !== 'undefined') {
|
2925
|
-
updateData.lastConsumedMessageIndex = data.lastConsumedMessageIndex;
|
2926
|
-
}
|
2927
|
-
if (!isEqual__default['default'](updateData, {})) {
|
2928
|
-
conversation._update(updateData);
|
2929
|
-
}
|
2930
|
-
conversation._subscribe().then(() => {
|
2931
|
-
this.emit('conversationJoined', conversation);
|
2932
|
-
});
|
2933
|
-
return;
|
2934
|
-
}
|
2935
|
-
if (data.status === 'notParticipating' && conversation.status === 'joined') {
|
2936
|
-
conversation._setStatus('notParticipating', source);
|
2937
|
-
conversation._update(data);
|
2938
|
-
await conversation._subscribe();
|
2939
|
-
this.emit('conversationLeft', conversation);
|
2940
|
-
return;
|
2941
|
-
}
|
2942
|
-
if (data.status === 'notParticipating') {
|
2943
|
-
await conversation._subscribe();
|
2944
|
-
return;
|
2945
|
-
}
|
2946
|
-
conversation._update(data);
|
2947
|
-
}
|
2948
|
-
async _upsertConversation(source, sid, data) {
|
2949
|
-
log$2.trace(`upsertConversation called for ${sid}`, data);
|
2950
|
-
const conversation = this.conversations.get(sid);
|
2951
|
-
// If the channel is known, update it
|
2952
|
-
if (conversation) {
|
2953
|
-
log$2.trace(`upsertConversation: the conversation ${conversation.sid} is known;` +
|
2954
|
-
`its status is known from the source ${conversation._statusSource()} ` +
|
2955
|
-
`and the update came from the source ${source}`, conversation);
|
2956
|
-
await this._updateConversation(source, conversation, data);
|
2957
|
-
await conversation._subscribe();
|
2958
|
-
return conversation;
|
2959
|
-
}
|
2960
|
-
// If the conversations is deleted, ignore it
|
2961
|
-
if (['chat', 'rest'].includes(source) && this.tombstones.has(sid)) {
|
2962
|
-
log$2.trace('upsertChannel: the channel is deleted but reappeared again from chat, ignoring', sid);
|
2963
|
-
return;
|
2964
|
-
}
|
2965
|
-
// If the conversation is unknown, fetch it
|
2966
|
-
log$2.trace('upsertConversation: creating a local conversation object with sid ' + sid, data);
|
2967
|
-
const baseLink = `${this.configuration.links.conversations}/${sid}`;
|
2968
|
-
const links = {
|
2969
|
-
self: baseLink,
|
2970
|
-
messages: `${baseLink}/Messages`,
|
2971
|
-
participants: `${baseLink}/Participants`
|
2972
|
-
};
|
2973
|
-
const newConversation = new Conversation(data, sid, links, this.configuration, this.services);
|
2974
|
-
this.conversations.set(sid, newConversation);
|
2975
|
-
await newConversation._subscribe();
|
2976
|
-
this._registerForEvents(newConversation);
|
2977
|
-
this.emit('conversationAdded', newConversation);
|
2978
|
-
if (data.status === 'joined') {
|
2979
|
-
newConversation._setStatus('joined', source);
|
2980
|
-
this.emit('conversationJoined', newConversation);
|
2981
|
-
}
|
2982
|
-
return newConversation;
|
2983
|
-
}
|
2984
|
-
async _fetchMyConversations() {
|
2985
|
-
let conversations = [];
|
2986
|
-
let pageToken = null;
|
2987
|
-
do {
|
2988
|
-
const url = new UriBuilder(this.configuration.links.myConversations);
|
2989
|
-
if (pageToken) {
|
2990
|
-
url.arg('PageToken', pageToken);
|
2991
|
-
}
|
2992
|
-
const response = await this.services.network.get(url.build());
|
2993
|
-
const receivedConversations = response.body.conversations.map((conversationDescriptor) => ({
|
2994
|
-
descriptor: conversationDescriptor,
|
2995
|
-
channel_sid: conversationDescriptor.conversation_sid,
|
2996
|
-
status: conversationDescriptor.status,
|
2997
|
-
channel: conversationDescriptor.sync_objects.conversation,
|
2998
|
-
messages: conversationDescriptor.sync_objects.messages,
|
2999
|
-
roster: `${conversationDescriptor.conversation_sid}.roster`,
|
3000
|
-
lastConsumedMessageIndex: conversationDescriptor.last_consumed_message_index,
|
3001
|
-
notificationLevel: conversationDescriptor.notification_level
|
3002
|
-
}));
|
3003
|
-
pageToken = response.body.meta.next_token;
|
3004
|
-
conversations = [...conversations, ...receivedConversations];
|
3005
|
-
} while (pageToken);
|
3006
|
-
return conversations;
|
3007
|
-
}
|
3008
|
-
_onConversationRemoved(sid) {
|
3009
|
-
const conversation = this.conversations.get(sid);
|
3010
|
-
if (conversation) {
|
3011
|
-
this.conversations.delete(sid);
|
3012
|
-
this.emit('conversationRemoved', conversation);
|
3013
|
-
}
|
3014
|
-
}
|
3015
|
-
_registerForEvents(conversation) {
|
3016
|
-
conversation.on('removed', () => this._onConversationRemoved(conversation.sid));
|
3017
|
-
conversation.on('updated', (args) => this.emit('conversationUpdated', args));
|
3018
|
-
conversation.on('participantJoined', this.emit.bind(this, 'participantJoined'));
|
3019
|
-
conversation.on('participantLeft', this.emit.bind(this, 'participantLeft'));
|
3020
|
-
conversation.on('participantUpdated', (args) => this.emit('participantUpdated', args));
|
3021
|
-
conversation.on('messageAdded', this.emit.bind(this, 'messageAdded'));
|
3022
|
-
conversation.on('messageUpdated', (args) => this.emit('messageUpdated', args));
|
3023
|
-
conversation.on('messageRemoved', this.emit.bind(this, 'messageRemoved'));
|
3024
|
-
conversation.on('typingStarted', this.emit.bind(this, 'typingStarted'));
|
3025
|
-
conversation.on('typingEnded', this.emit.bind(this, 'typingEnded'));
|
3026
|
-
}
|
3027
|
-
}
|
3028
|
-
|
3029
|
-
/**
|
3030
|
-
* Container for known users
|
3031
|
-
*/
|
3032
|
-
class Users extends replayEventEmitter.ReplayEventEmitter {
|
3033
|
-
constructor(myself, configuration, services) {
|
3034
|
-
super();
|
3035
|
-
this.configuration = configuration;
|
3036
|
-
this.services = services;
|
3037
|
-
this.fifoStack = [];
|
3038
|
-
this.myself = myself;
|
3039
|
-
this.myself.on('updated', (args) => this.emit('userUpdated', args));
|
3040
|
-
this.myself.on('userSubscribed', () => this.emit('userSubscribed', this.myself));
|
3041
|
-
this.myself.on('userUnsubscribed', () => {
|
3042
|
-
this.emit('userUnsubscribed', this.myself);
|
3043
|
-
this.myself._ensureFetched();
|
3044
|
-
});
|
3045
|
-
this.subscribedUsers = new Map();
|
3046
|
-
}
|
3047
|
-
handleUnsubscribeUser(user) {
|
3048
|
-
if (this.subscribedUsers.has(user.identity)) {
|
3049
|
-
this.subscribedUsers.delete(user.identity);
|
3050
|
-
}
|
3051
|
-
let foundItemIndex = -1;
|
3052
|
-
let foundItem = this.fifoStack.find((item, index) => {
|
3053
|
-
if (item == user.identity) {
|
3054
|
-
foundItemIndex = index;
|
3055
|
-
return true;
|
3056
|
-
}
|
3057
|
-
return false;
|
3058
|
-
});
|
3059
|
-
if (foundItem) {
|
3060
|
-
this.fifoStack.splice(foundItemIndex, 1);
|
3061
|
-
}
|
3062
|
-
this.emit('userUnsubscribed', user);
|
3063
|
-
}
|
3064
|
-
handleSubscribeUser(user) {
|
3065
|
-
if (this.subscribedUsers.has(user.identity)) {
|
3066
|
-
return;
|
3067
|
-
}
|
3068
|
-
if (this.fifoStack.length >= this.configuration.userInfosToSubscribe) {
|
3069
|
-
this.subscribedUsers.get(this.fifoStack.shift()).unsubscribe();
|
3070
|
-
}
|
3071
|
-
this.fifoStack.push(user.identity);
|
3072
|
-
this.subscribedUsers.set(user.identity, user);
|
3073
|
-
this.emit('userSubscribed', user);
|
3074
|
-
}
|
3075
|
-
/**
|
3076
|
-
* Gets user, if it's in subscribed list - then return the user object from it,
|
3077
|
-
* if not - then subscribes and adds user to the FIFO stack
|
3078
|
-
* @returns {Promise<User>} Fully initialized user
|
3079
|
-
*/
|
3080
|
-
async getUser(identity, entityName = null) {
|
3081
|
-
await this.myself._ensureFetched();
|
3082
|
-
if (identity == this.myself.identity) {
|
3083
|
-
return this.myself;
|
3084
|
-
}
|
3085
|
-
let user = this.subscribedUsers.get(identity);
|
3086
|
-
if (!user) {
|
3087
|
-
if (!entityName) {
|
3088
|
-
entityName = await this.getSyncUniqueName(identity);
|
3089
|
-
}
|
3090
|
-
user = new User(identity, entityName, this.configuration, this.services);
|
3091
|
-
user.on('updated', (args) => this.emit('userUpdated', args));
|
3092
|
-
user.on('userSubscribed', () => this.handleSubscribeUser(user));
|
3093
|
-
user.on('userUnsubscribed', () => this.handleUnsubscribeUser(user));
|
3094
|
-
await user._ensureFetched();
|
3095
|
-
}
|
3096
|
-
return user;
|
3097
|
-
}
|
3098
|
-
/**
|
3099
|
-
* @returns {Promise<Array<User>>} returns list of subscribed User objects {@see User}
|
3100
|
-
*/
|
3101
|
-
async getSubscribedUsers() {
|
3102
|
-
await this.myself._ensureFetched();
|
3103
|
-
const users = [this.myself];
|
3104
|
-
this.subscribedUsers.forEach((user) => users.push(user));
|
3105
|
-
return users;
|
3106
|
-
}
|
3107
|
-
/**
|
3108
|
-
* @returns {Promise<string>} User's sync unique name
|
3109
|
-
*/
|
3110
|
-
async getSyncUniqueName(identity) {
|
3111
|
-
const url = new UriBuilder(this.configuration.links.users)
|
3112
|
-
.path(identity)
|
3113
|
-
.build();
|
3114
|
-
const response = await this.services.network.get(url);
|
3115
|
-
return response.body.sync_objects.user_info_map;
|
3116
|
-
}
|
3117
|
-
}
|
3118
|
-
|
3119
|
-
const log$1 = Logger.scope('TypingIndicator');
|
3120
|
-
/**
|
3121
|
-
* An important note in regards to typing timeout timers. There are two places that the SDK can get the "typing_timeout" attribute from. The first
|
3122
|
-
* place that the attribute appears in is the response received from POST -> /v1/typing REST call. In the body of that response, the value of the
|
3123
|
-
* "typing_timeout" attribute will be exactly the same as defined in the console. The second place that the attribute appears in is from a
|
3124
|
-
* notification of type "twilio.ipmsg.typing_indicator". In this case, the "typing_timeout" value will be +1 of that in the console. This
|
3125
|
-
* intentional. The timeout returned from the POST -> /v1/typing call should be used to disable further calls for that period of time. On contrary,
|
3126
|
-
* the timeout returned from the notification should be used as the timeout for the "typingEnded" event, +1 is to account for latency.
|
3127
|
-
*
|
3128
|
-
* @private
|
3129
|
-
*/
|
3130
|
-
/**
|
3131
|
-
* @class TypingIndicator
|
3132
|
-
*
|
3133
|
-
* @constructor
|
3134
|
-
* @private
|
3135
|
-
*/
|
3136
|
-
class TypingIndicator {
|
3137
|
-
constructor(getConversation, config, services) {
|
3138
|
-
this.configuration = config;
|
3139
|
-
this.services = services;
|
3140
|
-
this.getConversation = getConversation;
|
3141
|
-
this.serviceTypingTimeout = null;
|
3142
|
-
this.sentUpdates = new Map();
|
3143
|
-
}
|
3144
|
-
get typingTimeout() {
|
3145
|
-
return this.configuration.typingIndicatorTimeoutOverride
|
3146
|
-
|| this.serviceTypingTimeout
|
3147
|
-
|| this.configuration.typingIndicatorTimeoutDefault;
|
3148
|
-
}
|
3149
|
-
/**
|
3150
|
-
* Initialize TypingIndicator controller
|
3151
|
-
* Registers for needed message types and sets listeners
|
3152
|
-
* @private
|
3153
|
-
*/
|
3154
|
-
initialize() {
|
3155
|
-
// this.services.notificationClient.subscribe(NotificationTypes.TYPING_INDICATOR, 'twilsock');
|
3156
|
-
this.services.notificationClient.on('message', async (type, message) => {
|
3157
|
-
if (type === NotificationTypes.TYPING_INDICATOR) {
|
3158
|
-
await this._handleRemoteTyping(message);
|
3159
|
-
}
|
3160
|
-
});
|
3161
|
-
}
|
3162
|
-
/**
|
3163
|
-
* Remote participants typing events handler
|
3164
|
-
*/
|
3165
|
-
async _handleRemoteTyping(message) {
|
3166
|
-
log$1.trace('Got new typing indicator ', message);
|
3167
|
-
this.getConversation(message.channel_sid)
|
3168
|
-
.then(conversation => {
|
3169
|
-
if (!conversation) {
|
3170
|
-
return;
|
3171
|
-
}
|
3172
|
-
conversation.participants.forEach(participant => {
|
3173
|
-
if (participant.identity !== message.identity) {
|
3174
|
-
return;
|
3175
|
-
}
|
3176
|
-
const timeout = this.configuration.typingIndicatorTimeoutOverride + 1000 || message.typing_timeout * 1000;
|
3177
|
-
participant._startTyping(timeout);
|
3178
|
-
});
|
3179
|
-
})
|
3180
|
-
.catch(err => {
|
3181
|
-
log$1.error(err);
|
3182
|
-
throw err;
|
3183
|
-
});
|
3184
|
-
}
|
3185
|
-
/**
|
3186
|
-
* Send typing event for the given conversation sid
|
3187
|
-
* @param {String} conversationSid
|
3188
|
-
*/
|
3189
|
-
send(conversationSid) {
|
3190
|
-
const lastUpdate = this.sentUpdates.get(conversationSid);
|
3191
|
-
if (lastUpdate && lastUpdate > (Date.now() - this.typingTimeout)) {
|
3192
|
-
return Promise.resolve();
|
3193
|
-
}
|
3194
|
-
this.sentUpdates.set(conversationSid, Date.now());
|
3195
|
-
return this._send(conversationSid);
|
3196
|
-
}
|
3197
|
-
_send(conversationSid) {
|
3198
|
-
log$1.trace('Sending typing indicator');
|
3199
|
-
const url = this.configuration.links.typing;
|
3200
|
-
const headers = {
|
3201
|
-
'Content-Type': 'application/x-www-form-urlencoded'
|
3202
|
-
};
|
3203
|
-
const body = `ChannelSid=${conversationSid}`;
|
3204
|
-
return (this.services.twilsockClient.post(url, headers, body, this.configuration.productId)
|
3205
|
-
.then((response) => {
|
3206
|
-
if (response.body.hasOwnProperty('typing_timeout')) {
|
3207
|
-
this.serviceTypingTimeout = response.body.typing_timeout * 1000;
|
3208
|
-
}
|
3209
|
-
})
|
3210
|
-
.catch((err) => {
|
3211
|
-
log$1.error('Failed to send typing indicator:', err);
|
3212
|
-
throw err;
|
3213
|
-
}));
|
3214
|
-
}
|
3215
|
-
}
|
3216
|
-
|
3217
|
-
/**
|
3218
|
-
* Push notification for a Conversations client.
|
3219
|
-
*/
|
3220
|
-
class PushNotification {
|
3221
|
-
/**
|
3222
|
-
* @internal
|
3223
|
-
*/
|
3224
|
-
constructor(data) {
|
3225
|
-
this.title = data.title || null;
|
3226
|
-
this.body = data.body || null;
|
3227
|
-
this.sound = data.sound || null;
|
3228
|
-
this.badge = data.badge || null;
|
3229
|
-
this.action = data.action || null;
|
3230
|
-
this.type = data.type || null;
|
3231
|
-
this.data = data.data || {};
|
3232
|
-
}
|
3233
|
-
}
|
3234
|
-
|
3235
|
-
var version = "2.0.1-rc.3";
|
3236
|
-
|
3237
|
-
const trimSlashes = (url) => url.replace(/(^\/+|\/+$)/g, '');
|
3238
|
-
const isMutationConflictResponse = (response) => response.status.code === 202;
|
3239
|
-
class CommandExecutor {
|
3240
|
-
constructor(_serviceUrl, _services, _productId) {
|
3241
|
-
this._serviceUrl = _serviceUrl;
|
3242
|
-
this._services = _services;
|
3243
|
-
this._productId = _productId;
|
3244
|
-
}
|
3245
|
-
_preProcessUrl(url) {
|
3246
|
-
const trimmedUrl = trimSlashes(url);
|
3247
|
-
if (/^https?:\/\//.test(url)) {
|
3248
|
-
return trimmedUrl;
|
3249
|
-
}
|
3250
|
-
return `${trimSlashes(this._serviceUrl)}/${trimmedUrl}`;
|
3251
|
-
}
|
3252
|
-
async _makeRequest(method, url, requestBody, headers) {
|
3253
|
-
const preProcessedUrl = this._preProcessUrl(url);
|
3254
|
-
const finalHeaders = Object.assign({ 'Content-Type': 'application/json; charset=utf-8' }, (headers || {}));
|
3255
|
-
let response;
|
3256
|
-
switch (method) {
|
3257
|
-
case 'get':
|
3258
|
-
let getUrl = preProcessedUrl;
|
3259
|
-
if (requestBody) {
|
3260
|
-
getUrl +=
|
3261
|
-
'?' +
|
3262
|
-
Object.entries(requestBody)
|
3263
|
-
.map((entry) => entry.map(encodeURIComponent).join('='))
|
3264
|
-
.join('&');
|
3265
|
-
}
|
3266
|
-
response = await this._services.transport.get(getUrl, finalHeaders, this._productId);
|
3267
|
-
break;
|
3268
|
-
case 'post':
|
3269
|
-
response = await this._services.transport.post(preProcessedUrl, finalHeaders, JSON.stringify(requestBody), this._productId);
|
3270
|
-
break;
|
3271
|
-
case 'delete':
|
3272
|
-
response = await this._services.transport.delete(preProcessedUrl, finalHeaders, null, this._productId);
|
3273
|
-
break;
|
3274
|
-
}
|
3275
|
-
if (response.status.code < 200 || response.status.code >= 300) {
|
3276
|
-
throw new Error(`Request responded with a non-success code ${response.status.code}`);
|
3277
|
-
}
|
3278
|
-
return response;
|
3279
|
-
}
|
3280
|
-
async fetchResource(url, requestBody) {
|
3281
|
-
const maxAttemptsCount = 6;
|
3282
|
-
let result;
|
3283
|
-
try {
|
3284
|
-
result = await new operationRetrier.AsyncRetrier({ min: 50, max: 1600, maxAttemptsCount })
|
3285
|
-
.run(() => this._makeRequest('get', url, requestBody));
|
3286
|
-
}
|
3287
|
-
catch (_a) {
|
3288
|
-
throw new Error(`Fetch resource from "${url}" failed.`);
|
3289
|
-
}
|
3290
|
-
return result.body;
|
3291
|
-
}
|
3292
|
-
async mutateResource(method, url, requestBody) {
|
3293
|
-
const result = await this._makeRequest(method, url, requestBody, {
|
3294
|
-
'X-Twilio-Mutation-Id': uuid.v4()
|
3295
|
-
});
|
3296
|
-
if (isMutationConflictResponse(result)) {
|
3297
|
-
return await this.fetchResource(result.body.resource_url);
|
3298
|
-
}
|
3299
|
-
return result.body;
|
3300
|
-
}
|
3301
|
-
}
|
3302
|
-
|
3303
|
-
var Client_1;
|
3304
|
-
const log = Logger.scope('Client');
|
3305
|
-
const SDK_VERSION = version;
|
3306
|
-
class ClientServices {
|
3307
|
-
}
|
3308
|
-
/**
|
3309
|
-
* A client is the starting point to the Twilio Conversations functionality.
|
3310
|
-
*/
|
3311
|
-
exports.Client = Client_1 = class Client extends replayEventEmitter.ReplayEventEmitter {
|
3312
|
-
/**
|
3313
|
-
* Returned Conversations instance is not yet fully initialized. Calling any operations will block until it is.
|
3314
|
-
* Use connection events to monitor when client becomes fully available (connectionStateChanged with state
|
3315
|
-
* 'connected') or not available (connectionStateChange with state 'denied', event tokenExpired, event connectionError).
|
3316
|
-
*
|
3317
|
-
* @param fpaToken Access token
|
3318
|
-
* @param options Options to customize the Client
|
3319
|
-
* @returns A not yet fully-initialized client.
|
3320
|
-
*/
|
3321
|
-
constructor(fpaToken, options = {}) {
|
3322
|
-
var _a, _b, _c, _d, _e;
|
3323
|
-
super();
|
3324
|
-
/**
|
3325
|
-
* Client connection state.
|
3326
|
-
*/
|
3327
|
-
this.connectionState = 'unknown';
|
3328
|
-
this.conversationsPromise = null;
|
3329
|
-
this._ensureReady = null;
|
3330
|
-
this._resolveEnsureReady = null;
|
3331
|
-
this._rejectEnsureReady = null;
|
3332
|
-
/**
|
3333
|
-
* Current version of the Conversations client.
|
3334
|
-
*/
|
3335
|
-
this.version = SDK_VERSION;
|
3336
|
-
this.parsePushNotification = Client_1.parsePushNotification;
|
3337
|
-
this.fpaToken = fpaToken;
|
3338
|
-
this.options = options;
|
3339
|
-
if (!this.options.disableDeepClone) {
|
3340
|
-
let options = Object.assign(Object.assign({}, this.options), { transport: undefined, twilsockClient: undefined });
|
3341
|
-
options = deepClone(options);
|
3342
|
-
options.transport = this.options.transport;
|
3343
|
-
options.twilsockClient = this.options.twilsockClient;
|
3344
|
-
this.options = options;
|
3345
|
-
}
|
3346
|
-
this.options.logLevel = (_a = this.options.logLevel) !== null && _a !== void 0 ? _a : 'silent';
|
3347
|
-
log.setLevel(this.options.logLevel);
|
3348
|
-
const productId = this.options.productId = 'ip_messaging';
|
3349
|
-
// Filling ClientMetadata
|
3350
|
-
this.options.clientMetadata = this.options.clientMetadata || {};
|
3351
|
-
if (!this.options.clientMetadata.hasOwnProperty('type')) {
|
3352
|
-
this.options.clientMetadata.type = 'conversations';
|
3353
|
-
}
|
3354
|
-
if (!this.options.clientMetadata.hasOwnProperty('sdk')) {
|
3355
|
-
this.options.clientMetadata.sdk = 'JS';
|
3356
|
-
this.options.clientMetadata.sdkv = SDK_VERSION;
|
3357
|
-
}
|
3358
|
-
// Enable session local storage for Sync
|
3359
|
-
this.options.Sync = this.options.Sync || {};
|
3360
|
-
if (typeof this.options.Sync.enableSessionStorage === 'undefined') {
|
3361
|
-
this.options.Sync.enableSessionStorage = true;
|
3362
|
-
}
|
3363
|
-
if (this.options.region) {
|
3364
|
-
this.options.Sync.region = this.options.region;
|
3365
|
-
}
|
3366
|
-
if (!fpaToken) {
|
3367
|
-
throw new Error('A valid Twilio token should be provided');
|
3368
|
-
}
|
3369
|
-
this.services = new ClientServices();
|
3370
|
-
this._myself = new User('', '', null, this.services);
|
3371
|
-
const startTwilsock = !this.options.twilsockClient;
|
3372
|
-
// Create default init registrations if none were provided.
|
3373
|
-
// Otherwise, the outside party have to list all the init registrations they
|
3374
|
-
// need.
|
3375
|
-
// Init registrations passed to the Conversations client will be passed down
|
3376
|
-
// to the Sync client as well.
|
3377
|
-
if (!this.options.initRegistrations) {
|
3378
|
-
const initRegistration = new twilsock.InitRegistration(productId);
|
3379
|
-
Client_1.populateInitRegistrations(initRegistration);
|
3380
|
-
this.options.initRegistrations = [initRegistration];
|
3381
|
-
}
|
3382
|
-
this.services.twilsockClient = (this.options.twilsockClient = (_b = this.options.twilsockClient) !== null && _b !== void 0 ? _b : new twilsock.TwilsockClient(fpaToken, productId, this.options));
|
3383
|
-
this.services.twilsockClient.on('tokenAboutToExpire', ttl => this.emit('tokenAboutToExpire', ttl));
|
3384
|
-
this.services.twilsockClient.on('tokenExpired', () => this.emit('tokenExpired'));
|
3385
|
-
this.services.twilsockClient.on('connectionError', (error) => this.emit('connectionError', error));
|
3386
|
-
this.services.twilsockClient.on('stateChanged', (state) => {
|
3387
|
-
log.debug(`Handling stateChanged for ConversationsClient: new state ${state}`);
|
3388
|
-
if (state !== this.connectionState) {
|
3389
|
-
this.connectionState = state;
|
3390
|
-
this.emit('connectionStateChanged', this.connectionState);
|
3391
|
-
}
|
3392
|
-
});
|
3393
|
-
this.services.transport = (this.options.transport = ((_c = this.options.transport) !== null && _c !== void 0 ? _c : this.options.twilsockClient));
|
3394
|
-
this.services.notificationClient = (this.options.notificationsClient = (_d = this.options.notificationsClient) !== null && _d !== void 0 ? _d : new notifications.Notifications(fpaToken, this.options));
|
3395
|
-
this.services.syncClient = (this.options.syncClient = (_e = this.options.syncClient) !== null && _e !== void 0 ? _e : new twilioSync.SyncClient(fpaToken, this.options));
|
3396
|
-
const configurationOptions = options.Chat || options.IPMessaging || options || {};
|
3397
|
-
const region = configurationOptions.region || options.region;
|
3398
|
-
const baseUrl = configurationOptions.apiUri
|
3399
|
-
|| configurationOptions.typingUri
|
3400
|
-
|| `https://aim.${region || 'us1'}.twilio.com`;
|
3401
|
-
this.services.commandExecutor = new CommandExecutor(baseUrl, { transport: this.options.transport }, productId);
|
3402
|
-
const emitFailed = (err) => {
|
3403
|
-
this._rejectEnsureReady(err);
|
3404
|
-
this.emit('stateChanged', 'failed');
|
3405
|
-
};
|
3406
|
-
this.services.twilsockClient.once('connectionError', emitFailed);
|
3407
|
-
this.services.twilsockClient.once('disconnected', emitFailed);
|
3408
|
-
// ConversationsClient will be able to initialize only after twilsock is connected
|
3409
|
-
this.services.twilsockClient.once('connected', async () => {
|
3410
|
-
log.debug(`ConversationsClient started INITIALIZING`);
|
3411
|
-
this.services.twilsockClient.off('connectionError', emitFailed);
|
3412
|
-
this.services.twilsockClient.off('disconnected', emitFailed);
|
3413
|
-
try {
|
3414
|
-
const startupEvent = 'conversations.client.startup';
|
3415
|
-
this.services.twilsockClient.addPartialTelemetryEvent(new twilsock.TelemetryEventDescription(startupEvent, 'Conversations client startup', new Date()), startupEvent, twilsock.TelemetryPoint.Start);
|
3416
|
-
await this._initialize();
|
3417
|
-
this.services.twilsockClient.addPartialTelemetryEvent(new twilsock.TelemetryEventDescription('', '', new Date()), startupEvent, twilsock.TelemetryPoint.End);
|
3418
|
-
}
|
3419
|
-
catch (err) {
|
3420
|
-
// Fail ChatClient if initialization is incomplete
|
3421
|
-
this._rejectEnsureReady(err);
|
3422
|
-
this.emit('stateChanged', 'failed');
|
3423
|
-
}
|
3424
|
-
});
|
3425
|
-
this._ensureReady = new Promise((resolve, reject) => {
|
3426
|
-
this._resolveEnsureReady = resolve;
|
3427
|
-
this._rejectEnsureReady = reject;
|
3428
|
-
}).catch((err) => { }); // @todo How to process unhandled rejection here?
|
3429
|
-
if (startTwilsock) {
|
3430
|
-
this.services.twilsockClient.connect();
|
3431
|
-
}
|
3432
|
-
}
|
3433
|
-
static populateInitRegistrations(reg) {
|
3434
|
-
reg.populateInitRegistrations([NotificationTypes.TYPING_INDICATOR]);
|
3435
|
-
twilioSync.SyncClient.populateInitRegistrations(reg);
|
3436
|
-
}
|
3437
|
-
/**
|
3438
|
-
* @deprecated Call constructor directly.
|
3439
|
-
*
|
3440
|
-
* Factory method to create a Conversations client instance.
|
3441
|
-
*
|
3442
|
-
* The factory method will automatically trigger connection.
|
3443
|
-
* Do not use it if you need finer-grained control.
|
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
|
-
*
|
3452
|
-
* @param token Access token.
|
3453
|
-
* @param options Options to customize the client.
|
3454
|
-
* @returns Returns a fully initialized client.
|
3455
|
-
*/
|
3456
|
-
static async create(token, options) {
|
3457
|
-
// The logic is as follows:
|
3458
|
-
// - If twilsock is not passed in, then the ConversationsClient constructor will call twilsock.connect() by itself
|
3459
|
-
// and we do not need to do it here.
|
3460
|
-
// - If twilsock was passed in from the outside, but customer called ConversationsClient.create() then they are
|
3461
|
-
// using an obsolete workflow and the startup sequence will never complete.
|
3462
|
-
if (options === null || options === void 0 ? void 0 : options.twilsockClient) {
|
3463
|
-
throw new Error('Obsolete usage of ConversationsClient.create() ' +
|
3464
|
-
'factory method: if you pass twilsock from the outside then you must ' +
|
3465
|
-
'use ConversationsClient constructor and be prepared to work with ' +
|
3466
|
-
'uninitialized client.');
|
3467
|
-
}
|
3468
|
-
const client = new Client_1(token, options);
|
3469
|
-
await client._ensureReady;
|
3470
|
-
return client;
|
3471
|
-
}
|
3472
|
-
/**
|
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.
|
3476
|
-
*/
|
3477
|
-
get user() { return this._myself; }
|
3478
|
-
/**
|
3479
|
-
* Client reachability state. Throws if accessed before the client
|
3480
|
-
* initialization was completed.
|
3481
|
-
*/
|
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
|
-
}
|
3490
|
-
get token() { return this.fpaToken; }
|
3491
|
-
_subscribeToPushNotifications(channelType) {
|
3492
|
-
[NotificationTypes.NEW_MESSAGE,
|
3493
|
-
NotificationTypes.ADDED_TO_CONVERSATION,
|
3494
|
-
NotificationTypes.REMOVED_FROM_CONVERSATION,
|
3495
|
-
NotificationTypes.TYPING_INDICATOR,
|
3496
|
-
NotificationTypes.CONSUMPTION_UPDATE]
|
3497
|
-
.forEach(messageType => {
|
3498
|
-
this.services.notificationClient.subscribe(channelType, messageType);
|
3499
|
-
});
|
3500
|
-
}
|
3501
|
-
_unsubscribeFromPushNotifications(channelType) {
|
3502
|
-
[NotificationTypes.NEW_MESSAGE,
|
3503
|
-
NotificationTypes.ADDED_TO_CONVERSATION,
|
3504
|
-
NotificationTypes.REMOVED_FROM_CONVERSATION,
|
3505
|
-
NotificationTypes.TYPING_INDICATOR,
|
3506
|
-
NotificationTypes.CONSUMPTION_UPDATE]
|
3507
|
-
.forEach(messageType => {
|
3508
|
-
this.services.notificationClient.unsubscribe(channelType, messageType);
|
3509
|
-
});
|
3510
|
-
}
|
3511
|
-
async _initialize() {
|
3512
|
-
const configurationResponse = await this.services.commandExecutor.fetchResource('Client/v2/Configuration');
|
3513
|
-
this.configuration = new Configuration(this.options, configurationResponse, log);
|
3514
|
-
this._myself._resolveInitialization(this.configuration, this.configuration.userIdentity, this.configuration.userInfo, true);
|
3515
|
-
this.services.typingIndicator = new TypingIndicator(this.getConversationBySid.bind(this), this.configuration, this.services);
|
3516
|
-
this.services.network = new Network(this.configuration, this.services);
|
3517
|
-
this.services.users = new Users(this._myself, this.configuration, this.services);
|
3518
|
-
this.services.users.on('userSubscribed', this.emit.bind(this, 'userSubscribed'));
|
3519
|
-
this.services.users.on('userUpdated', (args) => this.emit('userUpdated', args));
|
3520
|
-
this.services.users.on('userUnsubscribed', this.emit.bind(this, 'userUnsubscribed'));
|
3521
|
-
this.conversations = new Conversations(this.configuration, this.services);
|
3522
|
-
this.conversations.on('conversationAdded', this.emit.bind(this, 'conversationAdded'));
|
3523
|
-
this.conversations.on('conversationRemoved', this.emit.bind(this, 'conversationRemoved'));
|
3524
|
-
this.conversations.on('conversationJoined', this.emit.bind(this, 'conversationJoined'));
|
3525
|
-
this.conversations.on('conversationLeft', this.emit.bind(this, 'conversationLeft'));
|
3526
|
-
this.conversations.on('conversationUpdated', (args) => this.emit('conversationUpdated', args));
|
3527
|
-
this.conversations.on('participantJoined', this.emit.bind(this, 'participantJoined'));
|
3528
|
-
this.conversations.on('participantLeft', this.emit.bind(this, 'participantLeft'));
|
3529
|
-
this.conversations.on('participantUpdated', (args) => this.emit('participantUpdated', args));
|
3530
|
-
this.conversations.on('messageAdded', this.emit.bind(this, 'messageAdded'));
|
3531
|
-
this.conversations.on('messageUpdated', (args) => this.emit('messageUpdated', args));
|
3532
|
-
this.conversations.on('messageRemoved', this.emit.bind(this, 'messageRemoved'));
|
3533
|
-
this.conversations.on('typingStarted', this.emit.bind(this, 'typingStarted'));
|
3534
|
-
this.conversations.on('typingEnded', this.emit.bind(this, 'typingEnded'));
|
3535
|
-
this.conversationsPromise = this.conversations.fetchConversations()
|
3536
|
-
.then(() => this.conversations)
|
3537
|
-
.catch((error) => {
|
3538
|
-
throw error;
|
3539
|
-
});
|
3540
|
-
await this.services.users.myself._ensureFetched();
|
3541
|
-
Client_1.supportedPushChannels.forEach(channelType => this._subscribeToPushNotifications(channelType));
|
3542
|
-
this.services.typingIndicator.initialize();
|
3543
|
-
this.services.mcsClient = new mcsClient.McsClient(this.fpaToken, this.configuration.links.mediaService, this.configuration.links.mediaSetService, Object.assign(Object.assign({}, this.options), { transport: null }));
|
3544
|
-
this._resolveEnsureReady();
|
3545
|
-
this.emit('stateChanged', 'initialized');
|
3546
|
-
}
|
3547
|
-
/**
|
3548
|
-
* Gracefully shut down the client.
|
3549
|
-
*/
|
3550
|
-
async shutdown() {
|
3551
|
-
await this._ensureReady;
|
3552
|
-
await this.services.twilsockClient.disconnect();
|
3553
|
-
}
|
3554
|
-
/**
|
3555
|
-
* Update the token used by the client and re-register with the Conversations services.
|
3556
|
-
* @param token New access token.
|
3557
|
-
*/
|
3558
|
-
async updateToken(token) {
|
3559
|
-
await this._ensureReady;
|
3560
|
-
log.info('updateToken');
|
3561
|
-
if (this.fpaToken === token) {
|
3562
|
-
return this;
|
3563
|
-
}
|
3564
|
-
await this.services.twilsockClient.updateToken(token);
|
3565
|
-
await this.services.notificationClient.updateToken(token);
|
3566
|
-
await this.services.mcsClient.updateToken(token);
|
3567
|
-
this.fpaToken = token;
|
3568
|
-
return this;
|
3569
|
-
}
|
3570
|
-
/**
|
3571
|
-
* Get a known conversation by its SID.
|
3572
|
-
* @param conversationSid Conversation sid
|
3573
|
-
*/
|
3574
|
-
async getConversationBySid(conversationSid) {
|
3575
|
-
await this._ensureReady;
|
3576
|
-
await this.conversations.myConversationsRead.promise;
|
3577
|
-
let conversation = await this.conversations.getConversation(conversationSid);
|
3578
|
-
if (!conversation) {
|
3579
|
-
conversation = await this.conversations.peekConversation(conversationSid);
|
3580
|
-
}
|
3581
|
-
if (!conversation) {
|
3582
|
-
throw new Error(`Conversation with SID ${conversationSid} is not found.`);
|
3583
|
-
}
|
3584
|
-
return conversation;
|
3585
|
-
}
|
3586
|
-
/**
|
3587
|
-
* Get a known conversation by its unique identifier name.
|
3588
|
-
* @param uniqueName The unique identifier name of the conversation.
|
3589
|
-
*/
|
3590
|
-
async getConversationByUniqueName(uniqueName) {
|
3591
|
-
await this._ensureReady;
|
3592
|
-
await this.conversations.myConversationsRead.promise;
|
3593
|
-
const conversation = await this.conversations.getConversationByUniqueName(uniqueName);
|
3594
|
-
if (!conversation) {
|
3595
|
-
throw new Error(`Conversation with unique name ${uniqueName} is not found.`);
|
3596
|
-
}
|
3597
|
-
return conversation;
|
3598
|
-
}
|
3599
|
-
/**
|
3600
|
-
* Get the current list of all the subscribed conversations.
|
3601
|
-
*/
|
3602
|
-
async getSubscribedConversations(args) {
|
3603
|
-
await this._ensureReady;
|
3604
|
-
return this.conversationsPromise.then(conversations => conversations.getConversations(args));
|
3605
|
-
}
|
3606
|
-
/**
|
3607
|
-
* Create a conversation on the server and subscribe to its events.
|
3608
|
-
* The default is a conversation with an empty friendly name.
|
3609
|
-
* @param options Options for the conversation.
|
3610
|
-
*/
|
3611
|
-
async createConversation(options) {
|
3612
|
-
await this._ensureReady;
|
3613
|
-
options = options || {};
|
3614
|
-
return this.conversationsPromise.then(conversationsEntity => conversationsEntity.addConversation(options));
|
3615
|
-
}
|
3616
|
-
/**
|
3617
|
-
* Register for push notifications.
|
3618
|
-
* @param channelType Channel type.
|
3619
|
-
* @param registrationId Push notification ID provided by the FCM/APNS service on the platform.
|
3620
|
-
*/
|
3621
|
-
async setPushRegistrationId(channelType, registrationId) {
|
3622
|
-
await this._ensureReady;
|
3623
|
-
this._subscribeToPushNotifications(channelType);
|
3624
|
-
this.services.notificationClient.setPushRegistrationId(channelType, registrationId);
|
3625
|
-
await this.services.notificationClient.commitChanges(); // Committing before this point is useless because we have no push id
|
3626
|
-
}
|
3627
|
-
/**
|
3628
|
-
* Unregister from push notifications.
|
3629
|
-
* @param channelType Channel type.
|
3630
|
-
* @deprecated Use removePushRegistrations() instead.
|
3631
|
-
*/
|
3632
|
-
async unsetPushRegistrationId(channelType) {
|
3633
|
-
await this._ensureReady;
|
3634
|
-
this._unsubscribeFromPushNotifications(channelType);
|
3635
|
-
await this.services.notificationClient.commitChanges();
|
3636
|
-
}
|
3637
|
-
/**
|
3638
|
-
* Clear existing registrations directly using provided device token.
|
3639
|
-
* This is useful to ensure stopped subscriptions without resubscribing.
|
3640
|
-
*
|
3641
|
-
* This function goes completely beside the state machine and removes all registrations.
|
3642
|
-
* Use with caution: if it races with current state machine operations, madness will ensue.
|
3643
|
-
*
|
3644
|
-
* @param channelType Channel type.
|
3645
|
-
* @param registrationId Push notification ID provided by the FCM/APNS service on the platform.
|
3646
|
-
*/
|
3647
|
-
async removePushRegistrations(channelType, registrationId) {
|
3648
|
-
// do not await this._ensureReady() here - it could be called at any moment
|
3649
|
-
await this.services.notificationClient.removeRegistrations(channelType, registrationId);
|
3650
|
-
}
|
3651
|
-
static parsePushNotificationChatData(data) {
|
3652
|
-
const result = {};
|
3653
|
-
for (let key in Client_1.supportedPushDataFields) {
|
3654
|
-
if (typeof data[key] === 'undefined' || data[key] === null) {
|
3655
|
-
continue;
|
3656
|
-
}
|
3657
|
-
if (key !== 'message_index') {
|
3658
|
-
result[Client_1.supportedPushDataFields[key]] = data[key];
|
3659
|
-
continue;
|
3660
|
-
}
|
3661
|
-
if (parseToNumber(data[key]) !== null) {
|
3662
|
-
result[Client_1.supportedPushDataFields[key]] = Number(data[key]);
|
3663
|
-
}
|
3664
|
-
}
|
3665
|
-
return result;
|
3666
|
-
}
|
3667
|
-
/**
|
3668
|
-
* Static method for push notification payload parsing. Returns parsed push as a {@link PushNotification} object.
|
3669
|
-
* @param notificationPayload Push notification payload.
|
3670
|
-
*/
|
3671
|
-
static parsePushNotification(notificationPayload) {
|
3672
|
-
log.debug('parsePushNotification, notificationPayload=', notificationPayload);
|
3673
|
-
// APNS specifics
|
3674
|
-
if (typeof notificationPayload.aps !== 'undefined') {
|
3675
|
-
if (!notificationPayload.twi_message_type) {
|
3676
|
-
throw new Error('Provided push notification payload does not contain Programmable Chat push notification type');
|
3677
|
-
}
|
3678
|
-
let data = Client_1.parsePushNotificationChatData(notificationPayload);
|
3679
|
-
let apsPayload = notificationPayload.aps;
|
3680
|
-
let body = null;
|
3681
|
-
let title = null;
|
3682
|
-
if (typeof apsPayload.alert === 'string') {
|
3683
|
-
body = apsPayload.alert || null;
|
3684
|
-
}
|
3685
|
-
else {
|
3686
|
-
body = apsPayload.alert.body || null;
|
3687
|
-
title = apsPayload.alert.title || null;
|
3688
|
-
}
|
3689
|
-
return new PushNotification({
|
3690
|
-
title: title,
|
3691
|
-
body: body,
|
3692
|
-
sound: apsPayload.sound || null,
|
3693
|
-
badge: apsPayload.badge || null,
|
3694
|
-
action: apsPayload.category || null,
|
3695
|
-
type: notificationPayload.twi_message_type,
|
3696
|
-
data: data
|
3697
|
-
});
|
3698
|
-
}
|
3699
|
-
// FCM specifics
|
3700
|
-
if (typeof notificationPayload.data !== 'undefined') {
|
3701
|
-
let dataPayload = notificationPayload.data;
|
3702
|
-
if (!dataPayload.twi_message_type) {
|
3703
|
-
throw new Error('Provided push notification payload does not contain Programmable Chat push notification type');
|
3704
|
-
}
|
3705
|
-
let data = Client_1.parsePushNotificationChatData(notificationPayload.data);
|
3706
|
-
return new PushNotification({
|
3707
|
-
title: dataPayload.twi_title || null,
|
3708
|
-
body: dataPayload.twi_body || null,
|
3709
|
-
sound: dataPayload.twi_sound || null,
|
3710
|
-
badge: null,
|
3711
|
-
action: dataPayload.twi_action || null,
|
3712
|
-
type: dataPayload.twi_message_type,
|
3713
|
-
data: data
|
3714
|
-
});
|
3715
|
-
}
|
3716
|
-
throw new Error('Provided push notification payload is not Programmable Chat notification');
|
3717
|
-
}
|
3718
|
-
/**
|
3719
|
-
* Handle push notification payload parsing and emit the {@link Client.pushNotification} event on this {@link Client} instance.
|
3720
|
-
* @param notificationPayload Push notification payload
|
3721
|
-
*/
|
3722
|
-
async handlePushNotification(notificationPayload) {
|
3723
|
-
await this._ensureReady;
|
3724
|
-
log.debug('handlePushNotification, notificationPayload=', notificationPayload);
|
3725
|
-
this.emit('pushNotification', Client_1.parsePushNotification(notificationPayload));
|
3726
|
-
}
|
3727
|
-
/**
|
3728
|
-
* Gets a user with the given identity. If it's in the subscribed list, then return the user object from it;
|
3729
|
-
* if not, then subscribe and add user to the subscribed list.
|
3730
|
-
* @param identity Identity of the user.
|
3731
|
-
* @returns A fully initialized user.
|
3732
|
-
*/
|
3733
|
-
async getUser(identity) {
|
3734
|
-
await this._ensureReady;
|
3735
|
-
return this.services.users.getUser(identity);
|
3736
|
-
}
|
3737
|
-
/**
|
3738
|
-
* Get a list of subscribed user objects.
|
3739
|
-
*/
|
3740
|
-
async getSubscribedUsers() {
|
3741
|
-
await this._ensureReady;
|
3742
|
-
return this.services.users.getSubscribedUsers();
|
3743
|
-
}
|
3744
|
-
};
|
3745
|
-
/**
|
3746
|
-
* Current version of the Conversations client.
|
3747
|
-
*/
|
3748
|
-
exports.Client.version = SDK_VERSION;
|
3749
|
-
exports.Client.supportedPushChannels = ['fcm', 'apn'];
|
3750
|
-
exports.Client.supportedPushDataFields = {
|
3751
|
-
'conversation_sid': 'conversationSid',
|
3752
|
-
'message_sid': 'messageSid',
|
3753
|
-
'message_index': 'messageIndex'
|
3754
|
-
};
|
3755
|
-
/**
|
3756
|
-
* Fired when a conversation becomes visible to the client. The event is also triggered when the client creates a new conversation.
|
3757
|
-
* Fired for all conversations client has joined.
|
3758
|
-
*
|
3759
|
-
* Parameters:
|
3760
|
-
* 1. {@link Conversation} `conversation` - the conversation in question
|
3761
|
-
* @event
|
3762
|
-
*/
|
3763
|
-
exports.Client.conversationAdded = 'conversationAdded';
|
3764
|
-
/**
|
3765
|
-
* Fired when the client joins a conversation.
|
3766
|
-
*
|
3767
|
-
* Parameters:
|
3768
|
-
* 1. {@link Conversation} `conversation` - the conversation in question
|
3769
|
-
* @event
|
3770
|
-
*/
|
3771
|
-
exports.Client.conversationJoined = 'conversationJoined';
|
3772
|
-
/**
|
3773
|
-
* Fired when the client leaves a conversation.
|
3774
|
-
*
|
3775
|
-
* Parameters:
|
3776
|
-
* 1. {@link Conversation} `conversation` - the conversation in question
|
3777
|
-
* @event
|
3778
|
-
*/
|
3779
|
-
exports.Client.conversationLeft = 'conversationLeft';
|
3780
|
-
/**
|
3781
|
-
* Fired when a conversation is no longer visible to the client.
|
3782
|
-
*
|
3783
|
-
* Parameters:
|
3784
|
-
* 1. {@link Conversation} `conversation` - the conversation in question
|
3785
|
-
* @event
|
3786
|
-
*/
|
3787
|
-
exports.Client.conversationRemoved = 'conversationRemoved';
|
3788
|
-
/**
|
3789
|
-
* Fired when the attributes or the metadata of a conversation have been updated.
|
3790
|
-
* During conversation's creation and initialization, this event might be fired multiple times
|
3791
|
-
* for same joined or created conversation as new data is arriving from different sources.
|
3792
|
-
*
|
3793
|
-
* Parameters:
|
3794
|
-
* 1. object `data` - info object provided with the event. It has the following properties:
|
3795
|
-
* * {@link Conversation} `conversation` - the conversation in question
|
3796
|
-
* * {@link ConversationUpdateReason}[] `updateReasons` - array of reasons for the update
|
3797
|
-
* @event
|
3798
|
-
*/
|
3799
|
-
exports.Client.conversationUpdated = 'conversationUpdated';
|
3800
|
-
/**
|
3801
|
-
* Fired when a participant has joined a conversation.
|
3802
|
-
*
|
3803
|
-
* Parameters:
|
3804
|
-
* 1. {@link Participant} `participant` - the participant in question
|
3805
|
-
* @event
|
3806
|
-
*/
|
3807
|
-
exports.Client.participantJoined = 'participantJoined';
|
3808
|
-
/**
|
3809
|
-
* Fired when a participant has left a conversation.
|
3810
|
-
*
|
3811
|
-
* Parameters:
|
3812
|
-
* 1. {@link Participant} `participant` - the participant in question
|
3813
|
-
* @event
|
3814
|
-
*/
|
3815
|
-
exports.Client.participantLeft = 'participantLeft';
|
3816
|
-
/**
|
3817
|
-
* Fired when a participant's fields have been updated.
|
3818
|
-
*
|
3819
|
-
* Parameters:
|
3820
|
-
* 1. object `data` - info object provided with the event. It has the following properties:
|
3821
|
-
* * {@link Participant} `participant` - the participant in question
|
3822
|
-
* * {@link ParticipantUpdateReason}[] `updateReasons` - array of reasons for the update
|
3823
|
-
* @event
|
3824
|
-
*/
|
3825
|
-
exports.Client.participantUpdated = 'participantUpdated';
|
3826
|
-
/**
|
3827
|
-
* Fired when a new message has been added to the conversation on the server.
|
3828
|
-
*
|
3829
|
-
* Parameters:
|
3830
|
-
* 1. {@link Message} `message` - the message in question
|
3831
|
-
* @event
|
3832
|
-
*/
|
3833
|
-
exports.Client.messageAdded = 'messageAdded';
|
3834
|
-
/**
|
3835
|
-
* Fired when a message is removed from the message list of a conversation.
|
3836
|
-
*
|
3837
|
-
* Parameters:
|
3838
|
-
* 1. {@link Message} `message` - the message in question
|
3839
|
-
* @event
|
3840
|
-
*/
|
3841
|
-
exports.Client.messageRemoved = 'messageRemoved';
|
3842
|
-
/**
|
3843
|
-
* Fired when the fields of an existing message are updated with new values.
|
3844
|
-
*
|
3845
|
-
* Parameters:
|
3846
|
-
* 1. object `data` - info object provided with the event. It has the following properties:
|
3847
|
-
* * {@link Message} `message` - the message in question
|
3848
|
-
* * {@link MessageUpdateReason}[] `updateReasons` - array of reasons for the update
|
3849
|
-
* @event
|
3850
|
-
*/
|
3851
|
-
exports.Client.messageUpdated = 'messageUpdated';
|
3852
|
-
/**
|
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
|
3856
|
-
* @event
|
3857
|
-
*/
|
3858
|
-
exports.Client.tokenAboutToExpire = 'tokenAboutToExpire';
|
3859
|
-
/**
|
3860
|
-
* Fired when the token has expired.
|
3861
|
-
* @event
|
3862
|
-
*/
|
3863
|
-
exports.Client.tokenExpired = 'tokenExpired';
|
3864
|
-
/**
|
3865
|
-
* Fired when a participant has stopped typing.
|
3866
|
-
*
|
3867
|
-
* Parameters:
|
3868
|
-
* 1. {@link Participant} `participant` - the participant in question
|
3869
|
-
* @event
|
3870
|
-
*/
|
3871
|
-
exports.Client.typingEnded = 'typingEnded';
|
3872
|
-
/**
|
3873
|
-
* Fired when a participant has started typing.
|
3874
|
-
*
|
3875
|
-
* Parameters:
|
3876
|
-
* 1. {@link Participant} `participant` - the participant in question
|
3877
|
-
* @event
|
3878
|
-
*/
|
3879
|
-
exports.Client.typingStarted = 'typingStarted';
|
3880
|
-
/**
|
3881
|
-
* Fired when the client has received (and parsed) a push notification via one of the push channels (apn or fcm).
|
3882
|
-
*
|
3883
|
-
* Parameters:
|
3884
|
-
* 1. {@link PushNotification} `pushNotification` - the push notification in question
|
3885
|
-
* @event
|
3886
|
-
*/
|
3887
|
-
exports.Client.pushNotification = 'pushNotification';
|
3888
|
-
/**
|
3889
|
-
* Fired when the client has subscribed to a user.
|
3890
|
-
*
|
3891
|
-
* Parameters:
|
3892
|
-
* 1. {@link User} `user` - the user in question
|
3893
|
-
* @event
|
3894
|
-
*/
|
3895
|
-
exports.Client.userSubscribed = 'userSubscribed';
|
3896
|
-
/**
|
3897
|
-
* Fired when the client has unsubscribed from a user.
|
3898
|
-
*
|
3899
|
-
* Parameters:
|
3900
|
-
* 1. {@link User} `user` - the user in question
|
3901
|
-
* @event
|
3902
|
-
*/
|
3903
|
-
exports.Client.userUnsubscribed = 'userUnsubscribed';
|
3904
|
-
/**
|
3905
|
-
* Fired when the properties or the reachability status of a user have been updated.
|
3906
|
-
*
|
3907
|
-
* Parameters:
|
3908
|
-
* 1. object `data` - info object provided with the event. It has the following properties:
|
3909
|
-
* * {@link User} `user` - the user in question
|
3910
|
-
* * {@link UserUpdateReason}[] `updateReasons` - array of reasons for the update
|
3911
|
-
* @event
|
3912
|
-
*/
|
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';
|
3930
|
-
/**
|
3931
|
-
* Fired when the connection is interrupted for an unexpected reason.
|
3932
|
-
*
|
3933
|
-
* Parameters:
|
3934
|
-
* 1. object `data` - info object provided with the event. It has the following properties:
|
3935
|
-
* * boolean `terminal` - Twilsock will stop connection attempts if true
|
3936
|
-
* * string `message` - the error message of the root cause
|
3937
|
-
* * number? `httpStatusCode` - http status code if available
|
3938
|
-
* * number? `errorCode` - Twilio public error code if available
|
3939
|
-
* @event
|
3940
|
-
*/
|
3941
|
-
exports.Client.connectionError = 'connectionError';
|
3942
|
-
__decorate([
|
3943
|
-
declarativeTypeValidator.validateTypesAsync(declarativeTypeValidator.nonEmptyString),
|
3944
|
-
__metadata("design:type", Function),
|
3945
|
-
__metadata("design:paramtypes", [String]),
|
3946
|
-
__metadata("design:returntype", Promise)
|
3947
|
-
], exports.Client.prototype, "updateToken", null);
|
3948
|
-
__decorate([
|
3949
|
-
declarativeTypeValidator.validateTypesAsync(declarativeTypeValidator.nonEmptyString),
|
3950
|
-
__metadata("design:type", Function),
|
3951
|
-
__metadata("design:paramtypes", [String]),
|
3952
|
-
__metadata("design:returntype", Promise)
|
3953
|
-
], exports.Client.prototype, "getConversationBySid", null);
|
3954
|
-
__decorate([
|
3955
|
-
declarativeTypeValidator.validateTypesAsync(declarativeTypeValidator.nonEmptyString),
|
3956
|
-
__metadata("design:type", Function),
|
3957
|
-
__metadata("design:paramtypes", [String]),
|
3958
|
-
__metadata("design:returntype", Promise)
|
3959
|
-
], exports.Client.prototype, "getConversationByUniqueName", null);
|
3960
|
-
__decorate([
|
3961
|
-
declarativeTypeValidator.validateTypesAsync([
|
3962
|
-
'undefined',
|
3963
|
-
declarativeTypeValidator.objectSchema('conversation options', {
|
3964
|
-
friendlyName: ['string', 'undefined'],
|
3965
|
-
isPrivate: ['boolean', 'undefined'],
|
3966
|
-
uniqueName: ['string', 'undefined']
|
3967
|
-
})
|
3968
|
-
]),
|
3969
|
-
__metadata("design:type", Function),
|
3970
|
-
__metadata("design:paramtypes", [Object]),
|
3971
|
-
__metadata("design:returntype", Promise)
|
3972
|
-
], exports.Client.prototype, "createConversation", null);
|
3973
|
-
__decorate([
|
3974
|
-
declarativeTypeValidator.validateTypesAsync(declarativeTypeValidator.literal('fcm', 'apn'), 'string'),
|
3975
|
-
__metadata("design:type", Function),
|
3976
|
-
__metadata("design:paramtypes", [String, String]),
|
3977
|
-
__metadata("design:returntype", Promise)
|
3978
|
-
], exports.Client.prototype, "setPushRegistrationId", null);
|
3979
|
-
__decorate([
|
3980
|
-
declarativeTypeValidator.validateTypesAsync(declarativeTypeValidator.literal('fcm', 'apn')),
|
3981
|
-
__metadata("design:type", Function),
|
3982
|
-
__metadata("design:paramtypes", [String]),
|
3983
|
-
__metadata("design:returntype", Promise)
|
3984
|
-
], exports.Client.prototype, "unsetPushRegistrationId", null);
|
3985
|
-
__decorate([
|
3986
|
-
declarativeTypeValidator.validateTypesAsync(declarativeTypeValidator.literal('fcm', 'apn'), declarativeTypeValidator.nonEmptyString),
|
3987
|
-
__metadata("design:type", Function),
|
3988
|
-
__metadata("design:paramtypes", [String, String]),
|
3989
|
-
__metadata("design:returntype", Promise)
|
3990
|
-
], exports.Client.prototype, "removePushRegistrations", null);
|
3991
|
-
__decorate([
|
3992
|
-
declarativeTypeValidator.validateTypesAsync(declarativeTypeValidator.pureObject),
|
3993
|
-
__metadata("design:type", Function),
|
3994
|
-
__metadata("design:paramtypes", [Object]),
|
3995
|
-
__metadata("design:returntype", Promise)
|
3996
|
-
], exports.Client.prototype, "handlePushNotification", null);
|
3997
|
-
__decorate([
|
3998
|
-
declarativeTypeValidator.validateTypesAsync(declarativeTypeValidator.nonEmptyString),
|
3999
|
-
__metadata("design:type", Function),
|
4000
|
-
__metadata("design:paramtypes", [String]),
|
4001
|
-
__metadata("design:returntype", Promise)
|
4002
|
-
], exports.Client.prototype, "getUser", null);
|
4003
|
-
__decorate([
|
4004
|
-
declarativeTypeValidator.validateTypesAsync('string', ['undefined', declarativeTypeValidator.pureObject]),
|
4005
|
-
__metadata("design:type", Function),
|
4006
|
-
__metadata("design:paramtypes", [String, Object]),
|
4007
|
-
__metadata("design:returntype", Promise)
|
4008
|
-
], exports.Client, "create", null);
|
4009
|
-
__decorate([
|
4010
|
-
declarativeTypeValidator.validateTypes(declarativeTypeValidator.pureObject),
|
4011
|
-
__metadata("design:type", Function),
|
4012
|
-
__metadata("design:paramtypes", [Object]),
|
4013
|
-
__metadata("design:returntype", PushNotification)
|
4014
|
-
], exports.Client, "parsePushNotification", null);
|
4015
|
-
exports.Client = Client_1 = __decorate([
|
4016
|
-
declarativeTypeValidator.validateConstructorTypes(declarativeTypeValidator.nonEmptyString, [
|
4017
|
-
declarativeTypeValidator.pureObject,
|
4018
|
-
'undefined'
|
4019
|
-
]),
|
4020
|
-
__metadata("design:paramtypes", [String, Object])
|
4021
|
-
], exports.Client);
|
4022
|
-
|
4023
|
-
exports.AggregatedDeliveryReceipt = AggregatedDeliveryReceipt;
|
4024
|
-
exports.Conversation = Conversation;
|
4025
|
-
exports.DetailedDeliveryReceipt = DetailedDeliveryReceipt;
|
4026
|
-
exports.Media = Media;
|
4027
|
-
exports.Message = Message;
|
4028
|
-
exports.MessageBuilder = MessageBuilder;
|
4029
|
-
exports.NotificationTypes = NotificationTypes;
|
4030
|
-
exports.Participant = Participant;
|
4031
|
-
exports.PushNotification = PushNotification;
|
4032
|
-
exports.RestPaginator = RestPaginator;
|
4033
|
-
exports.UnsentMessage = UnsentMessage;
|
4034
|
-
exports.User = User;
|
4035
|
-
//# sourceMappingURL=react-native.js.map
|