stanza 12.17.1 → 12.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/Client.d.ts +2 -0
  2. package/Client.js +45 -25
  3. package/Constants.js +1 -1
  4. package/README.md +0 -8
  5. package/Utils.d.ts +2 -0
  6. package/Utils.js +30 -6
  7. package/helpers/LegacyEntityCapabilities.js +4 -5
  8. package/helpers/NetworkDiscovery.d.ts +36 -0
  9. package/helpers/NetworkDiscovery.js +152 -0
  10. package/helpers/RSM.d.ts +6 -0
  11. package/helpers/RSM.js +20 -0
  12. package/index.d.ts +21 -7
  13. package/index.js +3 -1
  14. package/index.module.js +23 -0
  15. package/jingle/FileTransferSession.d.ts +1 -1
  16. package/jingle/FileTransferSession.js +1 -1
  17. package/jingle/SessionManager.js +4 -4
  18. package/jxt/Definitions.d.ts +2 -2
  19. package/jxt/Parser.js +2 -2
  20. package/jxt/StreamParser.d.ts +1 -1
  21. package/jxt/StreamParser.js +2 -2
  22. package/jxt/Types.d.ts +1 -0
  23. package/jxt/Types.js +3 -2
  24. package/lib/sasl/index.js +34 -35
  25. package/package.json +10 -18
  26. package/platform/browser/buffer/base64-js/index.d.ts +3 -0
  27. package/platform/browser/buffer/base64-js/index.js +110 -0
  28. package/platform/browser/buffer/ieee754/index.d.ts +2 -0
  29. package/platform/browser/buffer/ieee754/index.js +81 -0
  30. package/platform/browser/buffer/index.d.ts +120 -0
  31. package/platform/browser/buffer/index.js +1877 -0
  32. package/platform/browser/crypto/Hash.d.ts +28 -0
  33. package/platform/browser/crypto/Hash.js +114 -0
  34. package/platform/browser/crypto/Hmac.d.ts +27 -0
  35. package/platform/browser/crypto/Hmac.js +82 -0
  36. package/platform/browser/crypto/MD5.d.ts +22 -0
  37. package/platform/browser/crypto/MD5.js +129 -0
  38. package/platform/browser/crypto/SHA-1.d.ts +23 -0
  39. package/platform/browser/crypto/SHA-1.js +94 -0
  40. package/platform/browser/crypto/SHA-256.d.ts +33 -0
  41. package/platform/browser/crypto/SHA-256.js +173 -0
  42. package/platform/browser/crypto/SHA-512.d.ts +34 -0
  43. package/platform/browser/crypto/SHA-512.js +352 -0
  44. package/platform/browser/crypto/createHash.d.ts +3 -0
  45. package/platform/browser/crypto/createHash.js +31 -0
  46. package/platform/browser/index.d.ts +21 -0
  47. package/platform/browser/index.js +46 -0
  48. package/platform/browser/process.d.ts +1 -0
  49. package/platform/browser/process.js +62 -0
  50. package/platform/browser/stream/index.d.ts +5 -0
  51. package/platform/browser/stream/index.js +6 -0
  52. package/platform/browser/stream/lib/_stream_duplex.d.ts +12 -0
  53. package/platform/browser/stream/lib/_stream_duplex.js +114 -0
  54. package/platform/browser/stream/lib/_stream_passthrough.d.ts +6 -0
  55. package/platform/browser/stream/lib/_stream_passthrough.js +38 -0
  56. package/platform/browser/stream/lib/_stream_readable.d.ts +60 -0
  57. package/platform/browser/stream/lib/_stream_readable.js +980 -0
  58. package/platform/browser/stream/lib/_stream_transform.d.ts +20 -0
  59. package/platform/browser/stream/lib/_stream_transform.js +189 -0
  60. package/platform/browser/stream/lib/_stream_writable.d.ts +62 -0
  61. package/platform/browser/stream/lib/_stream_writable.js +632 -0
  62. package/platform/browser/stream/lib/internal/streams/BufferList.d.ts +11 -0
  63. package/platform/browser/stream/lib/internal/streams/BufferList.js +68 -0
  64. package/platform/browser/stream/lib/internal/streams/destroy.d.ts +2 -0
  65. package/platform/browser/stream/lib/internal/streams/destroy.js +62 -0
  66. package/platform/browser/stream/string_decoder.d.ts +24 -0
  67. package/platform/browser/stream/string_decoder.js +312 -0
  68. package/platform/browser/stream/util.d.ts +1 -0
  69. package/platform/browser/stream/util.js +34 -0
  70. package/platform/index.d.ts +1 -0
  71. package/platform/index.js +4 -0
  72. package/platform/node/index.d.ts +16 -0
  73. package/platform/node/index.js +53 -0
  74. package/platform/react-native/index.d.ts +2 -0
  75. package/platform/react-native/index.js +7 -0
  76. package/plugins/entity.js +1 -1
  77. package/plugins/hostmeta.d.ts +17 -10
  78. package/plugins/hostmeta.js +40 -62
  79. package/plugins/jingle.js +2 -2
  80. package/plugins/muc.js +1 -1
  81. package/protocol/xep0030.js +3 -1
  82. package/protocol/xep0084.js +6 -4
  83. package/protocol/xep0085.d.ts +1 -1
  84. package/protocol/xep0153.d.ts +1 -1
  85. package/protocol/xep0199.d.ts +1 -1
  86. package/protocol/xep0224.d.ts +1 -1
  87. package/protocol/xep0308.d.ts +1 -1
  88. package/protocol/xep0319.d.ts +1 -1
  89. package/protocol/xep0334.d.ts +1 -1
  90. package/transports/bosh.d.ts +2 -1
  91. package/transports/bosh.js +3 -4
  92. package/transports/websocket.d.ts +2 -1
  93. package/transports/websocket.js +9 -6
  94. package/module.js +0 -15317
package/Client.d.ts CHANGED
@@ -7,6 +7,7 @@ import * as JXT from './jxt';
7
7
  import { JSONData } from './jxt';
8
8
  import * as SASL from './lib/sasl';
9
9
  import { IQ, Message, Presence, StreamError, Stream } from './protocol';
10
+ import NetworkDiscovery from './helpers/NetworkDiscovery';
10
11
  interface StreamData {
11
12
  kind: string;
12
13
  stanza: any;
@@ -18,6 +19,7 @@ export default class Client extends EventEmitter {
18
19
  sm: StreamManagement;
19
20
  transport?: Transport;
20
21
  stanzas: JXT.Registry;
22
+ resolver: NetworkDiscovery;
21
23
  sessionStarting?: boolean;
22
24
  sessionStarted?: boolean;
23
25
  sessionTerminating?: boolean;
package/Client.js CHANGED
@@ -12,6 +12,7 @@ const protocol_1 = tslib_1.__importDefault(require("./protocol"));
12
12
  const bosh_1 = tslib_1.__importDefault(require("./transports/bosh"));
13
13
  const websocket_1 = tslib_1.__importDefault(require("./transports/websocket"));
14
14
  const Utils_1 = require("./Utils");
15
+ const NetworkDiscovery_1 = tslib_1.__importDefault(require("./helpers/NetworkDiscovery"));
15
16
  class Client extends events_1.EventEmitter {
16
17
  constructor(opts = {}) {
17
18
  super();
@@ -34,6 +35,7 @@ class Client extends events_1.EventEmitter {
34
35
  this.sasl.register('ANONYMOUS', SASL.ANONYMOUS, 0);
35
36
  this.stanzas = new JXT.Registry();
36
37
  this.stanzas.define(protocol_1.default);
38
+ this.resolver = new NetworkDiscovery_1.default();
37
39
  this.use(plugins_1.core);
38
40
  this.sm = new StreamManagement_1.default();
39
41
  if (this.config.allowResumption !== undefined) {
@@ -220,6 +222,7 @@ class Client extends events_1.EventEmitter {
220
222
  });
221
223
  }
222
224
  updateConfig(opts = {}) {
225
+ var _a;
223
226
  const currConfig = this.config || {};
224
227
  this.config = {
225
228
  allowResumption: true,
@@ -229,6 +232,7 @@ class Client extends events_1.EventEmitter {
229
232
  websocket: true
230
233
  },
231
234
  useStreamManagement: true,
235
+ transportPreferenceOrder: ['websocket', 'bosh'],
232
236
  ...currConfig,
233
237
  ...opts
234
238
  };
@@ -240,6 +244,9 @@ class Client extends events_1.EventEmitter {
240
244
  this.config.credentials.password = this.config.password;
241
245
  delete this.config.password;
242
246
  }
247
+ if (!this.config.transportPreferenceOrder) {
248
+ this.config.transportPreferenceOrder = Object.keys((_a = this.config.transports) !== null && _a !== void 0 ? _a : {});
249
+ }
243
250
  }
244
251
  get stream() {
245
252
  return this.transport ? this.transport.stream : undefined;
@@ -270,47 +277,60 @@ class Client extends events_1.EventEmitter {
270
277
  return this._getConfiguredCredentials();
271
278
  }
272
279
  async connect() {
280
+ var _a, _b, _c;
273
281
  this.sessionTerminating = false;
274
282
  this.sessionStarting = true;
275
283
  this.emit('--reset-stream-features');
276
284
  if (this.transport) {
277
285
  this.transport.disconnect(false);
278
286
  }
279
- const transportPref = ['websocket', 'bosh'];
287
+ const transportPref = (_a = this.config.transportPreferenceOrder) !== null && _a !== void 0 ? _a : [];
280
288
  let endpoints;
281
289
  for (const name of transportPref) {
282
- let conf = this.config.transports[name];
283
- if (!conf) {
290
+ const settings = this.config.transports[name];
291
+ if (!settings || !this.transports[name]) {
284
292
  continue;
285
293
  }
286
- if (typeof conf === 'string') {
287
- conf = { url: conf };
294
+ let config = {
295
+ acceptLanguages: this.config.acceptLanguages || [(_b = this.config.lang) !== null && _b !== void 0 ? _b : 'en'],
296
+ jid: this.config.jid,
297
+ lang: (_c = this.config.lang) !== null && _c !== void 0 ? _c : 'en',
298
+ server: this.config.server
299
+ };
300
+ const transport = new this.transports[name](this, this.sm, this.stanzas);
301
+ if (typeof settings === 'string') {
302
+ config.url = settings;
288
303
  }
289
- else if (conf === true) {
290
- if (!endpoints) {
291
- try {
292
- endpoints = await this.discoverBindings(this.config.server);
293
- }
294
- catch (err) {
295
- console.error(err);
304
+ else if (settings == true) {
305
+ if (transport.discoverBindings) {
306
+ const discovered = await transport.discoverBindings(this.config.server);
307
+ if (!discovered) {
296
308
  continue;
297
309
  }
310
+ config = {
311
+ ...config,
312
+ ...discovered
313
+ };
298
314
  }
299
- endpoints[name] = (endpoints[name] || []).filter(url => url.startsWith('wss:') || url.startsWith('https:'));
300
- if (!endpoints[name] || !endpoints[name].length) {
301
- continue;
315
+ else {
316
+ if (!endpoints) {
317
+ try {
318
+ endpoints = await this.discoverBindings(this.config.server);
319
+ }
320
+ catch (err) {
321
+ console.error(err);
322
+ continue;
323
+ }
324
+ }
325
+ endpoints[name] = (endpoints[name] || []).filter(url => url.startsWith('wss:') || url.startsWith('https:'));
326
+ if (!endpoints[name] || !endpoints[name].length) {
327
+ continue;
328
+ }
329
+ config.url = endpoints[name][0];
302
330
  }
303
- conf = { url: endpoints[name][0] };
304
331
  }
305
- this.transport = new this.transports[name](this, this.sm, this.stanzas);
306
- this.transport.connect({
307
- acceptLanguages: this.config.acceptLanguages || ['en'],
308
- jid: this.config.jid,
309
- lang: this.config.lang || 'en',
310
- server: this.config.server,
311
- url: conf.url,
312
- ...conf
313
- });
332
+ this.transport = transport;
333
+ this.transport.connect(config);
314
334
  return;
315
335
  }
316
336
  console.error('No endpoints found for the requested transports.');
package/Constants.js CHANGED
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.directionToSenders = exports.sendersToDirection = exports.JINGLE_INFO_RECEIVED_5 = exports.JINGLE_INFO_CHECKSUM_5 = exports.JINGLE_INFO_RINGING = exports.JINGLE_INFO_ACTIVE = exports.JINGLE_INFO_UNHOLD = exports.JINGLE_INFO_HOLD = exports.JINGLE_INFO_UNMUTE = exports.JINGLE_INFO_MUTE = exports.JINGLE_INFO = exports.USER_ACTIVITY_SPECIFIC = exports.USER_ACTIVITY_GENERAL = exports.USER_MOODS = exports.JingleReasonCondition = exports.JingleErrorCondition = exports.JingleAction = exports.JingleContentSenders = exports.JingleApplicationDirection = exports.JingleSessionRole = exports.ChatState = exports.PubsubErrorCondition = exports.MUCStatusCode = exports.MUCRole = exports.MUCAffiliation = exports.DataFormFieldType = exports.DataFormType = exports.RosterSubscription = exports.PresenceShow = exports.IQType = exports.PresenceType = exports.MessageType = exports.StanzaErrorCondition = exports.StreamErrorCondition = exports.SASLFailureCondition = exports.StreamType = exports.VERSION = void 0;
4
4
  const Namespaces_1 = require("./Namespaces");
5
- exports.VERSION = '12.17.1';
5
+ exports.VERSION = '12.18.0';
6
6
  // ====================================================================
7
7
  // Frequently Used Values
8
8
  // ====================================================================
package/README.md CHANGED
@@ -69,14 +69,6 @@ client.connect();
69
69
 
70
70
  MUC Room: [discuss@stanzajs.org](https://stanzajs.org/discuss/logs) / [Logs](https://stanzajs.org/discuss/logs)
71
71
 
72
- ## Related Modules
73
-
74
- These are related modules that form part of StanzaJS:
75
-
76
- | Name | Description | Source |
77
- | ------------------------------------------------------ | -------------------------------------------------------------------- | --------------------------------------------------- |
78
- | [stanza-shims](https://npmjs.org/package/stanza-shims) | Runtime shims used by StanzaJS for node, browsers, and React Native. | [Source](https://github.com/legastero/stanza-shims) |
79
-
80
72
  ## Recommended Modules
81
73
 
82
74
  These are some additional modules that are highly recommended for use with StanzaJS:
package/Utils.d.ts CHANGED
@@ -8,6 +8,8 @@
8
8
  */
9
9
  /// <reference types="node" />
10
10
  export declare function timeoutPromise<T>(target: Promise<T>, delay: number, rejectValue?: () => any): Promise<T>;
11
+ export declare function promiseAny<T>(promises: Array<Promise<T>>): Promise<T>;
12
+ export declare function shuffle<T>(array: T[]): T[];
11
13
  export declare function sleep(time: number): Promise<void>;
12
14
  export declare function octetCompare(str1: string | Buffer, str2: string | Buffer): number;
13
15
  export declare function uuid(): string;
package/Utils.js CHANGED
@@ -8,9 +8,9 @@
8
8
  * - uuid, Copyright (c) 2010-2016 Robert Kieffer and other contributors
9
9
  */
10
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
- exports.reviveData = exports.uuid = exports.octetCompare = exports.sleep = exports.timeoutPromise = void 0;
11
+ exports.reviveData = exports.uuid = exports.octetCompare = exports.sleep = exports.shuffle = exports.promiseAny = exports.timeoutPromise = void 0;
12
12
  // tslint:disable no-bitwise
13
- const stanza_shims_1 = require("stanza-shims");
13
+ const platform_1 = require("./platform");
14
14
  const bth = [];
15
15
  for (let i = 0; i < 256; ++i) {
16
16
  bth[i] = (i + 0x100).toString(16).substr(1);
@@ -27,6 +27,30 @@ async function timeoutPromise(target, delay, rejectValue = () => undefined) {
27
27
  return result;
28
28
  }
29
29
  exports.timeoutPromise = timeoutPromise;
30
+ async function promiseAny(promises) {
31
+ try {
32
+ const errors = await Promise.all(promises.map(p => {
33
+ return p.then(val => Promise.reject(val), err => Promise.resolve(err));
34
+ }));
35
+ return Promise.reject(errors);
36
+ }
37
+ catch (val) {
38
+ return Promise.resolve(val);
39
+ }
40
+ }
41
+ exports.promiseAny = promiseAny;
42
+ function shuffle(array) {
43
+ let end = array.length;
44
+ while (end > 0) {
45
+ const selected = Math.floor(Math.random() * end);
46
+ end -= 1;
47
+ const tmp = array[end];
48
+ array[end] = array[selected];
49
+ array[selected] = tmp;
50
+ }
51
+ return array;
52
+ }
53
+ exports.shuffle = shuffle;
30
54
  async function sleep(time) {
31
55
  return new Promise(resolve => {
32
56
  setTimeout(() => resolve(), time);
@@ -34,13 +58,13 @@ async function sleep(time) {
34
58
  }
35
59
  exports.sleep = sleep;
36
60
  function octetCompare(str1, str2) {
37
- const b1 = typeof str1 === 'string' ? Buffer.from(str1, 'utf8') : str1;
38
- const b2 = typeof str2 === 'string' ? Buffer.from(str2, 'utf8') : str2;
61
+ const b1 = typeof str1 === 'string' ? platform_1.Buffer.from(str1, 'utf8') : str1;
62
+ const b2 = typeof str2 === 'string' ? platform_1.Buffer.from(str2, 'utf8') : str2;
39
63
  return b1.compare(b2);
40
64
  }
41
65
  exports.octetCompare = octetCompare;
42
66
  function uuid() {
43
- const buf = stanza_shims_1.randomBytes(16);
67
+ const buf = platform_1.randomBytes(16);
44
68
  // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
45
69
  buf[6] = (buf[6] & 0x0f) | 0x40;
46
70
  buf[8] = (buf[8] & 0x3f) | 0x80;
@@ -90,7 +114,7 @@ function reviveData(key, value) {
90
114
  typeof value === 'object' &&
91
115
  value.type === 'Buffer' &&
92
116
  Array.isArray(value.data)) {
93
- return Buffer.from(value);
117
+ return platform_1.Buffer.from(value);
94
118
  }
95
119
  return value;
96
120
  }
@@ -1,11 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.verify = exports.generate = void 0;
4
- const tslib_1 = require("tslib");
5
- const Hashes = tslib_1.__importStar(require("stanza-shims"));
4
+ const platform_1 = require("../platform");
6
5
  const Utils_1 = require("../Utils");
7
6
  function escape(value) {
8
- return Buffer.from(value.replace(/</g, '&lt;'), 'utf-8');
7
+ return platform_1.Buffer.from(value.replace(/</g, '&lt;'), 'utf-8');
9
8
  }
10
9
  function encodeIdentities(identities = []) {
11
10
  const result = [];
@@ -115,7 +114,7 @@ function encodeForms(extensions = []) {
115
114
  }
116
115
  function generate(info, hashName) {
117
116
  const S = [];
118
- const separator = Buffer.from('<', 'utf8');
117
+ const separator = platform_1.Buffer.from('<', 'utf8');
119
118
  const append = (b1) => {
120
119
  S.push(b1);
121
120
  S.push(separator);
@@ -135,7 +134,7 @@ function generate(info, hashName) {
135
134
  for (const form of extensions) {
136
135
  append(form);
137
136
  }
138
- return Hashes.createHash(hashName).update(Buffer.concat(S)).digest('base64');
137
+ return platform_1.createHash(hashName).update(platform_1.Buffer.concat(S)).digest('base64');
139
138
  }
140
139
  exports.generate = generate;
141
140
  function verify(info, hashName, check) {
@@ -0,0 +1,36 @@
1
+ import { XRD } from '../protocol/xrd';
2
+ export interface Candidate {
3
+ host: string;
4
+ port: number;
5
+ secure?: boolean;
6
+ }
7
+ export interface DNSOptions {
8
+ srvType?: string;
9
+ srvTypeSecure?: string;
10
+ }
11
+ export interface SRVRecord {
12
+ name: string;
13
+ port: number;
14
+ priority: number;
15
+ weight: number;
16
+ secure?: boolean;
17
+ used?: boolean;
18
+ runningSum?: number;
19
+ id?: number;
20
+ }
21
+ export interface SRVResult {
22
+ records: SRVRecord[];
23
+ allowFallback: boolean;
24
+ }
25
+ export default class NetworkDiscovery {
26
+ private resolver?;
27
+ private registry;
28
+ private hostMetaCache;
29
+ private hostMetaTTL;
30
+ constructor();
31
+ getHostMeta(domain: string): Promise<XRD>;
32
+ resolveTXT(domain: string): Promise<string[][]>;
33
+ resolve(domain: string, defaultPort: number, opts?: DNSOptions): Promise<Candidate[]>;
34
+ resolveWeightedSRV(domain: string, srvType: string, srvTypeSecure?: string): Promise<SRVResult>;
35
+ resolveSRV(domain: string, srvType: string, secure?: boolean): Promise<SRVResult>;
36
+ }
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const platform_1 = require("../platform");
5
+ const Utils_1 = require("../Utils");
6
+ const jxt_1 = require("../jxt");
7
+ const xrd_1 = tslib_1.__importDefault(require("../protocol/xrd"));
8
+ class NetworkDiscovery {
9
+ constructor() {
10
+ this.hostMetaCache = new Map();
11
+ this.hostMetaTTL = 30000;
12
+ this.resolver = platform_1.createResolver();
13
+ this.registry = new jxt_1.Registry();
14
+ this.registry.define(xrd_1.default);
15
+ }
16
+ async getHostMeta(domain) {
17
+ const cached = this.hostMetaCache.get(domain);
18
+ if (cached) {
19
+ if (cached.created + this.hostMetaTTL < Date.now()) {
20
+ return cached.hostmeta;
21
+ }
22
+ else {
23
+ this.hostMetaCache.delete(domain);
24
+ }
25
+ }
26
+ const hostmeta = Utils_1.promiseAny([
27
+ platform_1.fetch(`https://${domain}/.well-known/host-meta.json`).then(async (res) => {
28
+ if (!res.ok) {
29
+ throw new Error('could-not-fetch-json');
30
+ }
31
+ return res.json();
32
+ }),
33
+ platform_1.fetch(`https://${domain}/.well-known/host-meta`).then(async (res) => {
34
+ if (!res.ok) {
35
+ throw new Error('could-not-fetch-xml');
36
+ }
37
+ const data = await res.text();
38
+ const xml = jxt_1.parse(data);
39
+ if (xml) {
40
+ return this.registry.import(xml);
41
+ }
42
+ else {
43
+ throw new Error('could-not-import-xml');
44
+ }
45
+ })
46
+ ]);
47
+ this.hostMetaCache.set(domain, { created: Date.now(), hostmeta });
48
+ hostmeta.catch(() => {
49
+ this.hostMetaCache.delete(domain);
50
+ });
51
+ return hostmeta;
52
+ }
53
+ async resolveTXT(domain) {
54
+ var _a, _b;
55
+ return (_b = (_a = this.resolver) === null || _a === void 0 ? void 0 : _a.resolveTxt(domain)) !== null && _b !== void 0 ? _b : [];
56
+ }
57
+ async resolve(domain, defaultPort, opts = {}) {
58
+ if (!this.resolver) {
59
+ return [];
60
+ }
61
+ let candidates = [];
62
+ let allowFallback = true;
63
+ if (opts.srvType) {
64
+ const srvResults = await this.resolveWeightedSRV(domain, opts.srvType, opts.srvTypeSecure);
65
+ allowFallback = srvResults.allowFallback;
66
+ candidates = srvResults.records.map(record => ({
67
+ host: record.name,
68
+ port: record.port,
69
+ secure: record.secure
70
+ }));
71
+ }
72
+ if (allowFallback) {
73
+ candidates.push({ host: domain, port: defaultPort });
74
+ }
75
+ return candidates;
76
+ }
77
+ async resolveWeightedSRV(domain, srvType, srvTypeSecure) {
78
+ const [records, secureRecords] = await Promise.all([
79
+ this.resolveSRV(domain, srvType),
80
+ srvTypeSecure
81
+ ? this.resolveSRV(domain, srvTypeSecure, true)
82
+ : Promise.resolve({ records: [], allowFallback: false })
83
+ ]);
84
+ const allRecords = [...records.records, ...secureRecords.records];
85
+ const priorities = new Map();
86
+ let id = 0;
87
+ for (const record of allRecords) {
88
+ record.id = id++;
89
+ record.runningSum = 0;
90
+ if (!priorities.has(record.priority)) {
91
+ priorities.set(record.priority, []);
92
+ }
93
+ const priorityGroup = priorities.get(record.priority);
94
+ priorityGroup.push(record);
95
+ }
96
+ const weightRecords = (unweightedRecords) => {
97
+ const sorted = [];
98
+ while (sorted.length < unweightedRecords.length) {
99
+ const ordered = Utils_1.shuffle(unweightedRecords.filter(record => record.weight === 0 && !record.used));
100
+ const unordered = Utils_1.shuffle(unweightedRecords.filter(record => {
101
+ return record.weight !== 0 && !record.used;
102
+ }));
103
+ let weightSum = 0;
104
+ for (const record of unordered) {
105
+ weightSum += record.weight;
106
+ record.runningSum = weightSum;
107
+ ordered.push(record);
108
+ }
109
+ const selector = Math.floor(Math.random() * (weightSum + 1));
110
+ for (const record of ordered) {
111
+ if (record.runningSum >= selector) {
112
+ record.used = true;
113
+ sorted.push(record);
114
+ break;
115
+ }
116
+ }
117
+ }
118
+ return sorted;
119
+ };
120
+ let sortedRecords = [];
121
+ for (const priority of Array.from(priorities.keys()).sort((a, b) => a < b ? -1 : a > b ? 1 : 0)) {
122
+ const priorityGroup = priorities.get(priority);
123
+ sortedRecords = sortedRecords.concat(weightRecords(priorityGroup));
124
+ }
125
+ return {
126
+ records: sortedRecords,
127
+ allowFallback: records.allowFallback
128
+ };
129
+ }
130
+ async resolveSRV(domain, srvType, secure) {
131
+ var _a, _b;
132
+ try {
133
+ const records = (_b = (await ((_a = this.resolver) === null || _a === void 0 ? void 0 : _a.resolveSrv(`${srvType}.${domain}`)))) !== null && _b !== void 0 ? _b : [];
134
+ if (records.length === 1 && (records[0].name === '.' || records[0].name === '')) {
135
+ return { records: [], allowFallback: false };
136
+ }
137
+ return {
138
+ records: records
139
+ .map(record => ({ secure, ...record }))
140
+ .filter(record => record.name !== '' && record.name !== '.'),
141
+ allowFallback: false
142
+ };
143
+ }
144
+ catch (_c) {
145
+ return {
146
+ records: [],
147
+ allowFallback: true
148
+ };
149
+ }
150
+ }
151
+ }
152
+ exports.default = NetworkDiscovery;
package/helpers/RSM.d.ts CHANGED
@@ -18,9 +18,15 @@ export declare class ResultSetPager<T> {
18
18
  private direction;
19
19
  private reverse;
20
20
  private pageSize;
21
+ private resultCount?;
22
+ private resultComplete;
23
+ private fetchedCount;
24
+ private yieldedCount;
21
25
  constructor(opts: RSMOptions<T>);
22
26
  [Symbol.asyncIterator](): AsyncGenerator<T>;
23
27
  size(): Promise<number | undefined>;
28
+ queryCompleted(): boolean;
29
+ finished(): boolean;
24
30
  private fetchPage;
25
31
  }
26
32
  export declare function createPager<T>(opts: RSMOptions<T>): ResultSetPager<T>;
package/helpers/RSM.js CHANGED
@@ -4,6 +4,9 @@ exports.createPager = exports.ResultSetPager = void 0;
4
4
  class ResultSetPager {
5
5
  constructor(opts) {
6
6
  var _a, _b, _c;
7
+ this.resultComplete = false;
8
+ this.fetchedCount = 0;
9
+ this.yieldedCount = 0;
7
10
  this.cursor = { first: opts.before, last: opts.after };
8
11
  this.query = opts.query;
9
12
  this.direction = (_a = opts.direction) !== null && _a !== void 0 ? _a : 'forward';
@@ -15,14 +18,25 @@ class ResultSetPager {
15
18
  do {
16
19
  currentResults = await this.fetchPage();
17
20
  for (const item of currentResults) {
21
+ this.yieldedCount += 1;
18
22
  yield item;
19
23
  }
20
24
  } while (currentResults.length > 0);
21
25
  }
22
26
  async size() {
27
+ if (this.resultCount !== undefined) {
28
+ return this.resultCount;
29
+ }
23
30
  const { paging } = await this.query({ max: 0 });
31
+ this.resultCount = paging.count;
24
32
  return paging.count;
25
33
  }
34
+ queryCompleted() {
35
+ return this.resultComplete;
36
+ }
37
+ finished() {
38
+ return this.resultComplete && this.yieldedCount === this.fetchedCount;
39
+ }
26
40
  async fetchPage() {
27
41
  var _a;
28
42
  const { results, paging } = await this.query({
@@ -31,6 +45,12 @@ class ResultSetPager {
31
45
  max: this.pageSize
32
46
  });
33
47
  this.cursor = paging;
48
+ this.resultCount = paging.count;
49
+ this.fetchedCount += results.length;
50
+ if ((this.pageSize && results.length < this.pageSize) ||
51
+ (this.resultCount && this.fetchedCount === this.resultCount)) {
52
+ this.resultComplete = true;
53
+ }
34
54
  if (this.reverse) {
35
55
  results.reverse();
36
56
  }
package/index.d.ts CHANGED
@@ -3,6 +3,7 @@ import { EventEmitter } from 'events';
3
3
  import Client from './Client';
4
4
  import * as Constants from './Constants';
5
5
  import * as RTT from './helpers/RTT';
6
+ import NetworkDiscovery from './helpers/NetworkDiscovery';
6
7
  import SM from './helpers/StreamManagement';
7
8
  import * as JID from './JID';
8
9
  import * as Jingle from './jingle';
@@ -13,6 +14,7 @@ import * as Namespaces from './Namespaces';
13
14
  import * as Stanzas from './protocol';
14
15
  import { CSI, IQ, Message, Presence, SASL, Stream, StreamError, StreamFeatures, StreamManagement } from './protocol';
15
16
  import * as Utils from './Utils';
17
+ import * as Platform from './platform';
16
18
  export * from './helpers/StreamManagement';
17
19
  export interface TopLevelElements {
18
20
  message: Message;
@@ -102,9 +104,13 @@ export interface Agent extends StrictEventEmitter<EventEmitter, AgentEvents> {
102
104
  sm: SM;
103
105
  sasl: LibSASL.Factory;
104
106
  stanzas: JXT.Registry;
107
+ resolver: NetworkDiscovery;
105
108
  sessionStarting: boolean;
106
109
  sessionStarted: boolean;
107
110
  sessionTerminating: boolean;
111
+ transports: {
112
+ [key: string]: new (client: Agent, sm: StreamManagement, registry: JXT.Registry) => Transport;
113
+ };
108
114
  use(plugin: (agent: Agent, registry: JXT.Registry, config: AgentConfig) => void): void;
109
115
  nextId(): string;
110
116
  updateConfig(opts?: AgentConfig): void;
@@ -177,14 +183,21 @@ export interface AgentConfig {
177
183
  *
178
184
  * If a transport is set to a string, that will be used as the connection URL.
179
185
  *
180
- * If a transport is set to an object, it MUST include a <code>url</code> value for
181
- * the connection URL.
182
- *
183
186
  * @default { websocket: true, bosh: true }
184
187
  */
185
188
  transports?: {
186
189
  [key: string]: boolean | string | Partial<TransportConfig>;
187
190
  };
191
+ /**
192
+ * Transport Preference Order
193
+ *
194
+ * Specify the order in which transports should be tried when connecting.
195
+ *
196
+ * If a configured transport type is not listed, it will be skipped.
197
+ *
198
+ * @default ['websocket', 'bosh']
199
+ */
200
+ transportPreferenceOrder?: string[];
188
201
  /**
189
202
  * Account Password
190
203
  *
@@ -208,17 +221,18 @@ export interface Transport {
208
221
  hasStream?: boolean;
209
222
  stream?: Stream;
210
223
  authenticated?: boolean;
224
+ discoverBindings?(host: string): Promise<Partial<TransportConfig> | null>;
211
225
  connect(opts: TransportConfig): void;
212
226
  disconnect(cleanly?: boolean): void;
213
227
  restart(): void;
214
228
  send(name: string, data?: JXT.JSONData): Promise<void>;
215
229
  }
216
230
  export interface TransportConfig {
217
- lang?: string;
218
- acceptLanguages?: string[];
219
231
  server: string;
220
- url: string;
221
232
  jid: string;
233
+ lang?: string;
234
+ acceptLanguages?: string[];
235
+ url?: string;
222
236
  sid?: string;
223
237
  rid?: number;
224
238
  maxRetries?: number;
@@ -227,7 +241,7 @@ export interface TransportConfig {
227
241
  }
228
242
  import * as RSM from './helpers/RSM';
229
243
  import * as DataForms from './helpers/DataForms';
230
- export { Client, Constants, DataForms, JXT, JID, Namespaces, Stanzas, Jingle, Utils, RSM, RTT, LibSASL as SASL };
244
+ export { Client, Constants, DataForms, JXT, JID, Namespaces, Stanzas, Jingle, Utils, RSM, RTT, LibSASL as SASL, Platform };
231
245
  export declare const VERSION = "__STANZAJS_VERSION__";
232
246
  export * from './plugins';
233
247
  export declare function createClient(opts: AgentConfig): Agent;
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createClient = exports.VERSION = exports.SASL = exports.RTT = exports.RSM = exports.Utils = exports.Jingle = exports.Stanzas = exports.Namespaces = exports.JID = exports.JXT = exports.DataForms = exports.Constants = exports.Client = void 0;
3
+ exports.createClient = exports.VERSION = exports.Platform = exports.SASL = exports.RTT = exports.RSM = exports.Utils = exports.Jingle = exports.Stanzas = exports.Namespaces = exports.JID = exports.JXT = exports.DataForms = exports.Constants = exports.Client = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const Client_1 = tslib_1.__importDefault(require("./Client"));
6
6
  exports.Client = Client_1.default;
@@ -22,6 +22,8 @@ const Stanzas = tslib_1.__importStar(require("./protocol"));
22
22
  exports.Stanzas = Stanzas;
23
23
  const Utils = tslib_1.__importStar(require("./Utils"));
24
24
  exports.Utils = Utils;
25
+ const Platform = tslib_1.__importStar(require("./platform"));
26
+ exports.Platform = Platform;
25
27
  tslib_1.__exportStar(require("./helpers/StreamManagement"), exports);
26
28
  const RSM = tslib_1.__importStar(require("./helpers/RSM"));
27
29
  exports.RSM = RSM;
@@ -0,0 +1,23 @@
1
+ import Client from './Client';
2
+ import * as Constants from './Constants';
3
+ import * as RTT from './helpers/RTT';
4
+ import * as JID from './JID';
5
+ import * as Jingle from './jingle';
6
+ import * as JXT from './jxt';
7
+ import * as LibSASL from './lib/sasl';
8
+ import * as Namespaces from './Namespaces';
9
+ import * as Stanzas from './protocol';
10
+ import * as Utils from './Utils';
11
+ import * as Platform from './platform';
12
+ export * from './helpers/StreamManagement';
13
+ import * as RSM from './helpers/RSM';
14
+ import * as DataForms from './helpers/DataForms';
15
+ export { Client, Constants, DataForms, JXT, JID, Namespaces, Stanzas, Jingle, Utils, RSM, RTT, LibSASL as SASL, Platform };
16
+ export const VERSION = Constants.VERSION;
17
+ import Plugins from './plugins';
18
+ export * from './plugins';
19
+ export function createClient(opts) {
20
+ const client = new Client(opts);
21
+ client.use(Plugins);
22
+ return client;
23
+ }
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  import { EventEmitter } from 'events';
3
- import * as Hashes from 'stanza-shims';
3
+ import * as Hashes from '../platform';
4
4
  import { FileDescription, Hash, Jingle } from '../protocol';
5
5
  import ICESession, { ICESessionOpts } from './ICESession';
6
6
  import { ActionCallback } from './Session';