├── .gitignore ├── .node-version ├── Procfile ├── README.md ├── assets ├── integrations.png └── integrations │ ├── canny.png │ ├── github.png │ ├── heroku.png │ └── rollbar.png ├── docs └── integrations │ ├── canny │ ├── README.md │ ├── add-webhook.png │ ├── copy-webhook.png │ └── example.png │ ├── github │ ├── README.md │ ├── add-webhook.png │ ├── copy-webhook.png │ └── example.png │ ├── heroku │ ├── README.md │ ├── add-webhook-1.png │ ├── add-webhook-2.png │ ├── copy-webhook.png │ └── example.png │ └── rollbar │ ├── README.md │ ├── add-webhook.png │ ├── copy-webhook.png │ └── example.png ├── lib ├── index.js ├── integration.js └── integrations │ ├── canny.js │ ├── github.js │ ├── heroku.js │ └── rollbar.js ├── package.json ├── server.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | 3 | node_modules/ 4 | npm-debug.log 5 | yarn-debug.log 6 | yarn-error.log 7 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | 18.14.1 2 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: yarn start 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
Push content into Missive via our hosted webhook integrations. 3 |
DocumentationSubmit your own 4 |

5 |
6 | 7 | 8 |

9 |
10 | Missive | Team email, team chat, team tasks, one app 11 |
Missive mixes team email and threaded group chat for productive teams. 12 |
A single app for all your internal and external communication and a full work management solution. 13 |
14 | -------------------------------------------------------------------------------- /assets/integrations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/missive/missive-webhooks/437a833897a80a64331902fd1c1df4d3cccb1ef6/assets/integrations.png -------------------------------------------------------------------------------- /assets/integrations/canny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/missive/missive-webhooks/437a833897a80a64331902fd1c1df4d3cccb1ef6/assets/integrations/canny.png -------------------------------------------------------------------------------- /assets/integrations/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/missive/missive-webhooks/437a833897a80a64331902fd1c1df4d3cccb1ef6/assets/integrations/github.png -------------------------------------------------------------------------------- /assets/integrations/heroku.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/missive/missive-webhooks/437a833897a80a64331902fd1c1df4d3cccb1ef6/assets/integrations/heroku.png -------------------------------------------------------------------------------- /assets/integrations/rollbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/missive/missive-webhooks/437a833897a80a64331902fd1c1df4d3cccb1ef6/assets/integrations/rollbar.png -------------------------------------------------------------------------------- /docs/integrations/canny/README.md: -------------------------------------------------------------------------------- 1 | # Install Canny integration on Missive 2 | Example 3 | 4 | ## Setup and copy webhook from Missive 5 | Copy webhook 6 | 7 | ## Add a webhook in your Canny settings 8 | Add webhook 9 | -------------------------------------------------------------------------------- /docs/integrations/canny/add-webhook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/missive/missive-webhooks/437a833897a80a64331902fd1c1df4d3cccb1ef6/docs/integrations/canny/add-webhook.png -------------------------------------------------------------------------------- /docs/integrations/canny/copy-webhook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/missive/missive-webhooks/437a833897a80a64331902fd1c1df4d3cccb1ef6/docs/integrations/canny/copy-webhook.png -------------------------------------------------------------------------------- /docs/integrations/canny/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/missive/missive-webhooks/437a833897a80a64331902fd1c1df4d3cccb1ef6/docs/integrations/canny/example.png -------------------------------------------------------------------------------- /docs/integrations/github/README.md: -------------------------------------------------------------------------------- 1 | # Install GitHub integration on Missive 2 | Example 3 | 4 | ## Setup and copy webhook from Missive 5 | Copy webhook 6 | 7 | ## Add an `application/json` webhook to your GitHub repo 8 | Add webhook 9 | -------------------------------------------------------------------------------- /docs/integrations/github/add-webhook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/missive/missive-webhooks/437a833897a80a64331902fd1c1df4d3cccb1ef6/docs/integrations/github/add-webhook.png -------------------------------------------------------------------------------- /docs/integrations/github/copy-webhook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/missive/missive-webhooks/437a833897a80a64331902fd1c1df4d3cccb1ef6/docs/integrations/github/copy-webhook.png -------------------------------------------------------------------------------- /docs/integrations/github/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/missive/missive-webhooks/437a833897a80a64331902fd1c1df4d3cccb1ef6/docs/integrations/github/example.png -------------------------------------------------------------------------------- /docs/integrations/heroku/README.md: -------------------------------------------------------------------------------- 1 | # Install Heroku integration on Missive 2 | Example 3 | 4 | ## Setup and copy webhook from Missive 5 | Copy webhook 6 | 7 | ## Add a `Deploy Hooks (HTTP Post Hook)` add-on to your Heroku app 8 | https://dashboard.heroku.com/apps/YOUR_APP/resources/new?addonService=deployhooks 9 | 10 | Add webhook: Step 1 11 | Add webhook: Step 2 12 | -------------------------------------------------------------------------------- /docs/integrations/heroku/add-webhook-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/missive/missive-webhooks/437a833897a80a64331902fd1c1df4d3cccb1ef6/docs/integrations/heroku/add-webhook-1.png -------------------------------------------------------------------------------- /docs/integrations/heroku/add-webhook-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/missive/missive-webhooks/437a833897a80a64331902fd1c1df4d3cccb1ef6/docs/integrations/heroku/add-webhook-2.png -------------------------------------------------------------------------------- /docs/integrations/heroku/copy-webhook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/missive/missive-webhooks/437a833897a80a64331902fd1c1df4d3cccb1ef6/docs/integrations/heroku/copy-webhook.png -------------------------------------------------------------------------------- /docs/integrations/heroku/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/missive/missive-webhooks/437a833897a80a64331902fd1c1df4d3cccb1ef6/docs/integrations/heroku/example.png -------------------------------------------------------------------------------- /docs/integrations/rollbar/README.md: -------------------------------------------------------------------------------- 1 | # Install Rollbar integration on Missive 2 | Example 3 | 4 | ## Setup and copy webhook from Missive 5 | `Account` and `Project` are required for Rollbar integration. 6 | 7 | Copy webhook 8 | 9 | ## Configure `Webhook` channel in your project’s Notifications settings 10 | https://rollbar.com/ACCOUNT/PROJECT/settings/notifications/webhook/ 11 | 12 | Add webhook 13 | -------------------------------------------------------------------------------- /docs/integrations/rollbar/add-webhook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/missive/missive-webhooks/437a833897a80a64331902fd1c1df4d3cccb1ef6/docs/integrations/rollbar/add-webhook.png -------------------------------------------------------------------------------- /docs/integrations/rollbar/copy-webhook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/missive/missive-webhooks/437a833897a80a64331902fd1c1df4d3cccb1ef6/docs/integrations/rollbar/copy-webhook.png -------------------------------------------------------------------------------- /docs/integrations/rollbar/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/missive/missive-webhooks/437a833897a80a64331902fd1c1df4d3cccb1ef6/docs/integrations/rollbar/example.png -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | const Canny = require('./integrations/canny') 2 | const GitHub = require('./integrations/github') 3 | const Heroku = require('./integrations/heroku') 4 | const Rollbar = require('./integrations/rollbar') 5 | 6 | module.exports = { 7 | canny: new Canny, 8 | github: new GitHub, 9 | heroku: new Heroku, 10 | rollbar: new Rollbar, 11 | } 12 | -------------------------------------------------------------------------------- /lib/integration.js: -------------------------------------------------------------------------------- 1 | class Integration { 2 | get name() { return this.constructor.name } 3 | get avatar() { return `https://raw.githubusercontent.com/missive/missive-webhooks/master/assets/integrations/${this.id}.png` } 4 | get icon() { return `https://raw.githubusercontent.com/missive/missive-webhooks/master/assets/integrations/${this.id}.png` } 5 | get schema() { return { options: [] } } 6 | 7 | link(url, label) { 8 | if (this.sanitizing) { 9 | return label || url 10 | } 11 | 12 | if (label) { 13 | return `<${url}|${label}>` 14 | } else { 15 | return `<${url}>` 16 | } 17 | } 18 | 19 | codeLink(url, label) { 20 | return this.link(url, `\`${label}\``) 21 | } 22 | 23 | sanitize(callbacks) { 24 | if (!Array.isArray(callbacks)) callbacks = [callbacks] 25 | 26 | let chunks = [] 27 | let sanitizedChunks = [] 28 | 29 | let exec = () => { 30 | return callbacks.map((cb) => cb()).join('') 31 | } 32 | 33 | let string = new String(exec()) 34 | string.callbacks = callbacks 35 | string.add = (callback) => { 36 | return this.sanitize(string.callbacks.concat(callback)) 37 | } 38 | 39 | this.sanitizing = true 40 | string.sanitized = exec() 41 | this.sanitizing = false 42 | 43 | return string 44 | } 45 | 46 | capitalize(string) { 47 | if (!string) return '' 48 | return string.charAt(0).toUpperCase() + string.substring(1).toLowerCase() 49 | } 50 | 51 | toJSON() { 52 | return { 53 | id: this.id, 54 | name: this.name, 55 | avatar: this.avatar, 56 | icon: this.icon, 57 | schema: this.schema, 58 | } 59 | } 60 | } 61 | 62 | module.exports = Integration 63 | -------------------------------------------------------------------------------- /lib/integrations/canny.js: -------------------------------------------------------------------------------- 1 | const Integration = require('../integration') 2 | 3 | const COLORS = { 4 | comment: '#999', 5 | vote: '#535df0', 6 | status: { 7 | open: '#999', 8 | under_review: '#85b5b5', 9 | planned: '#1fa0ff', 10 | in_progress: '#c17aff', 11 | complete: '#6dd345', 12 | closed: '#ed2b2b', 13 | }, 14 | } 15 | 16 | class Canny extends Integration { 17 | get id() { return 'canny' } 18 | 19 | process(payload, req) { 20 | let type = payload.type.replace('.', '_') 21 | 22 | if (this[type]) { 23 | return this[type](payload) 24 | } 25 | } 26 | 27 | // Supported event types 28 | post_created(payload) { 29 | let { object } = payload 30 | let { id, author, board, details, title, url, imageURLs } = object 31 | 32 | let pretext = this.sanitize(() => `${author.name} created a new post in ${this.boardLink(board)}`) 33 | let imageURL = undefined 34 | let color = this.getColorForPost(object) 35 | 36 | if (imageURLs && imageURLs.length) { 37 | imageURL = imageURLs[0] 38 | } 39 | 40 | return { 41 | references: [`${board.id}/${id}`], 42 | subject: title, 43 | color: color, 44 | notification: pretext.sanitized, 45 | attachment: { 46 | pretext: pretext.toString(), 47 | title: title, 48 | title_link: url, 49 | text: details, 50 | image_url: imageURL, 51 | color: color, 52 | } 53 | } 54 | } 55 | 56 | post_status_changed(payload) { 57 | let { object } = payload 58 | let { id, board, title, status, changeComment } = object 59 | 60 | let text = this.sanitize(() => `${this.postLink(object, board)} has been marked as *${status}*`) 61 | let color = this.getColorForPost(object) 62 | 63 | let attachments = [ 64 | { 65 | text: text.toString(), 66 | color: color, 67 | } 68 | ] 69 | 70 | if (changeComment) { 71 | let { imageURLs, value } = changeComment 72 | let imageURL = undefined 73 | 74 | if (imageURLs && imageURLs.length) { 75 | imageURL = imageURLs[0] 76 | } 77 | 78 | if (value || imageURL) { 79 | attachments.push({ 80 | text: value, 81 | image_url: imageURL, 82 | color: COLORS.comment, 83 | }) 84 | } 85 | } 86 | 87 | return { 88 | references: [`${board.id}/${id}`], 89 | subject: title, 90 | color: color, 91 | notification: text.sanitized, 92 | attachments: attachments, 93 | } 94 | } 95 | 96 | vote_created(payload) { 97 | let { object } = payload 98 | let { board, post } = object 99 | 100 | if (post.score % 5) return 101 | 102 | let text = this.sanitize(() => `${this.postLink(post, board)} hit *${post.score} votes*`) 103 | 104 | return { 105 | references: [`${board.id}/${post.id}`], 106 | subject: post.title, 107 | color: this.getColorForPost(post), 108 | notification: text.sanitized, 109 | attachment: { 110 | text: text.toString(), 111 | color: COLORS.vote, 112 | } 113 | } 114 | } 115 | 116 | comment_created(payload) { 117 | let { object } = payload 118 | let { author, board, post, value, imageURLs } = object 119 | 120 | let pretext = this.sanitize(() => `${author.name} posted a new comment in ${this.postLink(post, board)}`) 121 | let imageURL = undefined 122 | 123 | if (imageURLs && imageURLs.length) { 124 | imageURL = imageURLs[0] 125 | } 126 | 127 | return { 128 | references: [`${board.id}/${post.id}`], 129 | subject: post.title, 130 | color: this.getColorForPost(post), 131 | notification: pretext.sanitized, 132 | attachment: { 133 | pretext: pretext.toString(), 134 | text: value, 135 | color: COLORS.comment, 136 | image_url: imageURL, 137 | } 138 | } 139 | } 140 | 141 | // Helpers 142 | getColorForPost(post) { 143 | let { status } = post 144 | status = status.replace(/\s/g, '_') 145 | 146 | return COLORS.status[status] 147 | } 148 | 149 | boardLink(board) { 150 | return this.link(board.url, board.name) 151 | } 152 | 153 | postLink(post, board) { 154 | let title = post.title 155 | 156 | if (board) { 157 | title = `${board.name}: ${title}` 158 | } 159 | 160 | return this.link(post.url, title) 161 | } 162 | } 163 | 164 | module.exports = Canny 165 | -------------------------------------------------------------------------------- /lib/integrations/github.js: -------------------------------------------------------------------------------- 1 | const Integration = require('../integration') 2 | 3 | const COLORS = { 4 | commit: '#0093ce', 5 | commitComment: '#00acf0', 6 | issue: '#de5c00', 7 | issueComment: '#ff7d22', 8 | pr: '#009e61', 9 | prComment: '#00c76e', 10 | rejected: '#c6474e', 11 | deploy: '#430098', 12 | } 13 | 14 | class GitHub extends Integration { 15 | get id() { return 'github' } 16 | 17 | process(payload, req) { 18 | let type = req.get('X-GitHub-Event') 19 | let contentType = req.get('Content-Type') 20 | 21 | if (contentType == 'application/x-www-form-urlencoded') { 22 | if (payload && payload.payload) { 23 | payload = JSON.parse(`${payload.payload}`) 24 | } 25 | } 26 | 27 | if (this[type]) { 28 | return this[type](payload) 29 | } 30 | } 31 | 32 | // Supported event types 33 | ping (payload) { 34 | return { references: ['pong'] } 35 | } 36 | 37 | commit_comment (payload) { 38 | if (['created'].indexOf(payload.action) == -1) return 39 | 40 | var { comment, repository, sender } = payload 41 | var pretext = this.sanitize(() => `New comment by ${sender.login} on commit ${this.link(comment.html_url, this.shortCommit(comment.commit_id))}`) 42 | 43 | if (comment.line) { 44 | pretext = pretext.add(() => ` on line ${comment.line}`) 45 | } 46 | 47 | return { 48 | references: this.referencesForRepository(repository), 49 | subject: this.subjectForRepository(repository), 50 | notification: pretext.sanitized, 51 | attachment: { 52 | pretext: pretext.toString(), 53 | markdown: comment.body, 54 | color: COLORS.commitComment, 55 | } 56 | } 57 | } 58 | 59 | create (payload) { 60 | if (['tag'].indexOf(payload.ref_type) == -1) return 61 | 62 | var { ref, ref_type, repository, sender } = payload 63 | var text = this.sanitize(() => `New ${ref_type} ${this.branchLink(ref, repository)} was pushed by ${sender.login}`) 64 | 65 | return { 66 | references: this.referencesForRepository(repository), 67 | subject: this.subjectForRepository(repository), 68 | notification: text.sanitized, 69 | attachment: { 70 | text: text.toString(), 71 | color: COLORS.commit, 72 | } 73 | } 74 | } 75 | 76 | delete (payload) { 77 | if (['tag'].indexOf(payload.ref_type) == -1) return 78 | 79 | var { ref, ref_type, repository, sender } = payload 80 | var text = this.sanitize(() => `The ${ref_type} “${ref}” was deleted by ${sender.login}`) 81 | 82 | return { 83 | references: this.referencesForRepository(repository), 84 | subject: this.subjectForRepository(repository), 85 | notification: text.sanitized, 86 | attachment: { text: text.toString() }, 87 | } 88 | } 89 | 90 | deployment (payload) { /* TODO */ } 91 | 92 | deployment_status (payload) { 93 | const { deployment_status, deployment, sender, repository } = payload 94 | if (['success', 'failure'].indexOf(payload.deployment_status.state) == -1) return 95 | 96 | var text, color 97 | 98 | if (deployment_status.state == 'success') { 99 | text = this.sanitize(() => `${sender.login} ${this.link(deployment_status.target_url, 'deployed')} ${this.commitLink(deployment.sha, repository)} to ${this.link(deployment.payload.web_url, deployment.environment)}`) 100 | color = COLORS.deploy 101 | } else if (deployment_status.state == 'failure') { 102 | text = this.sanitize(() => `${sender.login} ${this.link(deployment_status.target_url, 'failed to deploy')} ${this.commitLink(deployment.sha, repository)} to ${this.link(deployment.payload.web_url, deployment.environment)}`) 103 | color = COLORS.rejected 104 | } 105 | 106 | var notification = text.sanitized 107 | text = text.toString() 108 | 109 | return { 110 | references: this.referencesForRepository(repository), 111 | subject: this.subjectForRepository(repository), 112 | notification: notification, 113 | attachment: { text, color }, 114 | } 115 | } 116 | 117 | fork (payload) { /* TODO */ } 118 | gollum (payload) { /* TODO */ } 119 | 120 | issue_comment(payload) { 121 | if (['created'].indexOf(payload.action) == -1) return 122 | 123 | var { issue, comment, repository, sender } = payload 124 | var pretext = this.sanitize(() => `New ${this.link(comment.html_url, 'comment')} by ${sender.login}`) 125 | var isPR = /\/pull\/\d+$/.test(issue.html_url) 126 | 127 | return { 128 | references: this.referencesForIssue(issue, repository), 129 | subject: this.subjectForIssue(issue, repository), 130 | notification: pretext.sanitized, 131 | attachment: { 132 | pretext: pretext.toString(), 133 | markdown: comment.body, 134 | color: isPR ? COLORS.prComment : COLORS.issueComment, 135 | } 136 | } 137 | } 138 | 139 | issues(payload) { 140 | if (['opened', 'closed', 'reopened'].indexOf(payload.action) == -1) return 141 | var { issue, repository, sender } = payload 142 | 143 | var title, title_link, text, markdown, color, pretext = this.sanitize(() => `${this.link(issue.html_url, 'Issue')} ${payload.action} by ${sender.login}`) 144 | var notification = pretext.sanitized 145 | 146 | if (payload.action == 'opened') { 147 | title = issue.title 148 | title_link = issue.html_url 149 | markdown = issue.body 150 | pretext = pretext.toString() 151 | } else { 152 | text = pretext.toString() 153 | pretext = undefined 154 | } 155 | 156 | if (payload.action != 'closed') { 157 | color = COLORS.issue 158 | } 159 | 160 | return { 161 | references: this.referencesForIssue(issue, repository), 162 | subject: this.subjectForIssue(issue, repository), 163 | notification: notification, 164 | attachment: { title, title_link, pretext, text, markdown, color }, 165 | } 166 | } 167 | 168 | member (payload) { 169 | if (['added'].indexOf(payload.action) == -1) return 170 | 171 | var { member, repository, sender } = payload 172 | var text = this.sanitize(() => `${sender.login} added ${this.userLink(member)} as a collaborator`) 173 | 174 | return { 175 | references: this.referencesForRepository(repository), 176 | subject: this.subjectForRepository(repository), 177 | attachment: { text: text.toString() }, 178 | } 179 | } 180 | 181 | page_build (payload) { 182 | if (['built', 'errored'].indexOf(payload.build.status) == -1) return 183 | 184 | var { build, repository } = payload 185 | var text 186 | 187 | switch (build.status) { 188 | case 'built': 189 | text = this.sanitize(() => `Page was successfully built: ${this.pageLink(repository)}`) 190 | break 191 | 192 | case 'errored': 193 | text = this.sanitize(() => `There was an error building the page: ${this.pageLink(repository)}`) 194 | break 195 | } 196 | 197 | return { 198 | references: this.referencesForRepository(repository), 199 | subject: this.subjectForRepository(repository), 200 | notification: text.sanitized, 201 | attachment: { text: text.toString() }, 202 | } 203 | } 204 | 205 | public (payload) { 206 | var { repository, sender } = payload 207 | var text = this.sanitize(() => `${sender.login} open sourced ${this.link(repository.html_url, repository.name)}`) 208 | 209 | return { 210 | references: this.referencesForRepository(repository), 211 | subject: this.subjectForRepository(repository), 212 | attachment: { text: text.toString() }, 213 | } 214 | } 215 | 216 | pull_request(payload) { 217 | if (['opened', 'closed', 'reopened', 'assigned', 'unassigned', 'review_requested', 'review_request_removed'].indexOf(payload.action) == -1) return 218 | 219 | var { action, pull_request, repository, sender } = payload 220 | var title, title_link, text, pretext, markdown, color, notification 221 | 222 | if (action == 'closed' && pull_request.merged) { 223 | action = 'merged' 224 | } 225 | 226 | if (action == 'assigned' || action == 'unassigned') { 227 | var { assignee } = payload 228 | var fromTo = action == 'assigned' ? 'to' : 'from' 229 | 230 | pretext = this.sanitize(() => `${sender.login} ${action} ${assignee.login} ${fromTo} ${this.pullRequestLink(pull_request, repository)}`) 231 | } else if (action == 'review_requested' || action == 'review_request_removed') { 232 | var { requested_reviewer } = payload 233 | var theAction = '' 234 | 235 | if (action == 'review_requested') { 236 | theAction = 'requested a review' 237 | } else { 238 | theAction = 'removed the review request' 239 | } 240 | 241 | pretext = this.sanitize(() => `${sender.login} ${theAction} from ${requested_reviewer.login} on ${this.pullRequestLink(pull_request, repository)}`) 242 | } else { 243 | pretext = this.sanitize(() => `${this.pullRequestLink(pull_request, repository)} ${action} by ${sender.login}`) 244 | } 245 | 246 | notification = pretext.sanitized 247 | 248 | if (action == 'opened') { 249 | title = pull_request.title 250 | title_link = pull_request.html_url 251 | markdown = pull_request.body 252 | pretext = pretext.toString() 253 | } else { 254 | text = pretext.toString() 255 | pretext = undefined 256 | } 257 | 258 | if (action != 'closed') { 259 | color = COLORS.pr 260 | } 261 | 262 | return { 263 | references: this.referencesForIssue(pull_request, repository), 264 | subject: this.subjectForIssue(pull_request, repository), 265 | update_existing_conversation_subject: true, 266 | notification: notification, 267 | attachment: { title, title_link, pretext, text, markdown, color }, 268 | } 269 | } 270 | 271 | pull_request_review(payload) { 272 | if (['submitted'].indexOf(payload.action) == -1) return 273 | 274 | var { pull_request, review, repository, sender } = payload 275 | var pretext, color = COLORS.prComment 276 | 277 | if (review.state == 'changes_requested') { 278 | pretext = this.sanitize(() => `New changes requested by ${sender.login} in ${this.link(review.html_url, 'review')}`) 279 | color = COLORS.rejected 280 | } else if (review.state == 'approved') { 281 | pretext = this.sanitize(() => `New changes approved by ${sender.login} in ${this.link(review.html_url, 'review')}`) 282 | } else { 283 | if (!review.body) return 284 | pretext = this.sanitize(() => `New ${this.link(review.html_url, 'review')} by ${sender.login}`) 285 | } 286 | 287 | return { 288 | references: this.referencesForIssue(pull_request, repository), 289 | subject: this.subjectForIssue(pull_request, repository), 290 | notification: pretext.sanitized, 291 | attachment: { 292 | pretext: pretext.toString(), 293 | markdown: review.body, 294 | color: color, 295 | } 296 | } 297 | } 298 | 299 | pull_request_review_comment(payload) { 300 | if (['created'].indexOf(payload.action) == -1) return 301 | 302 | var { pull_request, comment, repository, sender } = payload 303 | var pretext = this.sanitize(() => `New ${this.link(comment.html_url, 'comment')} by ${sender.login}`) 304 | 305 | return { 306 | references: this.referencesForIssue(pull_request, repository), 307 | subject: this.subjectForIssue(pull_request, repository), 308 | notification: pretext.sanitized, 309 | attachment: { 310 | pretext: pretext.toString(), 311 | markdown: comment.body, 312 | color: COLORS.prComment, 313 | } 314 | } 315 | } 316 | 317 | push (payload) { 318 | var { ref, created, deleted, forced, head_commit, compare, commits, repository, sender } = payload 319 | var text = [], pretext, notification, branch, size, includeCommits, color 320 | 321 | if (!ref.startsWith('refs/heads/')) return 322 | 323 | branch = ref.replace('refs/heads/', '') 324 | if (branch.startsWith('gh-readonly-queue')) return 325 | 326 | size = commits.length 327 | color = COLORS.commit 328 | 329 | if (created) { 330 | pretext = this.sanitize(() => `${sender.login} created new branch ${this.branchLink(branch, repository)}`) 331 | if (size > 0) { 332 | pretext = pretext.add(() => ' and') 333 | includeCommits = true 334 | } 335 | } else if (deleted) { 336 | pretext = this.sanitize(() => `${sender.login} deleted “${branch}”`) 337 | color = undefined 338 | } else if (forced) { 339 | pretext = this.sanitize(() => `${sender.login} force-pushed ${this.branchLink(branch, repository)} to ${this.link(this.commitUrl(head_commit), this.shortCommit(head_commit.id))}`) 340 | } else { 341 | pretext = this.sanitize(() => `${sender.login}`) 342 | includeCommits = true 343 | } 344 | 345 | const referencedConversations = [] 346 | 347 | if (includeCommits && size > 0) { 348 | pretext = pretext.add(() => ` pushed ${this.link(compare, `${size} new commit${size > 1 ? 's' : ''}`)} to ${this.branchLink(branch, repository)}`) 349 | commits.forEach((commit) => { 350 | const msg = commit.message.split('\n')[0] 351 | let line = `${this.codeLink(this.commitUrl(commit), this.shortCommit(commit.id))} ${msg}` 352 | 353 | if (commit.author.username && commit.author.username.toLowerCase() != sender.login.toLowerCase()) { 354 | line += ` - ${commit.author.username}` 355 | } 356 | 357 | // Detect if commit contains conversation links 358 | if (commit.distinct) { 359 | const protocols = ['https', 'missive'] 360 | const domain = 'mail.missiveapp.com' 361 | const mailboxType = '(?:[^\/]+)' 362 | const uuid = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" 363 | const regex = new RegExp(`(?:${protocols.join('|')}):\/\/${domain}\/#${mailboxType}.*\/conversations\/(${uuid})`, 'gi') 364 | 365 | let match 366 | while (match = regex.exec(commit.message)) { 367 | const conversation = match[1] 368 | referencedConversations.push({ conversation, commit }) 369 | } 370 | } 371 | 372 | text.push(line) 373 | }) 374 | 375 | text = text.join('\n') 376 | } 377 | 378 | notification = pretext.sanitized 379 | pretext = pretext.toString() 380 | 381 | if (!text.length) { 382 | text = pretext 383 | pretext = undefined 384 | } 385 | 386 | return { 387 | references: [`${repository.id}/${branch}`], 388 | subject: this.subjectForRepository(null, repository, branch), 389 | notification: notification, 390 | attachment: { pretext, text, color }, 391 | callback: (conversationId, { createPost }) => { 392 | if (!referencedConversations.length) return 393 | for (const { conversation, commit } of referencedConversations) { 394 | if (conversationId == conversation) continue 395 | 396 | let text = this.sanitize(() => `${commit.author.username} referenced this conversation in ${this.codeLink(this.commitUrl(commit), this.repositoryCommit(repository, commit))}`) 397 | 398 | const notification = text.sanitized 399 | const color = COLORS.commit 400 | text = text.toString() 401 | 402 | createPost({ 403 | conversation: conversation, 404 | notification: notification, 405 | attachment: { text, color }, 406 | }) 407 | } 408 | }, 409 | } 410 | } 411 | 412 | release (payload) { /* TODO */ } 413 | repository (payload) { /* TODO */ } 414 | status (payload) { /* TODO */ } 415 | team_add (payload) { /* TODO */ } 416 | watch (payload) { /* TODO */ } 417 | 418 | // Helpers 419 | userLink(user) { 420 | return this.link(user.html_url, user.login) 421 | } 422 | 423 | pageLink(repository) { 424 | return this.link(`https://${repository.owner.login}.github.io/${repository.name}`) 425 | } 426 | 427 | branchLink(branch, repository) { 428 | return this.link(`${repository.html_url}/tree/${branch}`, `${repository.name}/${branch}`) 429 | } 430 | 431 | pullRequestLink(pull_request, repository) { 432 | return this.link(`${pull_request.html_url}`, `${repository.name}/${pull_request.number}`) 433 | } 434 | 435 | commitLink(commitId, repository) { 436 | return this.codeLink(`${repository.html_url}/commit/${commitId}`, this.shortCommit(commitId)) 437 | } 438 | 439 | repositoryCommit(repository, commit) { 440 | return `${repository.full_name}@${this.shortCommit(commit.id)}` 441 | } 442 | 443 | shortCommit(commitId) { 444 | return commitId.substr(0, 7) 445 | } 446 | 447 | commitUrl(commit) { 448 | return `${commit.url}?w=1` 449 | } 450 | 451 | referencesForRepository(repository, ref = 'master') { 452 | return [`${repository.id}/${ref}`] 453 | } 454 | 455 | referencesForIssue(issue, repository) { 456 | let references = [`${repository.id}/${issue.number}`] 457 | 458 | // When `issue` is a pull-request from the same repo, 459 | // add branch reference so that everything related to that PR 460 | // is added to the branch conversation 461 | if (issue.head && issue.head.repo.id == repository.id) { 462 | let branch = issue.head.ref 463 | references.unshift(`${repository.id}/${branch}`) 464 | } 465 | 466 | return references 467 | } 468 | 469 | subjectForIssue(issue, repository) { 470 | let { number, title, head } = issue 471 | let subject = `#${number} ${title}` 472 | let branch 473 | 474 | // When `issue` is a pull-request from the same repo, 475 | // add branch to the subject 476 | if (head && head.repo.id == repository.id) { 477 | branch = head.ref 478 | } 479 | 480 | return this.subjectForRepository(subject, repository, branch) 481 | } 482 | 483 | subjectForRepository(subject, repository, branch) { 484 | if (!repository) { 485 | repository = subject 486 | subject = null 487 | } 488 | 489 | let repoName = `[${repository.name}${branch ? `:${branch}` : ''}]` 490 | 491 | if (!subject) { 492 | return repoName 493 | } else { 494 | return `${subject} ${repoName}` 495 | } 496 | } 497 | } 498 | 499 | module.exports = GitHub 500 | -------------------------------------------------------------------------------- /lib/integrations/heroku.js: -------------------------------------------------------------------------------- 1 | const Integration = require('../integration') 2 | 3 | class Heroku extends Integration { 4 | get deprecated() { return true } 5 | get id() { return 'heroku' } 6 | 7 | process(payload, req) { 8 | var { app, user, url, head, git_log, release } = payload 9 | var pretext = this.sanitize(() => `${user} deployed version *${release || head}* of ${this.link(url, app)}`) 10 | 11 | return { 12 | references: [app], 13 | subject: app, 14 | notification: pretext.sanitized, 15 | attachment: { 16 | pretext: pretext.toString(), 17 | markdown: git_log, 18 | color: '#430098', 19 | } 20 | } 21 | } 22 | } 23 | 24 | module.exports = Heroku 25 | -------------------------------------------------------------------------------- /lib/integrations/rollbar.js: -------------------------------------------------------------------------------- 1 | const Integration = require('../integration') 2 | 3 | const COLORS = { 4 | resolved: '#009e61', 5 | level: { 6 | critical: '#c00', 7 | error: '#c00', 8 | warning: '#ffc258', 9 | info: '#0093ce', 10 | debug: '#bab6b6', 11 | }, 12 | } 13 | 14 | class Rollbar extends Integration { 15 | get id() { return 'rollbar' } 16 | get schema() { 17 | return { 18 | options: [ 19 | { key: 'account', type: 'String', required: true }, 20 | { key: 'project', type: 'String', required: true }, 21 | ] 22 | } 23 | } 24 | 25 | process(payload, req, options) { 26 | let { event_name, data } = payload 27 | this.options = options || {} 28 | 29 | if (this[event_name]) { 30 | return this[event_name](data) 31 | } 32 | } 33 | 34 | // Supported event types 35 | test(payload) { 36 | return { references: ['test'] } 37 | } 38 | 39 | deploy(payload) { 40 | let { deploy } = payload 41 | } 42 | 43 | exp_repeat_item(payload) { 44 | let { item, occurrences } = payload 45 | let { title } = item 46 | let text = this.sanitize(() => `${occurrences}th occurrence: ${title.replace('\n', '')}\n${this.linksForItem(item)}`) 47 | 48 | return { 49 | references: [item.id], 50 | subject: item.title, 51 | notification: text.sanitized, 52 | attachment: { 53 | text: text.toString(), 54 | color: COLORS.level.info, 55 | } 56 | } 57 | } 58 | 59 | item_velocity(payload) { 60 | let { item, trigger } = payload 61 | let { title } = item 62 | let text = this.sanitize(() => `${trigger.threshold} occurrences in ${trigger.window_size_description}: ${title.replace('\n', '')}\n${this.linksForItem(item)}`) 63 | 64 | return { 65 | references: [item.id], 66 | subject: item.title, 67 | notification: text.sanitized, 68 | attachment: { 69 | text: text.toString(), 70 | color: COLORS.level.info, 71 | } 72 | } 73 | } 74 | 75 | new_item(payload) { 76 | let { item } = payload 77 | let { title } = item 78 | let text = this.sanitize(() => `New item: ${title.replace('\n', '')}\n${this.linksForItem(item)}`) 79 | 80 | return { 81 | references: [item.id], 82 | subject: item.title, 83 | notification: text.sanitized, 84 | attachment: { 85 | color: COLORS.level.info, 86 | text: text.toString(), 87 | } 88 | } 89 | } 90 | 91 | occurrence(payload) { 92 | let { item, occurrence } = payload 93 | let { title } = item 94 | let { version, person, client, level } = occurrence 95 | 96 | let text = this.sanitize(() => `${title.replace('\n', '')} (${this.capitalize(level)})\n${this.linksForItem(item, true)}`) 97 | let color = COLORS.level[level] || COLORS.level.error 98 | let fields = [] 99 | 100 | if (person) { 101 | fields.push({ 102 | title: 'User', 103 | value: person.email || person.id, 104 | short: true, 105 | }) 106 | } 107 | 108 | if (version) { 109 | fields.push({ 110 | title: 'Version', 111 | value: version, 112 | short: true, 113 | }) 114 | } 115 | 116 | return { 117 | references: [item.id], 118 | subject: item.title, 119 | color: color, 120 | notification: text.sanitized, 121 | attachment: { 122 | text: text.toString(), 123 | color: color, 124 | fields: fields, 125 | } 126 | } 127 | } 128 | 129 | reactivated_item(payload) { 130 | let { item } = payload 131 | let { title } = item 132 | let text = this.sanitize(() => `Reactivated: ${title.replace('\n', '')}\n${this.linksForItem(item)}`) 133 | 134 | return { 135 | references: [item.id], 136 | subject: item.title, 137 | notification: text.sanitized, 138 | attachment: { 139 | color: COLORS.level.info, 140 | text: text.toString(), 141 | } 142 | } 143 | } 144 | 145 | reopened_item(payload) { 146 | let { item } = payload 147 | let { title } = item 148 | let text = this.sanitize(() => `Reopened: ${title.replace('\n', '')}\n${this.linksForItem(item)}`) 149 | 150 | return { 151 | references: [item.id], 152 | subject: item.title, 153 | notification: text.sanitized, 154 | attachment: { 155 | color: COLORS.level.info, 156 | text: text.toString(), 157 | } 158 | } 159 | } 160 | 161 | resolved_item(payload) { 162 | let { item } = payload 163 | let { title } = item 164 | let text = this.sanitize(() => `Resolved: ${title.replace('\n', '')}\n${this.linksForItem(item)}`) 165 | let color = COLORS.resolved 166 | 167 | return { 168 | references: [item.id], 169 | subject: item.title, 170 | color: color, 171 | notification: text.sanitized, 172 | attachment: { 173 | color: color, 174 | text: text.toString(), 175 | } 176 | } 177 | } 178 | 179 | // Helpers 180 | linksForItem(item, occurrence) { 181 | let { counter, last_occurrence_id } = item 182 | 183 | let baseURL = `https://rollbar.com/${this.options.account}/${this.options.project}` 184 | let itemURL = `${baseURL}/items/${counter}` 185 | 186 | if (occurrence) { 187 | let occurrenceURL = `${itemURL}/occurrences/${last_occurrence_id}` 188 | return `${this.link(itemURL)} (${this.link(occurrenceURL, 'Occurrence')})` 189 | } else { 190 | return this.link(itemURL) 191 | } 192 | } 193 | } 194 | 195 | module.exports = Rollbar 196 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "missive-webhooks", 3 | "version": "1.0.0", 4 | "description": "Missive built-in integrations", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "start": "node server.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+ssh://git@github.com/missive/missive-webhooks.git" 12 | }, 13 | "author": "", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/missive/missive-webhooks/issues" 17 | }, 18 | "homepage": "https://github.com/missive/missive-webhooks#readme", 19 | "dependencies": { 20 | "atob": "2.1.2", 21 | "body-parser": "1.18.2", 22 | "cors": "2.8.5", 23 | "express": "4.18.2", 24 | "request": "2.88.2", 25 | "rollbar": "2.4.2" 26 | }, 27 | "devDependencies": { 28 | "dotenv": "4.0.0" 29 | }, 30 | "engines": { 31 | "node": "18.14.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV || (process.env.NODE_ENV = 'development') 2 | if (process.env.NODE_ENV != 'production') { 3 | require('dotenv').config() 4 | } 5 | 6 | const Atob = require('atob') 7 | const BodyParser = require('body-parser') 8 | const Express = require('express') 9 | const Port = process.env.PORT || 8080 10 | const Request = require('request') 11 | const Rollbar = require('rollbar') 12 | const Cors = require('cors') 13 | 14 | const Integrations = require('.') 15 | 16 | let app = Express() 17 | app.disable('x-powered-by') 18 | app.use(BodyParser.json({ limit: '10mb' })) 19 | app.use(BodyParser.urlencoded({ extended: true, limit: '10mb' })) 20 | app.use(Cors()) 21 | 22 | app.use((req, res, next) => { 23 | res.header('Content-Security-Policy', "default-src 'none'; style-src 'unsafe-inline'") 24 | res.header('X-Content-Type-Options', 'nosniff') 25 | res.header('X-Frame-Options', 'SAMEORIGIN') 26 | res.header('X-XSS-Protection', '1; mode=block') 27 | 28 | // Force HTTPS 29 | if (req.secure || req.header('X-Forwarded-Proto') == 'https') { 30 | res.header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains') 31 | return next() 32 | } 33 | res.redirect(`https://${req.hostname}${req.url}`) 34 | }) 35 | 36 | app.post('/:provider', (req, res) => { 37 | let { provider } = req.params 38 | let integration, base64JSON = req.query.t 39 | 40 | let notFound = () => { 41 | res.status(404).send(`Integration not found: ${provider}`) 42 | } 43 | 44 | if (!base64JSON) { 45 | return notFound() 46 | } 47 | 48 | let data = null 49 | try { 50 | data = JSON.parse(Atob(base64JSON)) 51 | } catch (e) { 52 | return notFound() 53 | } 54 | 55 | const { token: bearer, options } = data 56 | 57 | const createPost = (payload = {}) => { 58 | const posts = JSON.parse(JSON.stringify(options || {})) 59 | 60 | const { references, conversation, subject, color, update_existing_conversation_subject, attachment, text, markdown, notification, callback } = payload 61 | const attachments = attachment ? [attachment] : payload.attachments 62 | 63 | if ((references || conversation) && (text || markdown || attachments)) { 64 | posts.username = integration.name 65 | posts.username_icon = integration.avatar 66 | posts.text = text 67 | posts.markdown = markdown 68 | posts.attachments = attachments 69 | posts.notification = { 70 | title: subject, 71 | body: notification, 72 | } 73 | 74 | if (conversation) { 75 | posts.conversation = conversation 76 | delete posts.organization 77 | delete posts.add_shared_labels 78 | delete posts.add_users 79 | } else { 80 | posts.references = references.map((ref) => `<${provider}/${ref}@missive-integrations>`) 81 | posts.conversation_subject = subject 82 | posts.conversation_color = color 83 | posts.update_existing_conversation_subject = update_existing_conversation_subject || false 84 | posts.conversation_icon = integration.icon 85 | } 86 | 87 | return Request.post({ 88 | baseUrl: process.env.MISSIVE_API_BASE_URL, 89 | uri: '/posts', 90 | json: { posts }, 91 | auth: { bearer }, 92 | callback: (err, response, body) => { 93 | if (err) return 94 | callback && callback(body.posts.conversation, { createPost }) 95 | }, 96 | }) 97 | } 98 | } 99 | 100 | if (integration = Integrations[provider]) { 101 | const payload = integration.process(req.body, req, data[provider]) 102 | const request = createPost(payload) 103 | 104 | if (request) { 105 | return request.pipe(res) 106 | } 107 | 108 | return res.status(200).send('Event type not implemented') 109 | } 110 | 111 | notFound() 112 | }) 113 | 114 | app.post('/', (req, res) => { 115 | res.send('Pong') 116 | }) 117 | 118 | app.get('/', (req, res) => { 119 | res.send(` 120 | 137 | 138 | 139 | 🖖 140 | 141 | `) 142 | }) 143 | 144 | app.get('/integrations', (req, res) => { 145 | let integrations = {} 146 | 147 | for (let provider in Integrations) { 148 | let integration = Integrations[provider] 149 | if (integration.deprecated) continue 150 | 151 | integrations[provider] = integration.toJSON() 152 | } 153 | 154 | res.send(integrations) 155 | }) 156 | 157 | app.get('*', (req, res) => { 158 | res.status(404).send('Not Found') 159 | }) 160 | 161 | // Rollbar 162 | // Must be added after all routes are registered 163 | if (process.env.ROLLBAR_SERVER_ACCESS_TOKEN) { 164 | let rollbar = new Rollbar({ 165 | accessToken: process.env.ROLLBAR_SERVER_ACCESS_TOKEN, 166 | captureUncaught: true, 167 | captureUnhandledRejections: true, 168 | }) 169 | 170 | app.use(rollbar.errorHandler()) 171 | rollbar.handleUncaughtExceptions() 172 | } 173 | 174 | app.listen(Port, () => { 175 | console.log(`Missive Webhooks listening on port ${Port}`) 176 | }) 177 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | accepts@~1.3.8: 6 | version "1.3.8" 7 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" 8 | integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== 9 | dependencies: 10 | mime-types "~2.1.34" 11 | negotiator "0.6.3" 12 | 13 | ajv@^6.12.3: 14 | version "6.12.6" 15 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" 16 | integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== 17 | dependencies: 18 | fast-deep-equal "^3.1.1" 19 | fast-json-stable-stringify "^2.0.0" 20 | json-schema-traverse "^0.4.1" 21 | uri-js "^4.2.2" 22 | 23 | array-flatten@1.1.1: 24 | version "1.1.1" 25 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 26 | integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= 27 | 28 | asn1@~0.2.3: 29 | version "0.2.6" 30 | resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" 31 | integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== 32 | dependencies: 33 | safer-buffer "~2.1.0" 34 | 35 | assert-plus@1.0.0, assert-plus@^1.0.0: 36 | version "1.0.0" 37 | resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" 38 | integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== 39 | 40 | async@~1.2.1: 41 | version "1.2.1" 42 | resolved "https://registry.yarnpkg.com/async/-/async-1.2.1.tgz#a4816a17cd5ff516dfa2c7698a453369b9790de0" 43 | integrity sha1-pIFqF81f9RbfosdpikUzabl5DeA= 44 | 45 | asynckit@^0.4.0: 46 | version "0.4.0" 47 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 48 | integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= 49 | 50 | atob@2.1.2: 51 | version "2.1.2" 52 | resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" 53 | integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== 54 | 55 | aws-sign2@~0.7.0: 56 | version "0.7.0" 57 | resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" 58 | integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= 59 | 60 | aws4@^1.8.0: 61 | version "1.11.0" 62 | resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" 63 | integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== 64 | 65 | bcrypt-pbkdf@^1.0.0: 66 | version "1.0.2" 67 | resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" 68 | integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== 69 | dependencies: 70 | tweetnacl "^0.14.3" 71 | 72 | body-parser@1.18.2: 73 | version "1.18.2" 74 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" 75 | integrity sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ= 76 | dependencies: 77 | bytes "3.0.0" 78 | content-type "~1.0.4" 79 | debug "2.6.9" 80 | depd "~1.1.1" 81 | http-errors "~1.6.2" 82 | iconv-lite "0.4.19" 83 | on-finished "~2.3.0" 84 | qs "6.5.1" 85 | raw-body "2.3.2" 86 | type-is "~1.6.15" 87 | 88 | body-parser@1.20.1: 89 | version "1.20.1" 90 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" 91 | integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== 92 | dependencies: 93 | bytes "3.1.2" 94 | content-type "~1.0.4" 95 | debug "2.6.9" 96 | depd "2.0.0" 97 | destroy "1.2.0" 98 | http-errors "2.0.0" 99 | iconv-lite "0.4.24" 100 | on-finished "2.4.1" 101 | qs "6.11.0" 102 | raw-body "2.5.1" 103 | type-is "~1.6.18" 104 | unpipe "1.0.0" 105 | 106 | bytes@3.0.0: 107 | version "3.0.0" 108 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" 109 | integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= 110 | 111 | bytes@3.1.2: 112 | version "3.1.2" 113 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" 114 | integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== 115 | 116 | call-bind@^1.0.0: 117 | version "1.0.2" 118 | resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" 119 | integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== 120 | dependencies: 121 | function-bind "^1.1.1" 122 | get-intrinsic "^1.0.2" 123 | 124 | caseless@~0.12.0: 125 | version "0.12.0" 126 | resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" 127 | integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= 128 | 129 | combined-stream@^1.0.6, combined-stream@~1.0.6: 130 | version "1.0.8" 131 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" 132 | integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== 133 | dependencies: 134 | delayed-stream "~1.0.0" 135 | 136 | console-polyfill@0.3.0: 137 | version "0.3.0" 138 | resolved "https://registry.yarnpkg.com/console-polyfill/-/console-polyfill-0.3.0.tgz#84900902a18c47a5eba932be75fa44d23e8af861" 139 | integrity sha512-w+JSDZS7XML43Xnwo2x5O5vxB0ID7T5BdqDtyqT6uiCAX2kZAgcWxNaGqT97tZfSHzfOcvrfsDAodKcJ3UvnXQ== 140 | 141 | content-disposition@0.5.4: 142 | version "0.5.4" 143 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" 144 | integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== 145 | dependencies: 146 | safe-buffer "5.2.1" 147 | 148 | content-type@~1.0.4: 149 | version "1.0.4" 150 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" 151 | integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== 152 | 153 | cookie-signature@1.0.6: 154 | version "1.0.6" 155 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" 156 | integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= 157 | 158 | cookie@0.5.0: 159 | version "0.5.0" 160 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" 161 | integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== 162 | 163 | core-util-is@1.0.2: 164 | version "1.0.2" 165 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 166 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= 167 | 168 | cors@2.8.5: 169 | version "2.8.5" 170 | resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" 171 | integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== 172 | dependencies: 173 | object-assign "^4" 174 | vary "^1" 175 | 176 | dashdash@^1.12.0: 177 | version "1.14.1" 178 | resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" 179 | integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g== 180 | dependencies: 181 | assert-plus "^1.0.0" 182 | 183 | debug@2.6.9: 184 | version "2.6.9" 185 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 186 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 187 | dependencies: 188 | ms "2.0.0" 189 | 190 | decache@^3.0.5: 191 | version "3.1.0" 192 | resolved "https://registry.yarnpkg.com/decache/-/decache-3.1.0.tgz#4f5036fbd6581fcc97237ac3954a244b9536c2da" 193 | integrity sha1-T1A2+9ZYH8yXI3rDlUokS5U2wto= 194 | dependencies: 195 | find "^0.2.4" 196 | 197 | delayed-stream@~1.0.0: 198 | version "1.0.0" 199 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 200 | integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= 201 | 202 | depd@1.1.1, depd@~1.1.1: 203 | version "1.1.1" 204 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" 205 | integrity sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k= 206 | 207 | depd@2.0.0: 208 | version "2.0.0" 209 | resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" 210 | integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== 211 | 212 | destroy@1.2.0: 213 | version "1.2.0" 214 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" 215 | integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== 216 | 217 | dotenv@4.0.0: 218 | version "4.0.0" 219 | resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-4.0.0.tgz#864ef1379aced55ce6f95debecdce179f7a0cd1d" 220 | integrity sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0= 221 | 222 | ecc-jsbn@~0.1.1: 223 | version "0.1.2" 224 | resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" 225 | integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw== 226 | dependencies: 227 | jsbn "~0.1.0" 228 | safer-buffer "^2.1.0" 229 | 230 | ee-first@1.1.1: 231 | version "1.1.1" 232 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 233 | integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= 234 | 235 | encodeurl@~1.0.2: 236 | version "1.0.2" 237 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" 238 | integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== 239 | 240 | error-stack-parser@1.3.3: 241 | version "1.3.3" 242 | resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-1.3.3.tgz#fada6e3a9cd2b0e080e6d6fc751418649734f35c" 243 | integrity sha1-+tpuOpzSsOCA5tb8dRQYZJc081w= 244 | dependencies: 245 | stackframe "^0.3.1" 246 | 247 | escape-html@~1.0.3: 248 | version "1.0.3" 249 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 250 | integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= 251 | 252 | etag@~1.8.1: 253 | version "1.8.1" 254 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" 255 | integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= 256 | 257 | express@4.18.2: 258 | version "4.18.2" 259 | resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" 260 | integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== 261 | dependencies: 262 | accepts "~1.3.8" 263 | array-flatten "1.1.1" 264 | body-parser "1.20.1" 265 | content-disposition "0.5.4" 266 | content-type "~1.0.4" 267 | cookie "0.5.0" 268 | cookie-signature "1.0.6" 269 | debug "2.6.9" 270 | depd "2.0.0" 271 | encodeurl "~1.0.2" 272 | escape-html "~1.0.3" 273 | etag "~1.8.1" 274 | finalhandler "1.2.0" 275 | fresh "0.5.2" 276 | http-errors "2.0.0" 277 | merge-descriptors "1.0.1" 278 | methods "~1.1.2" 279 | on-finished "2.4.1" 280 | parseurl "~1.3.3" 281 | path-to-regexp "0.1.7" 282 | proxy-addr "~2.0.7" 283 | qs "6.11.0" 284 | range-parser "~1.2.1" 285 | safe-buffer "5.2.1" 286 | send "0.18.0" 287 | serve-static "1.15.0" 288 | setprototypeof "1.2.0" 289 | statuses "2.0.1" 290 | type-is "~1.6.18" 291 | utils-merge "1.0.1" 292 | vary "~1.1.2" 293 | 294 | extend@~3.0.2: 295 | version "3.0.2" 296 | resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" 297 | integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== 298 | 299 | extsprintf@1.3.0: 300 | version "1.3.0" 301 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" 302 | integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= 303 | 304 | extsprintf@^1.2.0: 305 | version "1.4.0" 306 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" 307 | integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= 308 | 309 | fast-deep-equal@^3.1.1: 310 | version "3.1.3" 311 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" 312 | integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== 313 | 314 | fast-json-stable-stringify@^2.0.0: 315 | version "2.0.0" 316 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" 317 | integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= 318 | 319 | finalhandler@1.2.0: 320 | version "1.2.0" 321 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" 322 | integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== 323 | dependencies: 324 | debug "2.6.9" 325 | encodeurl "~1.0.2" 326 | escape-html "~1.0.3" 327 | on-finished "2.4.1" 328 | parseurl "~1.3.3" 329 | statuses "2.0.1" 330 | unpipe "~1.0.0" 331 | 332 | find@^0.2.4: 333 | version "0.2.9" 334 | resolved "https://registry.yarnpkg.com/find/-/find-0.2.9.tgz#4b73f1ff9e56ad91b76e716407fe5ffe6554bb8c" 335 | integrity sha1-S3Px/55WrZG3bnFkB/5f/mVUu4w= 336 | dependencies: 337 | traverse-chain "~0.1.0" 338 | 339 | forever-agent@~0.6.1: 340 | version "0.6.1" 341 | resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" 342 | integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= 343 | 344 | form-data@~2.3.2: 345 | version "2.3.3" 346 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" 347 | integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== 348 | dependencies: 349 | asynckit "^0.4.0" 350 | combined-stream "^1.0.6" 351 | mime-types "^2.1.12" 352 | 353 | forwarded@0.2.0: 354 | version "0.2.0" 355 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" 356 | integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== 357 | 358 | fresh@0.5.2: 359 | version "0.5.2" 360 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" 361 | integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= 362 | 363 | function-bind@^1.1.1: 364 | version "1.1.1" 365 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 366 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 367 | 368 | get-intrinsic@^1.0.2: 369 | version "1.1.3" 370 | resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385" 371 | integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A== 372 | dependencies: 373 | function-bind "^1.1.1" 374 | has "^1.0.3" 375 | has-symbols "^1.0.3" 376 | 377 | getpass@^0.1.1: 378 | version "0.1.7" 379 | resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" 380 | integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng== 381 | dependencies: 382 | assert-plus "^1.0.0" 383 | 384 | har-schema@^2.0.0: 385 | version "2.0.0" 386 | resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" 387 | integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= 388 | 389 | har-validator@~5.1.3: 390 | version "5.1.5" 391 | resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" 392 | integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== 393 | dependencies: 394 | ajv "^6.12.3" 395 | har-schema "^2.0.0" 396 | 397 | has-symbols@^1.0.3: 398 | version "1.0.3" 399 | resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" 400 | integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== 401 | 402 | has@^1.0.3: 403 | version "1.0.3" 404 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 405 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 406 | dependencies: 407 | function-bind "^1.1.1" 408 | 409 | http-errors@1.6.2, http-errors@~1.6.2: 410 | version "1.6.2" 411 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" 412 | integrity sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY= 413 | dependencies: 414 | depd "1.1.1" 415 | inherits "2.0.3" 416 | setprototypeof "1.0.3" 417 | statuses ">= 1.3.1 < 2" 418 | 419 | http-errors@2.0.0: 420 | version "2.0.0" 421 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" 422 | integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== 423 | dependencies: 424 | depd "2.0.0" 425 | inherits "2.0.4" 426 | setprototypeof "1.2.0" 427 | statuses "2.0.1" 428 | toidentifier "1.0.1" 429 | 430 | http-signature@~1.2.0: 431 | version "1.2.0" 432 | resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" 433 | integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= 434 | dependencies: 435 | assert-plus "^1.0.0" 436 | jsprim "^1.2.2" 437 | sshpk "^1.7.0" 438 | 439 | iconv-lite@0.4.19: 440 | version "0.4.19" 441 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" 442 | integrity sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ== 443 | 444 | iconv-lite@0.4.24: 445 | version "0.4.24" 446 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 447 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 448 | dependencies: 449 | safer-buffer ">= 2.1.2 < 3" 450 | 451 | inherits@2.0.3: 452 | version "2.0.3" 453 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 454 | integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= 455 | 456 | inherits@2.0.4: 457 | version "2.0.4" 458 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 459 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 460 | 461 | ipaddr.js@1.9.1: 462 | version "1.9.1" 463 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" 464 | integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== 465 | 466 | is-typedarray@~1.0.0: 467 | version "1.0.0" 468 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" 469 | integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= 470 | 471 | is_js@^0.9.0: 472 | version "0.9.0" 473 | resolved "https://registry.yarnpkg.com/is_js/-/is_js-0.9.0.tgz#0ab94540502ba7afa24c856aa985561669e9c52d" 474 | integrity sha1-CrlFQFArp6+iTIVqqYVWFmnpxS0= 475 | 476 | isstream@~0.1.2: 477 | version "0.1.2" 478 | resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" 479 | integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= 480 | 481 | jsbn@~0.1.0: 482 | version "0.1.1" 483 | resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" 484 | integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== 485 | 486 | json-schema-traverse@^0.4.1: 487 | version "0.4.1" 488 | resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" 489 | integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== 490 | 491 | json-schema@0.2.3: 492 | version "0.2.3" 493 | resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" 494 | integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= 495 | 496 | json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1: 497 | version "5.0.1" 498 | resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" 499 | integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= 500 | 501 | jsprim@^1.2.2: 502 | version "1.4.1" 503 | resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" 504 | integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= 505 | dependencies: 506 | assert-plus "1.0.0" 507 | extsprintf "1.3.0" 508 | json-schema "0.2.3" 509 | verror "1.10.0" 510 | 511 | lru-cache@~2.2.1: 512 | version "2.2.4" 513 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.2.4.tgz#6c658619becf14031d0d0b594b16042ce4dc063d" 514 | integrity sha1-bGWGGb7PFAMdDQtZSxYELOTcBj0= 515 | 516 | media-typer@0.3.0: 517 | version "0.3.0" 518 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 519 | integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= 520 | 521 | merge-descriptors@1.0.1: 522 | version "1.0.1" 523 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" 524 | integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= 525 | 526 | methods@~1.1.2: 527 | version "1.1.2" 528 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 529 | integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= 530 | 531 | mime-db@1.52.0: 532 | version "1.52.0" 533 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" 534 | integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== 535 | 536 | mime-db@~1.30.0: 537 | version "1.30.0" 538 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" 539 | integrity sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE= 540 | 541 | mime-types@^2.1.12, mime-types@~2.1.15: 542 | version "2.1.17" 543 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" 544 | integrity sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo= 545 | dependencies: 546 | mime-db "~1.30.0" 547 | 548 | mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: 549 | version "2.1.35" 550 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" 551 | integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== 552 | dependencies: 553 | mime-db "1.52.0" 554 | 555 | mime@1.6.0: 556 | version "1.6.0" 557 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" 558 | integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== 559 | 560 | ms@2.0.0: 561 | version "2.0.0" 562 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 563 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 564 | 565 | ms@2.1.3: 566 | version "2.1.3" 567 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" 568 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== 569 | 570 | negotiator@0.6.3: 571 | version "0.6.3" 572 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" 573 | integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== 574 | 575 | oauth-sign@~0.9.0: 576 | version "0.9.0" 577 | resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" 578 | integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== 579 | 580 | object-assign@^4: 581 | version "4.1.1" 582 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 583 | integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= 584 | 585 | object-inspect@^1.9.0: 586 | version "1.12.2" 587 | resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" 588 | integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== 589 | 590 | on-finished@2.4.1: 591 | version "2.4.1" 592 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" 593 | integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== 594 | dependencies: 595 | ee-first "1.1.1" 596 | 597 | on-finished@~2.3.0: 598 | version "2.3.0" 599 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 600 | integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= 601 | dependencies: 602 | ee-first "1.1.1" 603 | 604 | parseurl@~1.3.3: 605 | version "1.3.3" 606 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" 607 | integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== 608 | 609 | path-to-regexp@0.1.7: 610 | version "0.1.7" 611 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" 612 | integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= 613 | 614 | performance-now@^2.1.0: 615 | version "2.1.0" 616 | resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" 617 | integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= 618 | 619 | proxy-addr@~2.0.7: 620 | version "2.0.7" 621 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" 622 | integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== 623 | dependencies: 624 | forwarded "0.2.0" 625 | ipaddr.js "1.9.1" 626 | 627 | psl@^1.1.28: 628 | version "1.9.0" 629 | resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" 630 | integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== 631 | 632 | punycode@^2.1.0, punycode@^2.1.1: 633 | version "2.1.1" 634 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" 635 | integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== 636 | 637 | qs@6.11.0: 638 | version "6.11.0" 639 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" 640 | integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== 641 | dependencies: 642 | side-channel "^1.0.4" 643 | 644 | qs@6.5.1: 645 | version "6.5.1" 646 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" 647 | integrity sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A== 648 | 649 | qs@~6.5.2: 650 | version "6.5.3" 651 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" 652 | integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== 653 | 654 | range-parser@~1.2.1: 655 | version "1.2.1" 656 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" 657 | integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== 658 | 659 | raw-body@2.3.2: 660 | version "2.3.2" 661 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" 662 | integrity sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k= 663 | dependencies: 664 | bytes "3.0.0" 665 | http-errors "1.6.2" 666 | iconv-lite "0.4.19" 667 | unpipe "1.0.0" 668 | 669 | raw-body@2.5.1: 670 | version "2.5.1" 671 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" 672 | integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== 673 | dependencies: 674 | bytes "3.1.2" 675 | http-errors "2.0.0" 676 | iconv-lite "0.4.24" 677 | unpipe "1.0.0" 678 | 679 | request-ip@~2.0.1: 680 | version "2.0.2" 681 | resolved "https://registry.yarnpkg.com/request-ip/-/request-ip-2.0.2.tgz#deeae6d4af21768497db8cd05fa37143f8f1257e" 682 | integrity sha1-3urm1K8hdoSX24zQX6NxQ/jxJX4= 683 | dependencies: 684 | is_js "^0.9.0" 685 | 686 | request@2.88.2: 687 | version "2.88.2" 688 | resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" 689 | integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== 690 | dependencies: 691 | aws-sign2 "~0.7.0" 692 | aws4 "^1.8.0" 693 | caseless "~0.12.0" 694 | combined-stream "~1.0.6" 695 | extend "~3.0.2" 696 | forever-agent "~0.6.1" 697 | form-data "~2.3.2" 698 | har-validator "~5.1.3" 699 | http-signature "~1.2.0" 700 | is-typedarray "~1.0.0" 701 | isstream "~0.1.2" 702 | json-stringify-safe "~5.0.1" 703 | mime-types "~2.1.19" 704 | oauth-sign "~0.9.0" 705 | performance-now "^2.1.0" 706 | qs "~6.5.2" 707 | safe-buffer "^5.1.2" 708 | tough-cookie "~2.5.0" 709 | tunnel-agent "^0.6.0" 710 | uuid "^3.3.2" 711 | 712 | rollbar@2.4.2: 713 | version "2.4.2" 714 | resolved "https://registry.yarnpkg.com/rollbar/-/rollbar-2.4.2.tgz#44286aec383a49d7849da92b5b9e31999847cfc9" 715 | integrity sha512-7k3eTkdOBZ/ieKhdq2GUrYZpSyD8T+lrpzx9kBJpAhtj/aGCQkVyT1ZVPUxusGXrovv90Ap/1XwcpzAH1BUWjA== 716 | dependencies: 717 | async "~1.2.1" 718 | console-polyfill "0.3.0" 719 | debug "2.6.9" 720 | error-stack-parser "1.3.3" 721 | json-stringify-safe "~5.0.0" 722 | lru-cache "~2.2.1" 723 | request-ip "~2.0.1" 724 | uuid "3.0.x" 725 | optionalDependencies: 726 | decache "^3.0.5" 727 | 728 | safe-buffer@5.2.1, safe-buffer@^5.1.2: 729 | version "5.2.1" 730 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 731 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 732 | 733 | safe-buffer@^5.0.1: 734 | version "5.1.1" 735 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" 736 | integrity sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg== 737 | 738 | "safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: 739 | version "2.1.2" 740 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 741 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 742 | 743 | send@0.18.0: 744 | version "0.18.0" 745 | resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" 746 | integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== 747 | dependencies: 748 | debug "2.6.9" 749 | depd "2.0.0" 750 | destroy "1.2.0" 751 | encodeurl "~1.0.2" 752 | escape-html "~1.0.3" 753 | etag "~1.8.1" 754 | fresh "0.5.2" 755 | http-errors "2.0.0" 756 | mime "1.6.0" 757 | ms "2.1.3" 758 | on-finished "2.4.1" 759 | range-parser "~1.2.1" 760 | statuses "2.0.1" 761 | 762 | serve-static@1.15.0: 763 | version "1.15.0" 764 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" 765 | integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== 766 | dependencies: 767 | encodeurl "~1.0.2" 768 | escape-html "~1.0.3" 769 | parseurl "~1.3.3" 770 | send "0.18.0" 771 | 772 | setprototypeof@1.0.3: 773 | version "1.0.3" 774 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" 775 | integrity sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ= 776 | 777 | setprototypeof@1.2.0: 778 | version "1.2.0" 779 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" 780 | integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== 781 | 782 | side-channel@^1.0.4: 783 | version "1.0.4" 784 | resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" 785 | integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== 786 | dependencies: 787 | call-bind "^1.0.0" 788 | get-intrinsic "^1.0.2" 789 | object-inspect "^1.9.0" 790 | 791 | sshpk@^1.7.0: 792 | version "1.17.0" 793 | resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" 794 | integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== 795 | dependencies: 796 | asn1 "~0.2.3" 797 | assert-plus "^1.0.0" 798 | bcrypt-pbkdf "^1.0.0" 799 | dashdash "^1.12.0" 800 | ecc-jsbn "~0.1.1" 801 | getpass "^0.1.1" 802 | jsbn "~0.1.0" 803 | safer-buffer "^2.0.2" 804 | tweetnacl "~0.14.0" 805 | 806 | stackframe@^0.3.1: 807 | version "0.3.1" 808 | resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-0.3.1.tgz#33aa84f1177a5548c8935533cbfeb3420975f5a4" 809 | integrity sha1-M6qE8Rd6VUjIk1Uzy/6zQgl19aQ= 810 | 811 | statuses@2.0.1: 812 | version "2.0.1" 813 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" 814 | integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== 815 | 816 | "statuses@>= 1.3.1 < 2": 817 | version "1.4.0" 818 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" 819 | integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== 820 | 821 | toidentifier@1.0.1: 822 | version "1.0.1" 823 | resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" 824 | integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== 825 | 826 | tough-cookie@~2.5.0: 827 | version "2.5.0" 828 | resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" 829 | integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== 830 | dependencies: 831 | psl "^1.1.28" 832 | punycode "^2.1.1" 833 | 834 | traverse-chain@~0.1.0: 835 | version "0.1.0" 836 | resolved "https://registry.yarnpkg.com/traverse-chain/-/traverse-chain-0.1.0.tgz#61dbc2d53b69ff6091a12a168fd7d433107e40f1" 837 | integrity sha1-YdvC1Ttp/2CRoSoWj9fUMxB+QPE= 838 | 839 | tunnel-agent@^0.6.0: 840 | version "0.6.0" 841 | resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" 842 | integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= 843 | dependencies: 844 | safe-buffer "^5.0.1" 845 | 846 | tweetnacl@^0.14.3, tweetnacl@~0.14.0: 847 | version "0.14.5" 848 | resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" 849 | integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== 850 | 851 | type-is@~1.6.15: 852 | version "1.6.15" 853 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" 854 | integrity sha1-yrEPtJCeRByChC6v4a1kbIGARBA= 855 | dependencies: 856 | media-typer "0.3.0" 857 | mime-types "~2.1.15" 858 | 859 | type-is@~1.6.18: 860 | version "1.6.18" 861 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" 862 | integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== 863 | dependencies: 864 | media-typer "0.3.0" 865 | mime-types "~2.1.24" 866 | 867 | unpipe@1.0.0, unpipe@~1.0.0: 868 | version "1.0.0" 869 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 870 | integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= 871 | 872 | uri-js@^4.2.2: 873 | version "4.4.1" 874 | resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" 875 | integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== 876 | dependencies: 877 | punycode "^2.1.0" 878 | 879 | utils-merge@1.0.1: 880 | version "1.0.1" 881 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" 882 | integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= 883 | 884 | uuid@3.0.x: 885 | version "3.0.1" 886 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" 887 | integrity sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE= 888 | 889 | uuid@^3.3.2: 890 | version "3.4.0" 891 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" 892 | integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== 893 | 894 | vary@^1, vary@~1.1.2: 895 | version "1.1.2" 896 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" 897 | integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= 898 | 899 | verror@1.10.0: 900 | version "1.10.0" 901 | resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" 902 | integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= 903 | dependencies: 904 | assert-plus "^1.0.0" 905 | core-util-is "1.0.2" 906 | extsprintf "^1.2.0" 907 | --------------------------------------------------------------------------------