├── .gitignore ├── .vscode └── files.exclude ├── README.md ├── app ├── jitsi-test.ts ├── sine-wave.js └── test-sdp.ts ├── package.json ├── src ├── JingleSDP.ts ├── JitsiClient.ts ├── Logger.ts ├── index.ts └── xmpp │ ├── BoshConnection.ts │ ├── BoshParser.ts │ ├── BoshSessionData.ts │ ├── DiscoInfoResponse.ts │ └── JitsiPresence.ts ├── tsconfig.json ├── types └── sdp-jingle-json.d.ts └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | lib/ 2 | node_modules/ 3 | package-lock.json 4 | *.log 5 | -------------------------------------------------------------------------------- /.vscode/files.exclude: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "**/*.js": { "when": "$(basename).ts" }, 4 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | node-jitsi 2 | ========== 3 | 4 | Participate in Jiti Meet calls without requiring a browser! 5 | 6 | This project aims to implement the ability to join Jitsi Meet conferences, 7 | with full support for bi-directional audio and video. 8 | 9 | Currently the project has just started out and is missing nearly everything 10 | required to get anything working, however progress is being made. 11 | 12 | If you want to use Jitsi Meet in a browser context, [jitsi/lib-jitsi-meet](https://github.com/jitsi/lib-jitsi-meet) 13 | exists as an excellent starting place. This project only aims to run in a Node.JS environment. 14 | 15 | ## Setup 16 | 17 | Currently, this is left as an exercise to the user as the library lacks 18 | pretty much everything you might want. However, it's a typescript node app 19 | so setting it up will be fairly standard. 20 | 21 | ## Milestones 22 | 23 | A set of very high level milestones for the project: 24 | 25 | - [x] Join Jitsi Meet conferences 26 | - [x] Over TCP (normal XMPP) 27 | - [ ] Over BOSH 28 | - [ ] Send messages in conference rooms 29 | - [ ] Listen to audio 30 | - [ ] Send audio 31 | - [ ] View video 32 | - [ ] Send video 33 | 34 | ## Support 35 | 36 | Come visit us at [#node-jitsi:half-shot.uk](https://matrix.to/#/#node-jitsi:half-shot.uk)! -------------------------------------------------------------------------------- /app/jitsi-test.ts: -------------------------------------------------------------------------------- 1 | import { JitsiClient } from "../src/JitsiClient"; 2 | import { RTCAudioSourceSineWave } from "./sine-wave"; 3 | import { FancyLogger } from "../src"; 4 | // Allow self signed 5 | const EVIL_GOOGLE_ICE_SERVERS = [ 6 | { urls: 'stun:stun.l.google.com:19302' }, 7 | { urls: 'stun:stun1.l.google.com:19302' }, 8 | { urls: 'stun:stun2.l.google.com:19302' } 9 | ]; 10 | 11 | process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = '0'; 12 | let jitsiClient: JitsiClient; 13 | async function main() { 14 | jitsiClient = new JitsiClient("xmpp://jitsi.modular.im", "jitsi.modular.im", "conference.jitsi.modular.im", { 15 | logger: (s) => new FancyLogger(s), 16 | iceServers: EVIL_GOOGLE_ICE_SERVERS, 17 | nick: "Testing node-jitsi", 18 | email: "gravatar@half-shot.uk", 19 | }); 20 | jitsiClient.addSource(new RTCAudioSourceSineWave()); 21 | jitsiClient.once('error', (ex) => { 22 | console.error('Encountered a fatal error, exiting'); 23 | process.exit(1); 24 | }); 25 | await jitsiClient.connect(); 26 | await jitsiClient.joinConference('testingbridge2'); 27 | } 28 | 29 | main().catch((ex) => { 30 | console.error("Failed:", ex); 31 | process.exit(1); 32 | }) 33 | 34 | process.on("beforeExit", () => { 35 | jitsiClient.disconnect(); 36 | }); -------------------------------------------------------------------------------- /app/sine-wave.js: -------------------------------------------------------------------------------- 1 | const { RTCAudioSource } = require('wrtc').nonstandard; 2 | 3 | const twoPi = 2 * Math.PI; 4 | 5 | export class RTCAudioSourceSineWave { 6 | constructor(options) { 7 | options = { 8 | frequency: 440, 9 | channelCount: 1, 10 | panning: null, 11 | sampleRate: 48000, 12 | schedule: setTimeout, 13 | unschedule: clearTimeout, 14 | ...options 15 | }; 16 | 17 | const { 18 | channelCount, 19 | sampleRate 20 | } = options; 21 | 22 | if (channelCount !== 1 && channelCount !== 2) { 23 | throw new Error('channelCount must be 1 or 2'); 24 | } 25 | 26 | const bitsPerSample = 16; 27 | const maxValue = Math.pow(2, bitsPerSample) / 2 - 1; 28 | const numberOfFrames = sampleRate / 100; 29 | const secondsPerSample = 1 / sampleRate; 30 | const source = new RTCAudioSource(); 31 | const samples = new Int16Array(channelCount * numberOfFrames); 32 | 33 | const data = { 34 | samples, 35 | sampleRate, 36 | bitsPerSample, 37 | channelCount, 38 | numberOfFrames 39 | }; 40 | 41 | const a = [1, 1]; 42 | 43 | let { 44 | frequency, 45 | panning 46 | } = options; 47 | 48 | let time = 0; 49 | 50 | function next() { 51 | for (let i = 0; i < numberOfFrames; i++, time += secondsPerSample) { 52 | for (let j = 0; j < channelCount; j++) { 53 | samples[i * channelCount + j] = a[j] * Math.sin(twoPi * frequency * time) * maxValue; 54 | } 55 | } 56 | source.onData(data); 57 | // eslint-disable-next-line 58 | scheduled = options.schedule(next); 59 | } 60 | 61 | let scheduled = options.schedule(next); 62 | 63 | this.close = () => { 64 | options.unschedule(scheduled); 65 | scheduled = null; 66 | }; 67 | 68 | this.createTrack = () => { 69 | return source.createTrack(); 70 | }; 71 | 72 | this.setFrequency = newFrequency => { 73 | frequency = newFrequency; 74 | }; 75 | 76 | this.setPanning = newPanning => { 77 | if (channelCount === 1) { 78 | return; 79 | } 80 | panning = newPanning; 81 | a[0] = 1 - (panning / 100); 82 | a[1] = 1 - ((100 - panning) / 100); 83 | }; 84 | 85 | this.setPanning(panning); 86 | 87 | Object.defineProperties(this, { 88 | frequency: { 89 | get() { 90 | return frequency; 91 | } 92 | }, 93 | panning: { 94 | get() { 95 | return panning; 96 | } 97 | } 98 | }); 99 | } 100 | } -------------------------------------------------------------------------------- /app/test-sdp.ts: -------------------------------------------------------------------------------- 1 | import { Parser } from "@xmpp/xml"; 2 | import { Jingle2SDP } from "../src/JingleSDP"; 3 | 4 | import { readFile } from "fs"; 5 | 6 | const parser = new Parser(); 7 | parser.on("element", (e) => { 8 | if (e.is("jingle")) { 9 | const res = Jingle2SDP(e, "ressp", "responder", "incoming"); 10 | console.log(res); 11 | } 12 | }) 13 | 14 | readFile('examples/session-initiate.xml', (err, data) => { 15 | console.log(err); 16 | parser.write(data); 17 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-jitsi", 3 | "version": "0.0.1", 4 | "description": "A Node.JS client library for Jitsi Meet", 5 | "main": "lib/index.js\\", 6 | "author": "Half-Shot", 7 | "license": "MIT", 8 | "private": false, 9 | "scripts": { 10 | "build": "tsc" 11 | }, 12 | "dependencies": { 13 | "@xmpp/client": "^0.11.1", 14 | "@xmpp/connection": "^0.11.0", 15 | "axios": "^0.19.2", 16 | "chalk": "^4.0.0", 17 | "sdp-jingle-json": "^3.1.0", 18 | "uuid": "^7.0.3", 19 | "wrtc": "^0.4.4" 20 | }, 21 | "devDependencies": { 22 | "@types/node": "^12", 23 | "@types/webrtc": "0.0.26", 24 | "@types/xmpp__jid": "^1.3.0", 25 | "@types/xmpp__xml": "^0.6.0", 26 | "source-map-support": "^0.5.16", 27 | "typescript": "^3.8.3" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/JingleSDP.ts: -------------------------------------------------------------------------------- 1 | import { Element, x } from "@xmpp/xml"; 2 | import { toSessionSDP, toSessionJSON } from 'sdp-jingle-json'; 3 | 4 | export function Jingle2SDP(jingleElement: Element, responder: string, role: string, direction: string) { 5 | const groups = jingleElement.getChildren("group")!.map((groupEl) => ({ 6 | semantics: groupEl.getAttr('semantics'), 7 | contents: groupEl.getChildren("content").map((el) => el.getAttr('name')), 8 | })); 9 | 10 | console.log(jingleElement.toString()); 11 | const contents = jingleElement.getChildren("content").map((e) => { 12 | const name = e.getAttr("name"); 13 | const descriptionElement = e.getChild("description")!; 14 | const sources = descriptionElement.getChildren("sources").map((srcE) => ({ 15 | ssrc: srcE.getAttr("ssrc"), 16 | parameters: srcE.getChildren("parameter").map((param) => ({ 17 | key: param.getAttr("name"), 18 | value: param.getAttr("value"), 19 | })), 20 | })); 21 | const headerExtensions = descriptionElement.getChildren("rtp-hdrext").map((extE) => ({ 22 | id: extE.getAttr("id"), 23 | uri: extE.getAttr("uri"), 24 | })); 25 | const payloads = descriptionElement.getChildren("payload-type").map((payloadType) => ({ 26 | id: payloadType.getAttr("id"), 27 | channels: payloadType.getAttr("channels"), 28 | clockrate: payloadType.getAttr("clockrate"), 29 | maxptime: descriptionElement.getAttr("maxptime"), 30 | name: payloadType.getAttr("name"), 31 | parameters: payloadType.getChildren("payload-type").map((params) => ({ 32 | key: params.getAttr("key"), 33 | value: params.getAttr("value"), 34 | })), 35 | feedback: payloadType.getChildren("rtcp-fb").map((params) => ({ 36 | type: params.getAttr("type"), 37 | subtype: params.getAttr("subtype"), 38 | })) 39 | // Do not parse any payloads with rtx. 40 | })).filter((p) => p.name !== 'rtx'); 41 | const sourceGroups = descriptionElement.getChildren("ssrc-group").map((ssrcGroup) => ({ 42 | semantics: ssrcGroup.getAttr("semantics"), 43 | sources: ssrcGroup.getChildren("source").map((e) => e.getAttr("ssrc")), 44 | })); 45 | const application = { 46 | encryption: [], 47 | sourceGroups, 48 | // bandwidth: { 49 | // type: 50 | // bandwidth: 51 | // } 52 | // More hacky naughiness 53 | applicationType: name === "data" ? "datachannel" : "rtp", 54 | media: descriptionElement.getAttr("media"), 55 | sources, 56 | headerExtensions, 57 | payloads, 58 | mux: !!descriptionElement.getChild("rtcp-mux"), 59 | } 60 | 61 | const transportElement = e.getChild("transport")!; 62 | const transport: any = { 63 | transportType: "iceUdp", 64 | ufrag: transportElement.getAttr("ufrag"), 65 | pwd: transportElement.getAttr("pwd"), 66 | mux: !!transportElement.getChild("rtcp-mux"), 67 | setup: transportElement.getChild("fingerprint")?.getAttr("setup"), 68 | candidates: transportElement.getChildren("candidate").map((candidate) => ({ 69 | component: candidate.getAttr("component"), 70 | foundation: candidate.getAttr("foundation"), 71 | type: candidate.getAttr("type"), 72 | generation: candidate.getAttr("generation"), 73 | ip: candidate.getAttr("ip"), 74 | priority: candidate.getAttr("priority"), 75 | id: candidate.getAttr("id"), 76 | network: candidate.getAttr("network"), 77 | protocol: candidate.getAttr("protocol"), 78 | port: candidate.getAttr("port"), 79 | })), 80 | fingerprints: transportElement.getChildren("fingerprint").map((fp) => ({ 81 | setup: fp.getAttr("setup"), 82 | hash: fp.getAttr("hash"), 83 | value: fp.getText(), 84 | })), 85 | sctp: [], 86 | } 87 | const sctpmap = transportElement.getChildren("sctpmap"); 88 | if (sctpmap.length) { 89 | transport.sctp.push(...sctpmap.map((e) => ({ 90 | number: e.getAttr("number"), 91 | protocol: e.getAttr("protocol"), 92 | streams: e.getAttr("streams"), 93 | }))); 94 | } 95 | return { 96 | name, 97 | creator: e.getAttr("creator"), 98 | senders: e.getAttr("senders"), 99 | application, 100 | transport, 101 | } 102 | }); 103 | 104 | const sdpObject = { 105 | action: jingleElement.attr("action"), 106 | initiator: jingleElement.attr("initiator"), 107 | responder, 108 | sid: jingleElement.attr("sid"), 109 | // ---- Content payload 110 | groups: groups, 111 | contents: contents, 112 | }; 113 | 114 | return toSessionSDP(sdpObject, {role, direction}); 115 | } 116 | 117 | /*** 118 | * 119 | contents: [ 120 | { 121 | creator: 'responder', 122 | name: 'audio', 123 | application: [Object], 124 | transport: [Object], 125 | senders: 'initiator' 126 | }, 127 | { 128 | creator: 'initiator', 129 | name: 'video', 130 | application: [Object], 131 | transport: [Object], 132 | senders: 'initiator' 133 | } 134 | ], 135 | groups: [ { semantics: 'BUNDLE', contents: [Array] } ] 136 | } 137 | */ 138 | 139 | function SdpContentToElement(content) { 140 | const contentElement = x("content", { 141 | creator: content.creator, 142 | name: content.name, 143 | senders: content.senders, 144 | }); 145 | const descriptionElement = x("description", { 146 | media: content.application.media, 147 | ssrc: content.application.ssrc, 148 | xmlns: "urn:xmpp:jingle:apps:rtp:1", 149 | }); 150 | if (content.application.mux) { 151 | descriptionElement.append(x('rtcp-mux')); 152 | } 153 | // Payloads not defined for data channels 154 | (content.application.payloads || []).forEach((payload) => { 155 | const payloadElement = x("payload-type", { 156 | channels: payload.channels, 157 | clockrate: payload.clockrate, 158 | id: payload.id, 159 | name: payload.name, 160 | }); 161 | payload.parameters.forEach((params) => 162 | payloadElement.append(x("parameter", { 163 | name: params.key, 164 | value: params.value, 165 | })) 166 | ); 167 | payload.feedback.forEach((feedback) => 168 | payloadElement.append(x("rtcp-fb", { 169 | id: feedback.id, 170 | type: feedback.type, 171 | subtype: feedback.subtype, 172 | })) 173 | ); 174 | descriptionElement.append(payloadElement); 175 | }); 176 | (content.application.sources || []).forEach((source) => 177 | descriptionElement.append(x("source", { 178 | ssrc: source.ssrc, 179 | xmlns: "urn:xmpp:jingle:apps:rtp:ssma:0", 180 | }, source.parameters.map((param => x("parameter", { 181 | name: param.key, 182 | value: param.value, 183 | }))))) 184 | ); 185 | (content.application.headerExtensions || []).forEach((ext) => 186 | descriptionElement.append(x("rtp-hdrext", { 187 | id: ext.id, 188 | senders: ext.senders, 189 | uri: ext.uri, 190 | xmlns: "urn:xmpp:jingle:apps:rtp:rtp-hdrext:0", 191 | })) 192 | ); 193 | const transportElement = x("transport", { 194 | pwd: content.transport.pwd, 195 | ufrag: content.transport.ufrag, 196 | // TODO: unhardcode this. 197 | transportType: "urn:xmpp:jingle:transports:ice-udp:1", 198 | }, x("fingerprint", { 199 | hash: content.transport.hash, 200 | setup: content.transport.setup, 201 | }, content.transport.value)); 202 | content.transport.candidates.forEach((candidate) => transportElement.append(x( 203 | "candidate", 204 | candidate, 205 | ))); 206 | contentElement.append(descriptionElement); 207 | contentElement.append(transportElement); 208 | return contentElement; 209 | } 210 | 211 | // Taken from https://github.com/jitsi/lib-jitsi-meet/blob/edfad5f51186d70c645c1c05ece88822c2486dc7/modules/xmpp/SDPUtil.js#L399 212 | export function candidateFromJingle(cand: Element) { 213 | let line = 'a=candidate:'; 214 | 215 | line += cand.attr('foundation'); 216 | line += ' '; 217 | line += cand.attr('component'); 218 | line += ' '; 219 | 220 | let protocol = cand.attr('protocol'); 221 | 222 | line += protocol; // .toUpperCase(); // chrome M23 doesn't like this 223 | line += ' '; 224 | line += cand.attr('priority'); 225 | line += ' '; 226 | line += cand.attr('ip'); 227 | line += ' '; 228 | line += cand.attr('port'); 229 | line += ' '; 230 | line += 'typ'; 231 | line += ` ${cand.attr('type')}`; 232 | line += ' '; 233 | switch (cand.attr('type')) { 234 | case 'srflx': 235 | case 'prflx': 236 | case 'relay': 237 | if (cand.attr('rel-addr') 238 | && cand.attr('rel-port')) { 239 | line += 'raddr'; 240 | line += ' '; 241 | line += cand.attr('rel-addr'); 242 | line += ' '; 243 | line += 'rport'; 244 | line += ' '; 245 | line += cand.attr('rel-port'); 246 | line += ' '; 247 | } 248 | break; 249 | } 250 | if (protocol.toLowerCase() === 'tcp') { 251 | line += 'tcptype'; 252 | line += ' '; 253 | line += cand.attr('tcptype'); 254 | line += ' '; 255 | } 256 | line += 'generation'; 257 | line += ' '; 258 | line += cand.attr('generation') || '0'; 259 | 260 | return `${line}\r\n`; 261 | } 262 | 263 | export function SDP2Jingle(sdpBlob: string, role: string, direction: string) { 264 | const sdp = toSessionJSON(sdpBlob, { 265 | role, 266 | direction, 267 | creators: ["responder", "responder"], // One for audio, one for video. 268 | }); 269 | const jingleElement = x("jingle", { 270 | xmlns: "urn:xmpp:jingle:1", 271 | }); 272 | sdp.groups.forEach(group => { 273 | jingleElement.append(x("group", { 274 | semantics: group.semantics, 275 | }, group.contents.map(name => x("content", { name })) 276 | )); 277 | }); 278 | sdp.contents.forEach(content => jingleElement.append(SdpContentToElement(content))); 279 | return jingleElement; 280 | } 281 | 282 | export function candidatesToJingle(candidates: RTCIceCandidate[]) { 283 | const ufrag = candidates[0].usernameFragment; 284 | const name = candidates[0].sdpMid; 285 | const transport = x("transport", { 286 | ufrag, 287 | }); 288 | candidates.forEach((candidate) => { 289 | const candidateJson = {...candidate}; 290 | delete candidateJson.candidate; 291 | transport.append(x("candidate", candidateJson)); 292 | }) 293 | const contentElem = x("content", { 294 | creator: "responder", 295 | name, // XXX: Guessing here. 296 | }, transport); 297 | return x("jingle", { 298 | action: "transport-info", 299 | xmlns: "urn:xmpp:jingle:1" 300 | }, contentElem); 301 | } -------------------------------------------------------------------------------- /src/JitsiClient.ts: -------------------------------------------------------------------------------- 1 | import { client } from "@xmpp/client"; 2 | import { JID } from "@xmpp/jid"; 3 | import { JitsiPresence, JitsiUserPresence } from "./xmpp/JitsiPresence"; 4 | import { RTCPeerConnection, RTCSessionDescription, RTCPeerConnectionIceEvent, RTCIceCandidate, nonstandard } from 'wrtc'; 5 | import xml, { Element } from "@xmpp/xml"; 6 | import { Jingle2SDP, SDP2Jingle, candidatesToJingle, candidateFromJingle } from "./JingleSDP"; 7 | import { v4 as uuid } from "uuid"; 8 | import { EventEmitter } from "events"; 9 | import { DiscoInfoResponse } from "./xmpp/DiscoInfoResponse"; 10 | import { ILogger, DummyLogger, LoggerFunc } from "./Logger"; 11 | import { url } from "inspector"; 12 | 13 | const { RTCAudioSource, RTCAudioSink } = nonstandard; 14 | 15 | export interface JitsiClientOpts { 16 | logger?: LoggerFunc, 17 | iceServers?: {urls: string}[], 18 | nick: string, 19 | email?: string, 20 | } 21 | 22 | export class JitsiClient extends EventEmitter { 23 | private client: any; 24 | private state: "offline"|"connecting"|"online"|"error"; 25 | private identity?: JID; 26 | private peerConnection?: RTCPeerConnection; 27 | private audioSink?: any; //RTCAudioSink; 28 | private remoteAudioSinks: {[trackName: string]: any} = {}; 29 | private sources: any[] = []; 30 | private remoteId?: string; 31 | private myLocalId?: string; 32 | private sid?: string; 33 | private localCandidateBatch?: RTCIceCandidate[]; 34 | private clientPresence: JitsiUserPresence; 35 | private roomName!: string; 36 | private logger: ILogger; 37 | constructor(urlOrHost: string, domain: string, private conferenceDomain: string, private opts: JitsiClientOpts) { 38 | super(); 39 | this.logger = opts.logger ? opts.logger('JitsiClient') : new DummyLogger(); 40 | if (urlOrHost.startsWith("http")) { 41 | throw Error("BOSH is not supported yet"); 42 | } 43 | this.state = "offline"; 44 | this.client = client({ 45 | service: urlOrHost, 46 | domain, 47 | }); 48 | this.client.on("error", this.onError.bind(this)); 49 | this.client.on("offline", this.onOffline.bind(this)); 50 | this.client.on("online", this.onOnline.bind(this)); 51 | this.client.on("stanza", this.onStanza.bind(this)); 52 | this.clientPresence = { 53 | audioMuted: false, 54 | videoMuted: true, 55 | email: opts.email, 56 | nick: opts.nick, 57 | handRaised: true, 58 | }; 59 | } 60 | 61 | public async connect() { 62 | this.state = "connecting"; 63 | await this.client.start(); 64 | await this.client.send(xml("presence")); 65 | } 66 | 67 | public async disconnect() { 68 | this.state = "offline"; 69 | await this.client.disconnect(); 70 | } 71 | 72 | public async joinConference(roomName: string) { 73 | this.logger.info("Joining conference", roomName); 74 | this.roomName = roomName; 75 | if (this.state !== "online" || !this.identity) { 76 | throw Error("Cannot join, not connected"); 77 | } 78 | this.client.write(new JitsiPresence( 79 | this.roomName, 80 | this.conferenceDomain, 81 | this.identity.resource, 82 | this.clientPresence, 83 | true, 84 | ).xml); 85 | } 86 | 87 | private onStanza(stanza: Element) { 88 | //this.logger.debug("XMPP RX:", stanza); 89 | let promise: Promise|null = null; 90 | if (stanza.is("iq")) { 91 | promise = this.onIq(stanza); 92 | } 93 | if (!promise) { 94 | return; 95 | } 96 | promise.catch((err) => { 97 | this.logger.debug("Failed to handle stanza:", err); 98 | }); 99 | } 100 | 101 | private async onIq(stanza: Element) { 102 | const { from, to, id } = stanza.attrs; 103 | const jingleElement = stanza.getChild("jingle"); 104 | if (!this.myLocalId) { 105 | // HACK TO DETERMINE LOCAL IDENTITY 106 | this.myLocalId = to; 107 | } 108 | if (jingleElement) { 109 | // We need to ack this immediately. 110 | this.client.write(``); 111 | return this.onJingle(jingleElement as xml.Element, from, to); 112 | } 113 | if (stanza.getChild("ping")) { 114 | return this.client.write(``) 115 | } 116 | if (stanza.getChildByAttr("xmlns", "http://jabber.org/protocol/disco#info")) { 117 | return this.client.write(new DiscoInfoResponse(id, from).xml) 118 | } 119 | this.logger.debug(stanza.toString()); 120 | } 121 | 122 | private async onRemoteIceCandidate(stanza: Element, from: string, to: string) { 123 | //https://github.com/jitsi/lib-jitsi-meet/blob/b012353d68a584086982d654f5403bc235776b4b/modules/xmpp/JingleSessionPC.js#L749-L770 124 | stanza.getChildren("content").forEach((content) => { 125 | const transport = content.getChild("transport"); 126 | const usernameFragment = transport?.attrs.ufrag; 127 | content.getChild("transport")?.getChildren("candidate").forEach((candidateElem) => { 128 | let line = candidateFromJingle(candidateElem as Element); 129 | line = line.replace('\r\n', '').replace('a=', ''); 130 | 131 | // FIXME this code does not care to handle 132 | // non-bundle transport 133 | const rtcCandidate = new RTCIceCandidate({ 134 | sdpMLineIndex: 0, 135 | sdpMid: '', 136 | candidate: line 137 | }); 138 | const candidate = new RTCIceCandidate(rtcCandidate); 139 | this.peerConnection.addIceCandidate(candidate); 140 | this.logger.debug(`Added new candidate`, candidate.candidate); 141 | }); 142 | }); 143 | } 144 | 145 | private onLocalIceCandidate(evt: RTCPeerConnectionIceEvent) { 146 | if (evt.candidate !== null) { 147 | this.localCandidateBatch!.push(evt); 148 | return; 149 | } 150 | const candidateCount = this.localCandidateBatch?.length || 0; 151 | this.logger.debug(`Got last candidate. Pushing ${candidateCount} candidates`); 152 | if (candidateCount === 0) { 153 | this.logger.warn(`No candidates in batch!`); 154 | return; 155 | } 156 | const jingleElem = candidatesToJingle(this.localCandidateBatch!); 157 | this.localCandidateBatch = []; 158 | jingleElem.attr("sid", this.sid); 159 | jingleElem.attr("initiator", this.remoteId); 160 | this.client.send(xml("iq", { 161 | to: this.remoteId, 162 | from: this.myLocalId, 163 | type: "set", 164 | id: uuid(), 165 | xmlns: "jabber:client", 166 | }, jingleElem)); 167 | } 168 | 169 | private onTrack(evt: RTCTrackEvent) { 170 | this.logger.debug("OnTrack:", evt); 171 | this.logger.debug(evt.track, evt.track.kind); 172 | if (evt.track.kind === "audio") { 173 | this.logger.debug("Track is audio"); 174 | let sink = this.remoteAudioSinks[evt.track.id] = new RTCAudioSink(evt.track); 175 | sink.ondata = (data) => { 176 | this.logger.debug("DATA:", data); 177 | }; 178 | } 179 | } 180 | 181 | private onDataChannel(evt: RTCDataChannelEvent) { 182 | this.logger.debug('Data channel is created!'); 183 | evt.channel.onopen = () => { 184 | this.logger.debug('Data channel is open and ready to be used.'); 185 | }; 186 | } 187 | 188 | private onConnectionStateChange(state) { 189 | this.logger.info("Peer connection state change", state); 190 | if (state === "connecting") { 191 | // Resend presence 192 | this.client.write(new JitsiPresence( 193 | this.roomName, 194 | this.conferenceDomain, 195 | this.identity!.resource, 196 | this.clientPresence, 197 | false, 198 | ).xml); } 199 | } 200 | 201 | private initalisePeerConnection() { 202 | this.logger.debug("Creating new peer connection"); 203 | this.peerConnection = new RTCPeerConnection({ 204 | iceServers: this.opts.iceServers, 205 | sdpSemantics: 'unified-plan', 206 | }); 207 | this.peerConnection.onicecandidate = (evt) => this.onLocalIceCandidate(evt); 208 | this.peerConnection.ontrack = this.onTrack.bind(this); 209 | this.peerConnection.ondatachannel = this.onDataChannel.bind(this); 210 | this.peerConnection.onnegotiationneeded = (...args) => this.logger.debug("onnegotiationneeded", args); 211 | this.peerConnection.onremovetrack = (...args) => this.logger.debug("onremovetrack", args); 212 | this.peerConnection.onconnectionstatechange = () => this.onConnectionStateChange(this.peerConnection.connectionState); 213 | this.peerConnection.oniceconnectionstatechange = () => this.logger.debug("oniceconnectionstatechange", this.peerConnection.iceConnectionState); 214 | this.peerConnection.onicegatheringstatechange= () => this.logger.debug("onicegatheringstatechange", this.peerConnection.iceGatheringState); 215 | this.peerConnection.onsignalingstatechange= () => this.logger.debug("onsignalingstatechange", this.peerConnection.signalingState); 216 | } 217 | 218 | private async onJingle(stanza: Element, from: string, to: string) { 219 | const action = stanza.attr("action"); 220 | const sid = stanza.attr("sid"); 221 | if (action === "transport-info") { 222 | if (!this.peerConnection) { 223 | this.logger.warn("Cannot handle transport-info: peerConnection not set"); 224 | return; 225 | } 226 | this.onRemoteIceCandidate(stanza, from, to); 227 | return; 228 | } 229 | if (action !== "session-initiate") { 230 | this.logger.debug(stanza.toString()); 231 | this.logger.debug("Not sure how to handle", action, from); 232 | return; 233 | } 234 | if (from.endsWith("focus")) { 235 | this.logger.debug("Got req from focus, ignoring so we can use P2P"); 236 | // Hack: Force use of P2P 237 | return; 238 | } 239 | this.logger.debug(`Got session-initiate from ${from}`); 240 | if (this.peerConnection) { 241 | this.logger.debug(`Ignoring request for new peer connection`); 242 | return; 243 | // this.logger.debug("Already had a peer connection, creating new one"); 244 | // this.peerConnection.close(); 245 | } 246 | this.initalisePeerConnection(); 247 | this.sid = sid; 248 | this.remoteId = from; 249 | this.localCandidateBatch = []; 250 | const sdp = Jingle2SDP(stanza, "", "responder", "incoming"); 251 | const description = new RTCSessionDescription(); 252 | description.type = "offer"; 253 | description.sdp = sdp; 254 | try { 255 | this.logger.debug("Setting remote description"); 256 | await this.peerConnection.setRemoteDescription(description); 257 | // Add tracks 258 | const channel = this.peerConnection.createDataChannel( 259 | 'JVB data channel', { 260 | protocol: 'http://jitsi.org/protocols/colibri' 261 | } 262 | ); 263 | channel.onopen = function(event) { 264 | this.logger.debug("OPEN"); 265 | channel.send('Hi you!'); 266 | } 267 | channel.onmessage = function(event) { 268 | this.logger.debug(event.data); 269 | } 270 | this.sources.forEach((s) => { 271 | this.peerConnection.addTrack(s.createTrack()); 272 | }) 273 | const answer = await this.peerConnection.createAnswer(); 274 | this.peerConnection.setLocalDescription(answer); 275 | return this.sendSDPAnswer(to, from, answer.sdp, sid); 276 | } catch (ex) { 277 | this.logger.error('Failed to handle session-initiate', ex); 278 | this.emit('error', Error('Failed to handle session-initiate' + ex)); 279 | } 280 | } 281 | 282 | private async sendSDPAnswer(from: string, to: string, sdp: string, sid: string) { 283 | const answerElement = SDP2Jingle(sdp, "responder", "outgoing"); 284 | answerElement.attr("action", "session-accept"); 285 | answerElement.attr("responder", from); 286 | answerElement.attr("sid", sid); 287 | this.logger.debug("Sending SDP answer"); 288 | return this.client.send(xml("iq", { 289 | from, 290 | to, 291 | type: 'set', 292 | id: uuid(), 293 | }, answerElement)); 294 | } 295 | 296 | private onError(err) { 297 | this.state = "error"; 298 | this.logger.error("XMPP ERROR:", err); 299 | } 300 | 301 | private onOffline() { 302 | this.state = "offline"; 303 | this.logger.warn("XMPP OFFLINE"); 304 | } 305 | 306 | private onOnline(myJid: JID) { 307 | this.state = "online"; 308 | this.identity = myJid; 309 | this.logger.info("Connected to XMPP server as", myJid.toString()); 310 | } 311 | 312 | public addSource(arg0: any) { 313 | this.sources.push(arg0); 314 | } 315 | } 316 | 317 | -------------------------------------------------------------------------------- /src/Logger.ts: -------------------------------------------------------------------------------- 1 | export type LoggerFunc = (moduleName: string) => ILogger; 2 | 3 | export interface ILogger { 4 | debug: (...parts: any[]) => void, 5 | info: (...parts: any[]) => void, 6 | warn: (...parts: any[]) => void, 7 | error: (...parts: any[]) => void, 8 | } 9 | 10 | export class DummyLogger implements ILogger{ 11 | debug() { }; 12 | info() { }; 13 | warn() { }; 14 | error() { }; 15 | } 16 | 17 | export class FancyLogger implements ILogger { 18 | private chalk: any; 19 | constructor(private moduleName: string) { 20 | this.chalk = require('chalk'); 21 | } 22 | debug(...parts: any[]) { 23 | console.log(`${this.chalk.blue('DEBG')} [${this.moduleName}]`, ...parts); 24 | } 25 | info(...parts: any[]) { 26 | console.info(`${this.chalk.green('INFO')} [${this.moduleName}]`, ...parts); 27 | } 28 | warn(...parts: any[]) { 29 | console.warn(`${this.chalk.yellow('WARN')} [${this.moduleName}]`, ...parts); 30 | } 31 | error(...parts: any[]) { 32 | console.error(`${this.chalk.red('ERRO')} [${this.moduleName}]`, ...parts); 33 | } 34 | } -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { JitsiClient } from "./JitsiClient"; 2 | export * from "./Logger"; -------------------------------------------------------------------------------- /src/xmpp/BoshConnection.ts: -------------------------------------------------------------------------------- 1 | // /** 2 | // * BOSH Connection client for xmpp.js 3 | // */ 4 | 5 | // import { EventEmitter } from "events"; 6 | // import Axios, { AxiosInstance } from "axios"; 7 | // import { BoshSessionData, BoshSessionCreationRequest } from "./BoshSessionData"; 8 | 9 | // export class BoshConnection extends EventEmitter { 10 | // private rid?: number; 11 | // private httpClient: AxiosInstance; 12 | // constructor(private domain: string, boshUrl: string) { 13 | // super(); 14 | // this.httpClient = Axios.create({ 15 | // baseURL: boshUrl, 16 | // timeout: 60000, 17 | // headers: { 18 | 19 | // }, 20 | // }); 21 | // console.log("Created BoshConnection"); 22 | // } 23 | 24 | // async connect(baseURL) { 25 | // // This is the stream creation stanza. 26 | // // Set an RID and write our own request 27 | // this.rid = Date.now(); 28 | // await this.writeSessionData( 29 | // new BoshSessionCreationRequest( 30 | // 'jitsi.modular.im', 31 | // this.rid.toString(), 32 | // ) 33 | // ); 34 | // } 35 | 36 | // write(data: string, cb: (error?: Error) => void) { 37 | // // XXX: Due to xmpp.js's requirements, this must return a cb. 38 | // // XXX: Horrible detection of stream creation 39 | // console.log(`PEND-TX: ${data}`); 40 | // let promise: Promise; 41 | // if (!this.rid) { 42 | // // This is the stream creation stanza. 43 | // // Set an RID and write our own request 44 | // this.rid = Date.now(); 45 | // promise = this.writeSessionData(new BoshSessionCreationRequest('jitsi.modular.im', this.rid.toString())); 46 | // } else { 47 | // promise = Promise.resolve(null); 48 | // } 49 | // this.rid++; 50 | // promise.then((data) => { 51 | // cb(); 52 | // return data; 53 | // }).then((data) => { 54 | // if (data) { 55 | // this.emit("data", data); 56 | // } 57 | // }).catch(cb); 58 | // } 59 | 60 | // private async writeSessionData(writeData: BoshSessionData): Promise { 61 | // try { 62 | // const xmlData = writeData.toXML(); 63 | // console.log("TX:", xmlData); 64 | // const { data } = await this.httpClient.post("",xmlData, { 65 | // headers: { 66 | // "Content-Type": "text/xml; charset=utf", 67 | // } 68 | // }); 69 | // console.log("RX:", data); 70 | // return data; 71 | // } catch (ex) { 72 | // console.log("ERROR REQ:", ex); 73 | // throw ex; 74 | // } 75 | // } 76 | // } -------------------------------------------------------------------------------- /src/xmpp/BoshParser.ts: -------------------------------------------------------------------------------- 1 | // import { Parser } from "@xmpp/xml"; 2 | 3 | // export class BoshParser extends Parser { 4 | // // Need emitters for: 5 | // // error 6 | // // element 7 | // // end 8 | // // start 9 | // constructor() { 10 | // super(); 11 | // } 12 | 13 | // write(xmlStr: string) { 14 | // super.write(xmlStr); 15 | // } 16 | // } -------------------------------------------------------------------------------- /src/xmpp/BoshSessionData.ts: -------------------------------------------------------------------------------- 1 | export interface BoshSessionData { 2 | toXML(): string; 3 | } 4 | 5 | export class BoshSessionCreationRequest implements BoshSessionData { 6 | constructor(private to: string, private rid: string) { 7 | 8 | } 9 | 10 | toXML(): string { 11 | return "`; 21 | } 22 | } -------------------------------------------------------------------------------- /src/xmpp/DiscoInfoResponse.ts: -------------------------------------------------------------------------------- 1 | export class DiscoInfoResponse { 2 | constructor(private id: string, private to: string) {} 3 | public get xml() { 4 | return ` 5 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | `; 25 | } 26 | } -------------------------------------------------------------------------------- /src/xmpp/JitsiPresence.ts: -------------------------------------------------------------------------------- 1 | export interface JitsiUserPresence { 2 | videoMuted: boolean, 3 | audioMuted: boolean, 4 | avatarId?: string, 5 | email?: string, 6 | nick: string, 7 | handRaised: boolean, 8 | } 9 | 10 | export class JitsiPresence { 11 | constructor(private roomName: string, private conferenceServer: string, private identity: string, private state: JitsiUserPresence, private isJoin: boolean) {} 12 | public get xml() { 13 | const mucJoin = this.isJoin ? '\n': ""; 14 | const handRaised = this.state.handRaised ? "\n" : ""; 15 | const email = this.state.email ? `${this.state.email}\n` : ""; 16 | 17 | return ` 18 | ${mucJoin}${handRaised}${email}${this.state.nick} 19 | ${this.state.videoMuted} 20 | ${this.state.audioMuted} 21 | `; 22 | } 23 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "incremental": true, /* Enable incremental compilation */ 5 | "target": "ES2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ 6 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ 7 | // "lib": [], /* Specify library files to be included in the compilation. */ 8 | "allowJs": true, /* Allow javascript files to be compiled. */ 9 | "checkJs": false, /* Report errors in .js files. */ 10 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 11 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 12 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 13 | // "outFile": "./", /* Concatenate and emit output to single file. */ 14 | "outDir": "./lib", /* Redirect output structure to the directory. */ 15 | "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 16 | // "composite": true, /* Enable project compilation */ 17 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 18 | // "removeComments": true, /* Do not emit comments to output. */ 19 | // "noEmit": true, /* Do not emit outputs. */ 20 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 21 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 22 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 23 | 24 | /* Strict Type-Checking Options */ 25 | "strict": true, /* Enable all strict type-checking options. */ 26 | "noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */ 27 | // "strictNullChecks": true, /* Enable strict null checks. */ 28 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 29 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 30 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 31 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 32 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 33 | 34 | /* Additional Checks */ 35 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 36 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 37 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 38 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 39 | 40 | /* Module Resolution Options */ 41 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 42 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 43 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 44 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 45 | "typeRoots": [ 46 | "types" 47 | ], /* List of folders to include type definitions from. */ 48 | // "types": [], /* Type declaration files to be included in compilation. */ 49 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 50 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 51 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 52 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 53 | 54 | /* Source Map Options */ 55 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 56 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 57 | "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 58 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 59 | 60 | /* Experimental Options */ 61 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 62 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 63 | 64 | /* Advanced Options */ 65 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 66 | }, 67 | "include": [ 68 | "src/**/*", 69 | "app/**/*" 70 | ], 71 | "exclude": [ 72 | 73 | ] 74 | } 75 | -------------------------------------------------------------------------------- /types/sdp-jingle-json.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for [~THE LIBRARY NAME~] [~OPTIONAL VERSION NUMBER~] 2 | // Project: [~THE PROJECT NAME~] 3 | // Definitions by: [~YOUR NAME~] <[~A URL FOR YOU~]> 4 | 5 | /*~ This is the module template file. You should rename it to index.d.ts 6 | *~ and place it in a folder with the same name as the module. 7 | *~ For example, if you were writing a file for "super-greeter", this 8 | *~ file should be 'super-greeter/index.d.ts' 9 | */ 10 | 11 | /*~ If this module has methods, declare them as functions like so. 12 | */ 13 | 14 | interface SdpJson { 15 | 16 | } 17 | 18 | export function toSessionSDP(sdpContent: SdpJson): string; 19 | export function toSessionJSON(sdp: string, opts: { role: string, direction: string, creators: string[]}): SdpJson; 20 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@types/ltx@*": 6 | version "2.8.1" 7 | resolved "https://registry.yarnpkg.com/@types/ltx/-/ltx-2.8.1.tgz#faa6a851a763fd43a7ac448093553d82a92b8a98" 8 | integrity sha512-SjgICSxqzd5ZJGveuFJfULEztuT6OlkMjammWl989w6Z7qrvHjizALrAevd4g1+lRq1jrBF6u3r7oxhTeoWtsw== 9 | dependencies: 10 | "@types/node" "*" 11 | 12 | "@types/node@*": 13 | version "13.9.8" 14 | resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.8.tgz#09976420fc80a7a00bf40680c63815ed8c7616f4" 15 | integrity sha512-1WgO8hsyHynlx7nhP1kr0OFzsgKz5XDQL+Lfc3b1Q3qIln/n8cKD4m09NJ0+P1Rq7Zgnc7N0+SsMnoD1rEb0kA== 16 | 17 | "@types/node@^12": 18 | version "12.12.32" 19 | resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.32.tgz#0ccc836d273e8a3cddf568daf22729cfa57c1925" 20 | integrity sha512-44/reuCrwiQEsXud3I5X3sqI5jIXAmHB5xoiyKUw965olNHF3IWKjBLKK3F9LOSUZmK+oDt8jmyO637iX+hMgA== 21 | 22 | "@types/webrtc@^0.0.26": 23 | version "0.0.26" 24 | resolved "https://registry.yarnpkg.com/@types/webrtc/-/webrtc-0.0.26.tgz#f1bae07215eb84577c35ca050866820e412a07e2" 25 | integrity sha512-hTDoPKPYbgcogZA9eqhihPO+HnUs5BNPfnoOyc9bzcuq56eYV28zwJ+3tortPN0uXgmDvNs3f1JaT4oTbtWxqg== 26 | 27 | "@types/xmpp__jid@^1.3.0": 28 | version "1.3.0" 29 | resolved "https://registry.yarnpkg.com/@types/xmpp__jid/-/xmpp__jid-1.3.0.tgz#2f2bdb05fb67b0e4cdecb1c1947d7c2405190a5d" 30 | integrity sha512-CTJZC0sVg+e+e4psLDrxFWXtNMMDBzgTBkQCblM9S4JcOFtH7ePZu/SI2nXp58wCnn0Pqt7JiwPLm2g9eEdxJw== 31 | 32 | "@types/xmpp__xml@^0.6.0": 33 | version "0.6.0" 34 | resolved "https://registry.yarnpkg.com/@types/xmpp__xml/-/xmpp__xml-0.6.0.tgz#6fe68c6b2195827135b0565e76cc4c95954d718b" 35 | integrity sha512-0Wd350Kj4DKinbmS66pcr5d0onPZdIrNiTQE7rJiaNyc8reIzlppNxdckOD2AWYIuWSbRZI/P88+5eKMr6myRQ== 36 | dependencies: 37 | "@types/ltx" "*" 38 | "@types/node" "*" 39 | 40 | "@xmpp/base64@^0.11.0": 41 | version "0.11.0" 42 | resolved "https://registry.yarnpkg.com/@xmpp/base64/-/base64-0.11.0.tgz#fd3158c947484ddd554c8d09bbd126b455a74010" 43 | integrity sha512-BPHndqM49t2h0+dIZm9F9WU/sxTCZjPOUYRSCsuNxDSBRxtP8dTbQc1jalq071EB1WF9uBAIv9kRcrpCF/Ym0w== 44 | dependencies: 45 | base-64 "^0.1.0" 46 | 47 | "@xmpp/client-core@^0.11.0": 48 | version "0.11.0" 49 | resolved "https://registry.yarnpkg.com/@xmpp/client-core/-/client-core-0.11.0.tgz#b1b5a6e92177651b05e469e7aced4f1f658545c3" 50 | integrity sha512-tyQMQxHEBK/W5uobwaMg7mFWuAJhxUbXW9r8YASHOvhFT5fmON2D527X/yUESQHv2erEbYTpbapbVnr0Boex4w== 51 | dependencies: 52 | "@xmpp/connection" "^0.11.0" 53 | "@xmpp/jid" "^0.11.0" 54 | "@xmpp/xml" "^0.11.0" 55 | 56 | "@xmpp/client@^0.11.1": 57 | version "0.11.1" 58 | resolved "https://registry.yarnpkg.com/@xmpp/client/-/client-0.11.1.tgz#4a2ca6737835ab7888a44a907d7464834d35eefe" 59 | integrity sha512-8tf2PKcC5vU2RsYiI1SKau/jaNzvsn+ltbRrfbsgQpyTsBOqkDRYGQEI1yKtzD6WQ8d3TE63YCm1NsZqFrC4eQ== 60 | dependencies: 61 | "@xmpp/client-core" "^0.11.0" 62 | "@xmpp/iq" "^0.11.0" 63 | "@xmpp/middleware" "^0.11.0" 64 | "@xmpp/reconnect" "^0.11.0" 65 | "@xmpp/resolve" "^0.11.0" 66 | "@xmpp/resource-binding" "^0.11.0" 67 | "@xmpp/sasl" "^0.11.0" 68 | "@xmpp/sasl-anonymous" "^0.11.0" 69 | "@xmpp/sasl-plain" "^0.11.0" 70 | "@xmpp/sasl-scram-sha-1" "^0.11.0" 71 | "@xmpp/session-establishment" "^0.11.0" 72 | "@xmpp/starttls" "^0.11.0" 73 | "@xmpp/stream-features" "^0.11.0" 74 | "@xmpp/stream-management" "^0.11.1" 75 | "@xmpp/tcp" "^0.11.0" 76 | "@xmpp/tls" "^0.11.0" 77 | "@xmpp/websocket" "^0.11.0" 78 | 79 | "@xmpp/connection-tcp@^0.11.0": 80 | version "0.11.0" 81 | resolved "https://registry.yarnpkg.com/@xmpp/connection-tcp/-/connection-tcp-0.11.0.tgz#2a15a035a77df019de440cbedcf99a10cd526395" 82 | integrity sha512-O2MX5PvxasZYbf9PhkPG9o7T+kjI3TxZ6U0lc/t+aNfs+tNUN2k3bvX+T0RpmEgg4+qacAiBTt6V98oZF2LEsQ== 83 | dependencies: 84 | "@xmpp/connection" "^0.11.0" 85 | "@xmpp/xml" "^0.11.0" 86 | 87 | "@xmpp/connection@^0.11.0": 88 | version "0.11.0" 89 | resolved "https://registry.yarnpkg.com/@xmpp/connection/-/connection-0.11.0.tgz#6fb49f7df9f499ba2f5d734a33daa8b115b465e5" 90 | integrity sha512-T2Cr3f36VMqxdRJOnxwJATK4KB1l54IAwQrRxuQKnWY9A8BH9cdKnuta8j/mxsnZyxX6qA07E3rVaQC+r8Am/A== 91 | dependencies: 92 | "@xmpp/error" "^0.11.0" 93 | "@xmpp/events" "^0.11.0" 94 | "@xmpp/jid" "^0.11.0" 95 | "@xmpp/xml" "^0.11.0" 96 | 97 | "@xmpp/error@^0.11.0": 98 | version "0.11.0" 99 | resolved "https://registry.yarnpkg.com/@xmpp/error/-/error-0.11.0.tgz#de2544b31b06e1210e63a10ac20f31e5dbb24355" 100 | integrity sha512-U/zm6VoI50kbFQka95yHIeibjhh+VznH6Jv2tNomwS5SxTvjnisdHvP6SYqaml111cnseSPv/ajroc+o5GIu+A== 101 | 102 | "@xmpp/events@^0.11.0": 103 | version "0.11.0" 104 | resolved "https://registry.yarnpkg.com/@xmpp/events/-/events-0.11.0.tgz#ad95ca101cd618acae60d51dba0da2fa907898d6" 105 | integrity sha512-zykyqHvZHvXnC9JDzl+g78YFzUNABZwzA8RZH6n7iUiTQS6qRwOKyQXdQ47AlT3orid2vU9Jaa7QppW9c4OJ5Q== 106 | dependencies: 107 | events "^3.1.0" 108 | 109 | "@xmpp/id@^0.11.0": 110 | version "0.11.0" 111 | resolved "https://registry.yarnpkg.com/@xmpp/id/-/id-0.11.0.tgz#de89a3ace51a055f0158cfb8fef63b60d18d6ba8" 112 | integrity sha512-8eleVn6SKKChRCNCGHTEHSBLuEbEqPespf30QwkB8RC/3yMzWi3/5itfn4YySSF630ad1rxBHNdzObOkwtOjjw== 113 | 114 | "@xmpp/iq@^0.11.0": 115 | version "0.11.0" 116 | resolved "https://registry.yarnpkg.com/@xmpp/iq/-/iq-0.11.0.tgz#c20551f6f174aa33ad8c93c57f9e875ce01440d8" 117 | integrity sha512-TsZoBGrs9Y+/9UKTsWeCKxIPca7vIGaAjfX+k3uKyPuTFEwiw38p1fKESR/nqXfWHfJqVgjJ4r6vqvMR9Qj6Yw== 118 | dependencies: 119 | "@xmpp/events" "^0.11.0" 120 | "@xmpp/id" "^0.11.0" 121 | "@xmpp/middleware" "^0.11.0" 122 | "@xmpp/xml" "^0.11.0" 123 | 124 | "@xmpp/jid@^0.11.0": 125 | version "0.11.0" 126 | resolved "https://registry.yarnpkg.com/@xmpp/jid/-/jid-0.11.0.tgz#7e3b22dd98e929126b8730c13175f983e98f51b5" 127 | integrity sha512-4bQWU2Z7t7TqPX076PC5UscZ3V1CIXg/KjFQJ1z1xOfmEhEgz2gqYIR6lqiNlwrPCR9o1wmfQ+PBa/6u1NigcA== 128 | 129 | "@xmpp/middleware@^0.11.0": 130 | version "0.11.0" 131 | resolved "https://registry.yarnpkg.com/@xmpp/middleware/-/middleware-0.11.0.tgz#77428cceeefac0608d787e00816645294a36d0fd" 132 | integrity sha512-y0rfM5LtKuDwNZ16dQcHdeWffuut6ooWkOnKapavDFa+VwVx4CV9cSX1hUnoHkhKyZGXS1uTo/J2iagN0KhASQ== 133 | dependencies: 134 | "@xmpp/error" "^0.11.0" 135 | "@xmpp/jid" "^0.11.0" 136 | "@xmpp/xml" "^0.11.0" 137 | koa-compose "^4.1.0" 138 | 139 | "@xmpp/reconnect@^0.11.0": 140 | version "0.11.0" 141 | resolved "https://registry.yarnpkg.com/@xmpp/reconnect/-/reconnect-0.11.0.tgz#89b303ff072a171ceb9de0012e6e4a660f0789c3" 142 | integrity sha512-0d462Fjs3aG2rej5/P4gdKqjgK9hiKaK/29Cun7ZaciL0MJ/d8Lh8fzQMmzjw1mRJlaWiZkuJ8zi73wd1yFxng== 143 | dependencies: 144 | "@xmpp/events" "^0.11.0" 145 | 146 | "@xmpp/resolve@^0.11.0": 147 | version "0.11.0" 148 | resolved "https://registry.yarnpkg.com/@xmpp/resolve/-/resolve-0.11.0.tgz#0d90c31264401acb36b551ce82d6e37bf76bcdd6" 149 | integrity sha512-zZolSgEgtQM/GX+NR3vh5lJ/BdWkUU5S7H47YHqr001iA1AdPZWBP2QRi1YiWR49nnuyW/7oLH91wFAp4Nx5sA== 150 | dependencies: 151 | "@xmpp/events" "^0.11.0" 152 | "@xmpp/xml" "^0.11.0" 153 | node-fetch "^2.6.0" 154 | 155 | "@xmpp/resource-binding@^0.11.0": 156 | version "0.11.0" 157 | resolved "https://registry.yarnpkg.com/@xmpp/resource-binding/-/resource-binding-0.11.0.tgz#186e7a4bee5c54efae9d5632dfcc8cc7a15b332f" 158 | integrity sha512-7bIMiwwJ/rH7myM8n4ElwwqjrAXP6qtJCRuQDTs393cRUBd4zkIyT81HnvXzvTBvhSOwdzHDqBnxoT9VCj4J5Q== 159 | dependencies: 160 | "@xmpp/xml" "^0.11.0" 161 | 162 | "@xmpp/sasl-anonymous@^0.11.0": 163 | version "0.11.0" 164 | resolved "https://registry.yarnpkg.com/@xmpp/sasl-anonymous/-/sasl-anonymous-0.11.0.tgz#c64f636ce6ff8ad4c7dfbb84ce63da67e8773679" 165 | integrity sha512-MyNJ1GJ5OPchI6cyEihPusfOKDtkZUOeYn8mVtH6WYHwYWD+LrnS3eBhGgAG7Yt20utDTTQvIHnUGSJ1fV+OLg== 166 | dependencies: 167 | sasl-anonymous "^0.1.0" 168 | 169 | "@xmpp/sasl-plain@^0.11.0": 170 | version "0.11.0" 171 | resolved "https://registry.yarnpkg.com/@xmpp/sasl-plain/-/sasl-plain-0.11.0.tgz#0f62bf7f7c962ba0919357c6221940913fbf9fa4" 172 | integrity sha512-2Qxl0LB1Q3I+NWaUdTwwfsf3iYM0JmSlJDVSfQK1M81rFbj68RZhmiE6/GZn3IcmLUlRo+B/R5sFJTSXud7LHA== 173 | dependencies: 174 | sasl-plain "^0.1.0" 175 | 176 | "@xmpp/sasl-scram-sha-1@^0.11.0": 177 | version "0.11.0" 178 | resolved "https://registry.yarnpkg.com/@xmpp/sasl-scram-sha-1/-/sasl-scram-sha-1-0.11.0.tgz#e12b2ae538095c83ae4fb85f09669dab4cf3a4d4" 179 | integrity sha512-bZmaZayrT7avkJkI4mmsbnFsjWbrUwu3DU+KlwNazdMGmgXiixqZCjH6TSx6VP45ixqk5R0EjRvpFU3PVw1eTg== 180 | dependencies: 181 | sasl-scram-sha-1 "^1.2.1" 182 | 183 | "@xmpp/sasl@^0.11.0": 184 | version "0.11.0" 185 | resolved "https://registry.yarnpkg.com/@xmpp/sasl/-/sasl-0.11.0.tgz#f1a1b4f20882688005603c24a1f368b225062bff" 186 | integrity sha512-qfZyYm3C8RVSSVs4FCjC9dH0ZFKPOGrhNvMl1yOIuY0CbzVj/TOWT5v4X2olOU2dnWj//9F18vfC7RcCQDB3LQ== 187 | dependencies: 188 | "@xmpp/base64" "^0.11.0" 189 | "@xmpp/error" "^0.11.0" 190 | "@xmpp/xml" "^0.11.0" 191 | saslmechanisms "^0.1.1" 192 | 193 | "@xmpp/session-establishment@^0.11.0": 194 | version "0.11.0" 195 | resolved "https://registry.yarnpkg.com/@xmpp/session-establishment/-/session-establishment-0.11.0.tgz#eb70e9a84f9e33af424034e3defe43fff8bbf002" 196 | integrity sha512-qPnkspEPIHeQOsfN0bEv321Xx3vTln8LWN5ltYJECdRHM7sdpjFZ8z362cRTJeYkb+O8DKKYNpFrCyeBi/bw3g== 197 | dependencies: 198 | "@xmpp/xml" "^0.11.0" 199 | 200 | "@xmpp/starttls@^0.11.0": 201 | version "0.11.0" 202 | resolved "https://registry.yarnpkg.com/@xmpp/starttls/-/starttls-0.11.0.tgz#91d64891c1a49ff6bb06439608e625ccfd3637f7" 203 | integrity sha512-S0FAxq7CFlE5ZM4498PmBORKbyVSrPesIyu4drdQkkE3QlDgrPimssqMUUR1woZbxmG4ohb+hPfTgogHS1BurQ== 204 | dependencies: 205 | "@xmpp/events" "^0.11.0" 206 | "@xmpp/xml" "^0.11.0" 207 | 208 | "@xmpp/stream-features@^0.11.0": 209 | version "0.11.0" 210 | resolved "https://registry.yarnpkg.com/@xmpp/stream-features/-/stream-features-0.11.0.tgz#51dc25e5aaf286d5d09331f3d17a261d459bc26a" 211 | integrity sha512-DWzdmPwbATtm+hTkyY3AHCIJgnHe0ffluMd0jfj8mYqpZOG5wS5E+0+kAYoZhGzS3jzXBZrX/na7RDs3i9nx3Q== 212 | 213 | "@xmpp/stream-management@^0.11.1": 214 | version "0.11.1" 215 | resolved "https://registry.yarnpkg.com/@xmpp/stream-management/-/stream-management-0.11.1.tgz#7f8f0c5c764556ae2dee39944159a8ec842e580e" 216 | integrity sha512-U/cxiPduHWga8uKBvOPknLYQ0bUbLhmAaZi5dpzAC+FzFkP6zumJQvtC6sVl966kltm8TOCGF0JSRCEkHs2uRg== 217 | dependencies: 218 | "@xmpp/xml" "^0.11.0" 219 | 220 | "@xmpp/tcp@^0.11.0": 221 | version "0.11.0" 222 | resolved "https://registry.yarnpkg.com/@xmpp/tcp/-/tcp-0.11.0.tgz#987b2950f506d1330b4e069b313fd0fca5d91e3e" 223 | integrity sha512-26pbx0Z6w4rF6Brb9yDhvXtczJl/S07HbMZpgpMdheczc6W/d9ypsplr5/rRM+4aZt1rOV1noJMdfRHl2qG3Jw== 224 | dependencies: 225 | "@xmpp/connection-tcp" "^0.11.0" 226 | 227 | "@xmpp/tls@^0.11.0": 228 | version "0.11.0" 229 | resolved "https://registry.yarnpkg.com/@xmpp/tls/-/tls-0.11.0.tgz#bf8009e94c365403e1cbacfe78b6ed6ecaf20940" 230 | integrity sha512-WnkpR3/Rd5BqYrJslpvYZJNL0GXMQlOOgrusf9qnXVJ25GKVSy+pYfWf1jhxBDw9WzuCCH5hfSAzZ0biRkq4gQ== 231 | dependencies: 232 | "@xmpp/connection" "^0.11.0" 233 | "@xmpp/connection-tcp" "^0.11.0" 234 | 235 | "@xmpp/websocket@^0.11.0": 236 | version "0.11.0" 237 | resolved "https://registry.yarnpkg.com/@xmpp/websocket/-/websocket-0.11.0.tgz#692bd90b4aa3e8c96233b5f4099bff5ae16d64f0" 238 | integrity sha512-2VY99uS6PEEJF/JLY3yC6AMmJPu1vTGLIzE38bDVNg3GslnYXxJyLfrrJs2QPr7i0ndYcCgoSL3cN6lep5LjsA== 239 | dependencies: 240 | "@xmpp/connection" "^0.11.0" 241 | "@xmpp/xml" "^0.11.0" 242 | ws "^7.2.1" 243 | 244 | "@xmpp/xml@^0.11.0": 245 | version "0.11.0" 246 | resolved "https://registry.yarnpkg.com/@xmpp/xml/-/xml-0.11.0.tgz#7290c9f95b9f7951f0aaa765583a146995289339" 247 | integrity sha512-CV1BLV27VErZmf/dmjWn5YsgHl0+FDUkp5V1IJH3BXsqDjs6xOG5nH22l3FtloRlam7nAc4f6+9VduRedxNpeQ== 248 | dependencies: 249 | ltx "^2.9.2" 250 | 251 | abbrev@1: 252 | version "1.1.1" 253 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" 254 | integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== 255 | 256 | ansi-regex@^2.0.0: 257 | version "2.1.1" 258 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 259 | integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= 260 | 261 | ansi-regex@^3.0.0: 262 | version "3.0.0" 263 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" 264 | integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= 265 | 266 | aproba@^1.0.3: 267 | version "1.2.0" 268 | resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" 269 | integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== 270 | 271 | are-we-there-yet@~1.1.2: 272 | version "1.1.5" 273 | resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" 274 | integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== 275 | dependencies: 276 | delegates "^1.0.0" 277 | readable-stream "^2.0.6" 278 | 279 | axios@^0.19.2: 280 | version "0.19.2" 281 | resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" 282 | integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA== 283 | dependencies: 284 | follow-redirects "1.5.10" 285 | 286 | balanced-match@^1.0.0: 287 | version "1.0.0" 288 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 289 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 290 | 291 | base-64@^0.1.0: 292 | version "0.1.0" 293 | resolved "https://registry.yarnpkg.com/base-64/-/base-64-0.1.0.tgz#780a99c84e7d600260361511c4877613bf24f6bb" 294 | integrity sha1-eAqZyE59YAJgNhURxId2E78k9rs= 295 | 296 | bitwise-xor@0.0.0: 297 | version "0.0.0" 298 | resolved "https://registry.yarnpkg.com/bitwise-xor/-/bitwise-xor-0.0.0.tgz#040a8172b5bb8cc562b0b7119f230b2a1a780e3d" 299 | integrity sha1-BAqBcrW7jMVisLcRnyMLKhp4Dj0= 300 | 301 | brace-expansion@^1.1.7: 302 | version "1.1.11" 303 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 304 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 305 | dependencies: 306 | balanced-match "^1.0.0" 307 | concat-map "0.0.1" 308 | 309 | buffer-from@^1.0.0: 310 | version "1.1.1" 311 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" 312 | integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== 313 | 314 | chownr@^1.1.1: 315 | version "1.1.4" 316 | resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" 317 | integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== 318 | 319 | cipher-base@^1.0.1, cipher-base@^1.0.3: 320 | version "1.0.4" 321 | resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" 322 | integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== 323 | dependencies: 324 | inherits "^2.0.1" 325 | safe-buffer "^5.0.1" 326 | 327 | code-point-at@^1.0.0: 328 | version "1.1.0" 329 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" 330 | integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= 331 | 332 | concat-map@0.0.1: 333 | version "0.0.1" 334 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 335 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 336 | 337 | console-control-strings@^1.0.0, console-control-strings@~1.1.0: 338 | version "1.1.0" 339 | resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" 340 | integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= 341 | 342 | core-util-is@~1.0.0: 343 | version "1.0.2" 344 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 345 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= 346 | 347 | create-hash@^1.1.0: 348 | version "1.2.0" 349 | resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" 350 | integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== 351 | dependencies: 352 | cipher-base "^1.0.1" 353 | inherits "^2.0.1" 354 | md5.js "^1.3.4" 355 | ripemd160 "^2.0.1" 356 | sha.js "^2.4.0" 357 | 358 | create-hmac@^1.1.3: 359 | version "1.1.7" 360 | resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" 361 | integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== 362 | dependencies: 363 | cipher-base "^1.0.3" 364 | create-hash "^1.1.0" 365 | inherits "^2.0.1" 366 | ripemd160 "^2.0.0" 367 | safe-buffer "^5.0.1" 368 | sha.js "^2.4.8" 369 | 370 | debug@=3.1.0: 371 | version "3.1.0" 372 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" 373 | integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== 374 | dependencies: 375 | ms "2.0.0" 376 | 377 | debug@^3.2.6: 378 | version "3.2.6" 379 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" 380 | integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== 381 | dependencies: 382 | ms "^2.1.1" 383 | 384 | deep-extend@^0.6.0: 385 | version "0.6.0" 386 | resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" 387 | integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== 388 | 389 | delegates@^1.0.0: 390 | version "1.0.0" 391 | resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" 392 | integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= 393 | 394 | detect-libc@^1.0.2: 395 | version "1.0.3" 396 | resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" 397 | integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= 398 | 399 | domexception@^1.0.1: 400 | version "1.0.1" 401 | resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" 402 | integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug== 403 | dependencies: 404 | webidl-conversions "^4.0.2" 405 | 406 | events@^3.1.0: 407 | version "3.1.0" 408 | resolved "https://registry.yarnpkg.com/events/-/events-3.1.0.tgz#84279af1b34cb75aa88bf5ff291f6d0bd9b31a59" 409 | integrity sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg== 410 | 411 | follow-redirects@1.5.10: 412 | version "1.5.10" 413 | resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" 414 | integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== 415 | dependencies: 416 | debug "=3.1.0" 417 | 418 | fs-minipass@^1.2.5: 419 | version "1.2.7" 420 | resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" 421 | integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== 422 | dependencies: 423 | minipass "^2.6.0" 424 | 425 | fs.realpath@^1.0.0: 426 | version "1.0.0" 427 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 428 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 429 | 430 | gauge@~2.7.3: 431 | version "2.7.4" 432 | resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" 433 | integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= 434 | dependencies: 435 | aproba "^1.0.3" 436 | console-control-strings "^1.0.0" 437 | has-unicode "^2.0.0" 438 | object-assign "^4.1.0" 439 | signal-exit "^3.0.0" 440 | string-width "^1.0.1" 441 | strip-ansi "^3.0.1" 442 | wide-align "^1.1.0" 443 | 444 | glob@^7.1.3: 445 | version "7.1.6" 446 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" 447 | integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== 448 | dependencies: 449 | fs.realpath "^1.0.0" 450 | inflight "^1.0.4" 451 | inherits "2" 452 | minimatch "^3.0.4" 453 | once "^1.3.0" 454 | path-is-absolute "^1.0.0" 455 | 456 | has-unicode@^2.0.0: 457 | version "2.0.1" 458 | resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" 459 | integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= 460 | 461 | hash-base@^3.0.0: 462 | version "3.0.4" 463 | resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" 464 | integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= 465 | dependencies: 466 | inherits "^2.0.1" 467 | safe-buffer "^5.0.1" 468 | 469 | iconv-lite@^0.4.4: 470 | version "0.4.24" 471 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 472 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 473 | dependencies: 474 | safer-buffer ">= 2.1.2 < 3" 475 | 476 | ignore-walk@^3.0.1: 477 | version "3.0.3" 478 | resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" 479 | integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== 480 | dependencies: 481 | minimatch "^3.0.4" 482 | 483 | inflight@^1.0.4: 484 | version "1.0.6" 485 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 486 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 487 | dependencies: 488 | once "^1.3.0" 489 | wrappy "1" 490 | 491 | inherits@2, inherits@^2.0.1, inherits@^2.0.4, inherits@~2.0.3: 492 | version "2.0.4" 493 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 494 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 495 | 496 | ini@~1.3.0: 497 | version "1.3.5" 498 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" 499 | integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== 500 | 501 | is-fullwidth-code-point@^1.0.0: 502 | version "1.0.0" 503 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" 504 | integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= 505 | dependencies: 506 | number-is-nan "^1.0.0" 507 | 508 | is-fullwidth-code-point@^2.0.0: 509 | version "2.0.0" 510 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 511 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= 512 | 513 | isarray@~1.0.0: 514 | version "1.0.0" 515 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 516 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= 517 | 518 | koa-compose@^4.1.0: 519 | version "4.1.0" 520 | resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-4.1.0.tgz#507306b9371901db41121c812e923d0d67d3e877" 521 | integrity sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw== 522 | 523 | ltx@^2.9.2: 524 | version "2.9.2" 525 | resolved "https://registry.yarnpkg.com/ltx/-/ltx-2.9.2.tgz#222b28745142b71f66c566f20bb73648f82c0d86" 526 | integrity sha512-llB7HflFhlfsYYT1SAe80elCBO5C20ryLdwPB/A/BZk38hhVeZztDlWQ9uTyvKNPX4aK6sA+JfS1f/mfzp5cxA== 527 | dependencies: 528 | inherits "^2.0.4" 529 | 530 | md5.js@^1.3.4: 531 | version "1.3.5" 532 | resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" 533 | integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== 534 | dependencies: 535 | hash-base "^3.0.0" 536 | inherits "^2.0.1" 537 | safe-buffer "^5.1.2" 538 | 539 | minimatch@^3.0.4: 540 | version "3.0.4" 541 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 542 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 543 | dependencies: 544 | brace-expansion "^1.1.7" 545 | 546 | minimist@^1.2.0, minimist@^1.2.5: 547 | version "1.2.5" 548 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" 549 | integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== 550 | 551 | minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: 552 | version "2.9.0" 553 | resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" 554 | integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== 555 | dependencies: 556 | safe-buffer "^5.1.2" 557 | yallist "^3.0.0" 558 | 559 | minizlib@^1.2.1: 560 | version "1.3.3" 561 | resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" 562 | integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== 563 | dependencies: 564 | minipass "^2.9.0" 565 | 566 | mkdirp@^0.5.0, mkdirp@^0.5.1: 567 | version "0.5.4" 568 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.4.tgz#fd01504a6797ec5c9be81ff43d204961ed64a512" 569 | integrity sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw== 570 | dependencies: 571 | minimist "^1.2.5" 572 | 573 | ms@2.0.0: 574 | version "2.0.0" 575 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 576 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 577 | 578 | ms@^2.1.1: 579 | version "2.1.2" 580 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 581 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 582 | 583 | needle@^2.2.1: 584 | version "2.3.3" 585 | resolved "https://registry.yarnpkg.com/needle/-/needle-2.3.3.tgz#a041ad1d04a871b0ebb666f40baaf1fb47867117" 586 | integrity sha512-EkY0GeSq87rWp1hoq/sH/wnTWgFVhYlnIkbJ0YJFfRgEFlz2RraCjBpFQ+vrEgEdp0ThfyHADmkChEhcb7PKyw== 587 | dependencies: 588 | debug "^3.2.6" 589 | iconv-lite "^0.4.4" 590 | sax "^1.2.4" 591 | 592 | node-fetch@^2.6.0: 593 | version "2.6.0" 594 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" 595 | integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== 596 | 597 | node-pre-gyp@^0.13.0: 598 | version "0.13.0" 599 | resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.13.0.tgz#df9ab7b68dd6498137717838e4f92a33fc9daa42" 600 | integrity sha512-Md1D3xnEne8b/HGVQkZZwV27WUi1ZRuZBij24TNaZwUPU3ZAFtvT6xxJGaUVillfmMKnn5oD1HoGsp2Ftik7SQ== 601 | dependencies: 602 | detect-libc "^1.0.2" 603 | mkdirp "^0.5.1" 604 | needle "^2.2.1" 605 | nopt "^4.0.1" 606 | npm-packlist "^1.1.6" 607 | npmlog "^4.0.2" 608 | rc "^1.2.7" 609 | rimraf "^2.6.1" 610 | semver "^5.3.0" 611 | tar "^4" 612 | 613 | nopt@^4.0.1: 614 | version "4.0.3" 615 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" 616 | integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== 617 | dependencies: 618 | abbrev "1" 619 | osenv "^0.1.4" 620 | 621 | npm-bundled@^1.0.1: 622 | version "1.1.1" 623 | resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b" 624 | integrity sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA== 625 | dependencies: 626 | npm-normalize-package-bin "^1.0.1" 627 | 628 | npm-normalize-package-bin@^1.0.1: 629 | version "1.0.1" 630 | resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" 631 | integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== 632 | 633 | npm-packlist@^1.1.6: 634 | version "1.4.8" 635 | resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" 636 | integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== 637 | dependencies: 638 | ignore-walk "^3.0.1" 639 | npm-bundled "^1.0.1" 640 | npm-normalize-package-bin "^1.0.1" 641 | 642 | npmlog@^4.0.2: 643 | version "4.1.2" 644 | resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" 645 | integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== 646 | dependencies: 647 | are-we-there-yet "~1.1.2" 648 | console-control-strings "~1.1.0" 649 | gauge "~2.7.3" 650 | set-blocking "~2.0.0" 651 | 652 | number-is-nan@^1.0.0: 653 | version "1.0.1" 654 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 655 | integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= 656 | 657 | object-assign@^4.1.0: 658 | version "4.1.1" 659 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 660 | integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= 661 | 662 | once@^1.3.0: 663 | version "1.4.0" 664 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 665 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 666 | dependencies: 667 | wrappy "1" 668 | 669 | os-homedir@^1.0.0: 670 | version "1.0.2" 671 | resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" 672 | integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= 673 | 674 | os-tmpdir@^1.0.0: 675 | version "1.0.2" 676 | resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" 677 | integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= 678 | 679 | osenv@^0.1.4: 680 | version "0.1.5" 681 | resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" 682 | integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== 683 | dependencies: 684 | os-homedir "^1.0.0" 685 | os-tmpdir "^1.0.0" 686 | 687 | path-is-absolute@^1.0.0: 688 | version "1.0.1" 689 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 690 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 691 | 692 | process-nextick-args@~2.0.0: 693 | version "2.0.1" 694 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" 695 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== 696 | 697 | randombytes@^2.0.1: 698 | version "2.1.0" 699 | resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" 700 | integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== 701 | dependencies: 702 | safe-buffer "^5.1.0" 703 | 704 | rc@^1.2.7: 705 | version "1.2.8" 706 | resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" 707 | integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== 708 | dependencies: 709 | deep-extend "^0.6.0" 710 | ini "~1.3.0" 711 | minimist "^1.2.0" 712 | strip-json-comments "~2.0.1" 713 | 714 | readable-stream@^2.0.6: 715 | version "2.3.7" 716 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" 717 | integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== 718 | dependencies: 719 | core-util-is "~1.0.0" 720 | inherits "~2.0.3" 721 | isarray "~1.0.0" 722 | process-nextick-args "~2.0.0" 723 | safe-buffer "~5.1.1" 724 | string_decoder "~1.1.1" 725 | util-deprecate "~1.0.1" 726 | 727 | rimraf@^2.6.1: 728 | version "2.7.1" 729 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" 730 | integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== 731 | dependencies: 732 | glob "^7.1.3" 733 | 734 | ripemd160@^2.0.0, ripemd160@^2.0.1: 735 | version "2.0.2" 736 | resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" 737 | integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== 738 | dependencies: 739 | hash-base "^3.0.0" 740 | inherits "^2.0.1" 741 | 742 | safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2: 743 | version "5.2.0" 744 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" 745 | integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== 746 | 747 | safe-buffer@~5.1.0, safe-buffer@~5.1.1: 748 | version "5.1.2" 749 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 750 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 751 | 752 | "safer-buffer@>= 2.1.2 < 3": 753 | version "2.1.2" 754 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 755 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 756 | 757 | sasl-anonymous@^0.1.0: 758 | version "0.1.0" 759 | resolved "https://registry.yarnpkg.com/sasl-anonymous/-/sasl-anonymous-0.1.0.tgz#f544c7e824df2a40d9ad4733829572cc8d9ed5a5" 760 | integrity sha1-9UTH6CTfKkDZrUczgpVyzI2e1aU= 761 | 762 | sasl-plain@^0.1.0: 763 | version "0.1.0" 764 | resolved "https://registry.yarnpkg.com/sasl-plain/-/sasl-plain-0.1.0.tgz#cf145e7c02222b64d60c0806d9cd2ae5380426cc" 765 | integrity sha1-zxRefAIiK2TWDAgG2c0q5TgEJsw= 766 | 767 | sasl-scram-sha-1@^1.2.1: 768 | version "1.2.1" 769 | resolved "https://registry.yarnpkg.com/sasl-scram-sha-1/-/sasl-scram-sha-1-1.2.1.tgz#d88d51feaa0ff320d8eb1d6fc75657653f9dcd4b" 770 | integrity sha1-2I1R/qoP8yDY6x1vx1ZXZT+dzUs= 771 | dependencies: 772 | bitwise-xor "0.0.0" 773 | create-hash "^1.1.0" 774 | create-hmac "^1.1.3" 775 | randombytes "^2.0.1" 776 | 777 | saslmechanisms@^0.1.1: 778 | version "0.1.1" 779 | resolved "https://registry.yarnpkg.com/saslmechanisms/-/saslmechanisms-0.1.1.tgz#478be1429500fcfaa780be88b3343ced7d2a9182" 780 | integrity sha1-R4vhQpUA/PqngL6IszQ87X0qkYI= 781 | 782 | sax@^1.2.4: 783 | version "1.2.4" 784 | resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" 785 | integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== 786 | 787 | sdp-jingle-json@^3.1.0: 788 | version "3.1.0" 789 | resolved "https://registry.yarnpkg.com/sdp-jingle-json/-/sdp-jingle-json-3.1.0.tgz#7067d5d998ef0be754c3a01a551ef0052a0ffbfb" 790 | integrity sha512-Uu+FelZD/edNoOc64NwQP8jjbBVMggAaErGU+2cSxPZgyReJTtqtp5287p2vu7bHubERxEbiW0H1pC2fnH5GEA== 791 | 792 | semver@^5.3.0: 793 | version "5.7.1" 794 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 795 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== 796 | 797 | set-blocking@~2.0.0: 798 | version "2.0.0" 799 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 800 | integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= 801 | 802 | sha.js@^2.4.0, sha.js@^2.4.8: 803 | version "2.4.11" 804 | resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" 805 | integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== 806 | dependencies: 807 | inherits "^2.0.1" 808 | safe-buffer "^5.0.1" 809 | 810 | signal-exit@^3.0.0: 811 | version "3.0.3" 812 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" 813 | integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== 814 | 815 | source-map-support@^0.5.16: 816 | version "0.5.16" 817 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" 818 | integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ== 819 | dependencies: 820 | buffer-from "^1.0.0" 821 | source-map "^0.6.0" 822 | 823 | source-map@^0.6.0: 824 | version "0.6.1" 825 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 826 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== 827 | 828 | string-width@^1.0.1: 829 | version "1.0.2" 830 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 831 | integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= 832 | dependencies: 833 | code-point-at "^1.0.0" 834 | is-fullwidth-code-point "^1.0.0" 835 | strip-ansi "^3.0.0" 836 | 837 | "string-width@^1.0.2 || 2": 838 | version "2.1.1" 839 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" 840 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== 841 | dependencies: 842 | is-fullwidth-code-point "^2.0.0" 843 | strip-ansi "^4.0.0" 844 | 845 | string_decoder@~1.1.1: 846 | version "1.1.1" 847 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" 848 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== 849 | dependencies: 850 | safe-buffer "~5.1.0" 851 | 852 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: 853 | version "3.0.1" 854 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 855 | integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= 856 | dependencies: 857 | ansi-regex "^2.0.0" 858 | 859 | strip-ansi@^4.0.0: 860 | version "4.0.0" 861 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" 862 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= 863 | dependencies: 864 | ansi-regex "^3.0.0" 865 | 866 | strip-json-comments@~2.0.1: 867 | version "2.0.1" 868 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 869 | integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= 870 | 871 | tar@^4: 872 | version "4.4.13" 873 | resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" 874 | integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== 875 | dependencies: 876 | chownr "^1.1.1" 877 | fs-minipass "^1.2.5" 878 | minipass "^2.8.6" 879 | minizlib "^1.2.1" 880 | mkdirp "^0.5.0" 881 | safe-buffer "^5.1.2" 882 | yallist "^3.0.3" 883 | 884 | typescript@^3.8.3: 885 | version "3.8.3" 886 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" 887 | integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== 888 | 889 | util-deprecate@~1.0.1: 890 | version "1.0.2" 891 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 892 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= 893 | 894 | uuid@^7.0.3: 895 | version "7.0.3" 896 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" 897 | integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== 898 | 899 | webidl-conversions@^4.0.2: 900 | version "4.0.2" 901 | resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" 902 | integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== 903 | 904 | wide-align@^1.1.0: 905 | version "1.1.3" 906 | resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" 907 | integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== 908 | dependencies: 909 | string-width "^1.0.2 || 2" 910 | 911 | wrappy@1: 912 | version "1.0.2" 913 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 914 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 915 | 916 | wrtc@^0.4.4: 917 | version "0.4.4" 918 | resolved "https://registry.yarnpkg.com/wrtc/-/wrtc-0.4.4.tgz#523bcec18ea91de5d8ee1ef11e5cbe4fcf7daf3d" 919 | integrity sha512-ithsvEKqS6pIbzPiXgJXU4SjQHR7fSszDgGMOREW8j2S4N+ay05r4aYpUZJnsa1fr6o5efeQ/ikFiDXDl5YqeQ== 920 | dependencies: 921 | node-pre-gyp "^0.13.0" 922 | optionalDependencies: 923 | domexception "^1.0.1" 924 | 925 | ws@^7.2.1: 926 | version "7.2.3" 927 | resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.3.tgz#a5411e1fb04d5ed0efee76d26d5c46d830c39b46" 928 | integrity sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ== 929 | 930 | yallist@^3.0.0, yallist@^3.0.3: 931 | version "3.1.1" 932 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" 933 | integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== 934 | --------------------------------------------------------------------------------