refactor: port to typescript
This commit is contained in:
Родитель
dee13eb576
Коммит
aeea088cd1
|
@ -1 +1,3 @@
|
|||
node_modules
|
||||
dist
|
||||
*error.log
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"trailingComma": "all",
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"printWidth": 100,
|
||||
"parser": "typescript"
|
||||
}
|
14
package.json
14
package.json
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "chromium-bot",
|
||||
"version": "1.0.0",
|
||||
"main": "src/index.js",
|
||||
"main": "dist/index.js",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"body-parser": "^1.19.0",
|
||||
|
@ -10,6 +10,16 @@
|
|||
"node-fetch": "^2.6.1"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node src/index.js"
|
||||
"build": "tsc",
|
||||
"start": "node dist/index.js",
|
||||
"prettier:check": "prettier --check \"src/**/*.ts\"",
|
||||
"prettier:write": "prettier --write \"src/**/*.ts\""
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.17.11",
|
||||
"@types/node": "^14.14.37",
|
||||
"@types/node-fetch": "^2.5.9",
|
||||
"prettier": "^2.2.1",
|
||||
"typescript": "^4.2.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
const fetch = require('node-fetch').default;
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
module.exports = async function handleChromiumReviewUnfurl(url, message_ts, channel) {
|
||||
const match = /^https:\/\/chromium-review\.googlesource\.com\/c\/([a-z0-9]+)\/([a-z0-9]+)\/\+\/([0-9]+)/g.exec(url);
|
||||
export async function handleChromiumReviewUnfurl(url: string, message_ts: string, channel: string) {
|
||||
const match = /^https:\/\/chromium-review\.googlesource\.com\/c\/([a-z0-9]+)\/([a-z0-9]+)\/\+\/([0-9]+)/g.exec(
|
||||
url,
|
||||
);
|
||||
if (match) {
|
||||
const repo = `${match[1]}%2F${match[2]}`;
|
||||
const niceRepo = `${match[1]}/${match[2]}`;
|
||||
|
@ -13,13 +15,18 @@ module.exports = async function handleChromiumReviewUnfurl(url, message_ts, chan
|
|||
const details = JSON.parse(detailsText.substr(4));
|
||||
const { project, subject, owner, labels, current_revision, revisions } = details;
|
||||
const commit = revisions[current_revision].commit;
|
||||
const { message, author: { date } } = commit;
|
||||
const messageWithoutSubject = message.startsWith(subject) ? message.substr(subject.length + 1).trim() : message;
|
||||
const {
|
||||
message,
|
||||
author: { date },
|
||||
} = commit;
|
||||
const messageWithoutSubject = message.startsWith(subject)
|
||||
? message.substr(subject.length + 1).trim()
|
||||
: message;
|
||||
|
||||
const unfurl = await fetch('https://slack.com/api/chat.unfurl', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${process.env.SLACK_TOKEN}`,
|
||||
Authorization: `Bearer ${process.env.SLACK_TOKEN}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
|
@ -30,22 +37,27 @@ module.exports = async function handleChromiumReviewUnfurl(url, message_ts, chan
|
|||
[url]: {
|
||||
color: '#4D394B',
|
||||
author_name: owner.name,
|
||||
author_icon: owner.avatars && owner.avatars.length ? owner.avatars[owner.avatars.length - 1].url : ':void',
|
||||
author_link: `https://chromium-review.googlesource.com/q/author:${encodeURIComponent(owner.email)}`,
|
||||
author_icon:
|
||||
owner.avatars && owner.avatars.length
|
||||
? owner.avatars[owner.avatars.length - 1].url
|
||||
: ':void',
|
||||
author_link: `https://chromium-review.googlesource.com/q/author:${encodeURIComponent(
|
||||
owner.email,
|
||||
)}`,
|
||||
fallback: `[${niceRepo}] #${cl} ${subject}`,
|
||||
title: `#${cl} ${subject}`,
|
||||
title_link: url,
|
||||
footer_icon: 'https://chromium-review.googlesource.com/favicon.ico',
|
||||
text: messageWithoutSubject,
|
||||
footer: `<https://source.chromium.org/chromium/${niceRepo}|${niceRepo}>`,
|
||||
ts: (new Date(date)).getTime(),
|
||||
ts: new Date(date).getTime(),
|
||||
// TODO: Labels? CQ status?
|
||||
// fields: [{
|
||||
|
||||
|
||||
// }]
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (unfurl.status === 200) {
|
||||
const resp = await unfurl.json();
|
|
@ -1,12 +1,12 @@
|
|||
const fetch = require('node-fetch').default;
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
const { Policy, ConstantBackoff } = require('cockatiel');
|
||||
import { Policy, ConstantBackoff } from 'cockatiel';
|
||||
|
||||
function parseBugIdentifier(url) {
|
||||
function parseBugIdentifier(url: string) {
|
||||
const parsed = new URL(url);
|
||||
if (parsed.host === 'bugs.chromium.org') {
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=1195924
|
||||
const number = parseInt(parsed.searchParams.get('id'), 10);
|
||||
const number = parseInt(parsed.searchParams.get('id') || '', 10);
|
||||
if (isNaN(number)) return null;
|
||||
|
||||
const match = /^https:\/\/bugs\.chromium\.org\/p\/([a-z0-9]+)\/issues\/detail/g.exec(url);
|
||||
|
@ -15,7 +15,7 @@ function parseBugIdentifier(url) {
|
|||
return {
|
||||
project: match[1],
|
||||
number,
|
||||
}
|
||||
};
|
||||
} else if (parsed.host === 'crbug.com') {
|
||||
// https://crbug.com/12345
|
||||
const number = parseInt(parsed.pathname.slice(1), 10);
|
||||
|
@ -30,10 +30,7 @@ function parseBugIdentifier(url) {
|
|||
return null;
|
||||
}
|
||||
|
||||
const retry = Policy.handleAll()
|
||||
.retry()
|
||||
.attempts(3)
|
||||
.backoff(new ConstantBackoff(250));
|
||||
const retry = Policy.handleAll().retry().attempts(3).backoff(new ConstantBackoff(250));
|
||||
|
||||
async function getMonorailToken() {
|
||||
return retry.execute(async () => {
|
||||
|
@ -52,13 +49,36 @@ async function getMonorailToken() {
|
|||
|
||||
async function getMonorailHeaders() {
|
||||
return {
|
||||
"accept": "application/json",
|
||||
"content-type": "application/json",
|
||||
"x-xsrf-token": await getMonorailToken()
|
||||
}
|
||||
accept: 'application/json',
|
||||
'content-type': 'application/json',
|
||||
'x-xsrf-token': await getMonorailToken(),
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = async function handleChromiumBugUnfurl(url, message_ts, channel) {
|
||||
type MonorailIssue = {
|
||||
statusRef: {
|
||||
meansOpen: boolean;
|
||||
};
|
||||
reporterRef: {
|
||||
displayName: string;
|
||||
userId: number;
|
||||
};
|
||||
projectName: string;
|
||||
localId: number;
|
||||
summary: string;
|
||||
openedTimestamp: number;
|
||||
componentRefs?: {
|
||||
path: string;
|
||||
}[];
|
||||
labelRefs?: {
|
||||
label: string;
|
||||
}[];
|
||||
};
|
||||
type MonorailComments = {
|
||||
content: string;
|
||||
}[];
|
||||
|
||||
export async function handleChromiumBugUnfurl(url: string, message_ts: string, channel: string) {
|
||||
const bugIdentifier = parseBugIdentifier(url);
|
||||
if (!bugIdentifier) return false;
|
||||
|
||||
|
@ -77,18 +97,20 @@ module.exports = async function handleChromiumBugUnfurl(url, message_ts, channel
|
|||
const commentResponse = fetch('https://bugs.chromium.org/prpc/monorail.Issues/ListComments', {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: monorailQuery
|
||||
})
|
||||
body: monorailQuery,
|
||||
});
|
||||
if ((await response).status !== 200) return false;
|
||||
if ((await commentResponse).status !== 200) return false;
|
||||
|
||||
const { issue } = JSON.parse((await (await response).text()).slice(4));
|
||||
const { comments } = JSON.parse((await (await commentResponse).text()).slice(4));
|
||||
|
||||
const { issue }: { issue: MonorailIssue } = JSON.parse((await (await response).text()).slice(4));
|
||||
const { comments }: { comments: MonorailComments } = JSON.parse(
|
||||
(await (await commentResponse).text()).slice(4),
|
||||
);
|
||||
|
||||
const unfurl = await fetch('https://slack.com/api/chat.unfurl', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${process.env.SLACK_TOKEN}`,
|
||||
Authorization: `Bearer ${process.env.SLACK_TOKEN}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
|
@ -107,22 +129,46 @@ module.exports = async function handleChromiumBugUnfurl(url, message_ts, channel
|
|||
text: comments[0].content,
|
||||
footer: `<https://bugs.chromium.org/p/${issue.projectName}|crbug/${issue.projectName}>`,
|
||||
ts: issue.openedTimestamp * 1000,
|
||||
fields: [issue.componentRefs && issue.componentRefs.length ? {
|
||||
title: 'Components',
|
||||
value: issue.componentRefs.map(ref => `• <https://bugs.chromium.org/p/${issue.projectName}/issues/list?q=component%3A${encodeURIComponent(ref.path)}|\`${ref.path.replace(/>/g, '→')}\`>`).join('\n'),
|
||||
short: true,
|
||||
} : null, issue.labelRefs && issue.labelRefs.length ? {
|
||||
title: 'Labels',
|
||||
value: issue.labelRefs.map(ref => `• <https://bugs.chromium.org/p/${issue.projectName}/issues/list?q=label%3A${encodeURIComponent(ref.label)}|\`${ref.label}\`>`).join('\n'),
|
||||
short: true,
|
||||
} : null, {
|
||||
title: 'Comments',
|
||||
value: `${comments.length}`,
|
||||
short: true,
|
||||
}].filter(Boolean)
|
||||
}
|
||||
}
|
||||
})
|
||||
fields: [
|
||||
issue.componentRefs && issue.componentRefs.length
|
||||
? {
|
||||
title: 'Components',
|
||||
value: issue.componentRefs
|
||||
.map(
|
||||
(ref) =>
|
||||
`• <https://bugs.chromium.org/p/${
|
||||
issue.projectName
|
||||
}/issues/list?q=component%3A${encodeURIComponent(
|
||||
ref.path,
|
||||
)}|\`${ref.path.replace(/>/g, '→')}\`>`,
|
||||
)
|
||||
.join('\n'),
|
||||
short: true,
|
||||
}
|
||||
: null,
|
||||
issue.labelRefs && issue.labelRefs.length
|
||||
? {
|
||||
title: 'Labels',
|
||||
value: issue.labelRefs
|
||||
.map(
|
||||
(ref) =>
|
||||
`• <https://bugs.chromium.org/p/${
|
||||
issue.projectName
|
||||
}/issues/list?q=label%3A${encodeURIComponent(ref.label)}|\`${ref.label}\`>`,
|
||||
)
|
||||
.join('\n'),
|
||||
short: true,
|
||||
}
|
||||
: null,
|
||||
{
|
||||
title: 'Comments',
|
||||
value: `${comments.length}`,
|
||||
short: true,
|
||||
},
|
||||
].filter(Boolean),
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (unfurl.status === 200) {
|
||||
const resp = await unfurl.json();
|
||||
|
@ -130,6 +176,6 @@ module.exports = async function handleChromiumBugUnfurl(url, message_ts, channel
|
|||
console.error('Failed to unfurl', resp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,34 +1,73 @@
|
|||
const fetch = require('node-fetch').default;
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
async function getGrimoireMetadata() {
|
||||
type GrimoireMeta = {
|
||||
token: string;
|
||||
endpoint: string;
|
||||
};
|
||||
|
||||
async function getGrimoireMetadata(): Promise<GrimoireMeta> {
|
||||
const response = await fetch('https://source.chromium.org/');
|
||||
const text = await response.text()
|
||||
const data = text.split('var GRIMOIRE_CONFIG = \'')[1].split(`'`)[0]
|
||||
const grimoireConfig = JSON.parse(data.replace(/\\x([\d\w]{2})/gi, (match, grp) => {
|
||||
return String.fromCharCode(parseInt(grp, 16));
|
||||
}).replace(/\\n/gi, ''));
|
||||
const token = grimoireConfig[0];
|
||||
const endpoint = grimoireConfig[6][1];
|
||||
const text = await response.text();
|
||||
const data = text.split("var GRIMOIRE_CONFIG = '")[1].split(`'`)[0];
|
||||
const grimoireConfig = JSON.parse(
|
||||
data
|
||||
.replace(/\\x([\d\w]{2})/gi, (match, grp) => {
|
||||
return String.fromCharCode(parseInt(grp, 16));
|
||||
})
|
||||
.replace(/\\n/gi, ''),
|
||||
);
|
||||
const token: string = grimoireConfig[0];
|
||||
const endpoint: string = grimoireConfig[6][1];
|
||||
return {
|
||||
token,
|
||||
endpoint,
|
||||
};
|
||||
}
|
||||
|
||||
async function getFileContents(grimoire, parent, project, projectKey, branch, fileName) {
|
||||
const response = await fetch(`${grimoire.endpoint}/$rpc/devtools.grimoire.FileService/GetContentsStreaming?%24httpHeaders=X-Goog-Api-Key%3A${grimoire.token}%0D%0AX-Goog-Api-Client%3Agrpc-web%2F1.0.0%20grimoire%2F1.0.0%2Buyti2atju1zl.be6of0mawakc.code.codebrowser-frontend-oss-20210330.07_p0%0D%0AX-Server-Timeout%3A60%0D%0AContent-Type%3Aapplication%2Fjson%2Bprotobuf%0D%0AX-User-Agent%3Agrpc-web-javascript%2F0.1%0D%0A`, {
|
||||
"headers": {
|
||||
"origin": "https://source.chromium.org",
|
||||
"content-type": "application/x-www-form-urlencoded;charset=UTF-8",
|
||||
type DeepArrayOfUnknowns = Array<unknown | string | DeepArrayOfUnknowns>;
|
||||
|
||||
async function getFileContents(
|
||||
grimoire: GrimoireMeta,
|
||||
parent: string,
|
||||
project: string,
|
||||
projectKey: string,
|
||||
branch: string,
|
||||
fileName: string,
|
||||
) {
|
||||
const response = await fetch(
|
||||
`${grimoire.endpoint}/$rpc/devtools.grimoire.FileService/GetContentsStreaming?%24httpHeaders=X-Goog-Api-Key%3A${grimoire.token}%0D%0AX-Goog-Api-Client%3Agrpc-web%2F1.0.0%20grimoire%2F1.0.0%2Buyti2atju1zl.be6of0mawakc.code.codebrowser-frontend-oss-20210330.07_p0%0D%0AX-Server-Timeout%3A60%0D%0AContent-Type%3Aapplication%2Fjson%2Bprotobuf%0D%0AX-User-Agent%3Agrpc-web-javascript%2F0.1%0D%0A`,
|
||||
{
|
||||
headers: {
|
||||
origin: 'https://source.chromium.org',
|
||||
'content-type': 'application/x-www-form-urlencoded;charset=UTF-8',
|
||||
},
|
||||
body: JSON.stringify([
|
||||
[
|
||||
[[null, `${project}/${projectKey}`, null, null, parent], null, branch],
|
||||
fileName,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
[],
|
||||
],
|
||||
true,
|
||||
null,
|
||||
true,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
true,
|
||||
]),
|
||||
method: 'POST',
|
||||
},
|
||||
"body": JSON.stringify([[[[null,`${project}/${projectKey}`,null,null,parent],null,branch],fileName,null,null,null,null,[]],true,null,true,null,null,null,null,true]),
|
||||
"method": "POST"
|
||||
});
|
||||
const data = JSON.parse(await response.text());
|
||||
);
|
||||
const data: DeepArrayOfUnknowns = JSON.parse(await response.text());
|
||||
|
||||
const best = { str: '', n: 0 };
|
||||
|
||||
function search(arr) {
|
||||
function search(arr: DeepArrayOfUnknowns) {
|
||||
for (const item of arr) {
|
||||
if (typeof item === 'string') {
|
||||
const n = item.split('\n').length;
|
||||
|
@ -37,11 +76,9 @@ async function getFileContents(grimoire, parent, project, projectKey, branch, fi
|
|||
best.n = n;
|
||||
}
|
||||
} else if (Array.isArray(item)) {
|
||||
const result = search(item);
|
||||
if (result) return result;
|
||||
search(item);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
search(data);
|
||||
|
@ -50,14 +87,14 @@ async function getFileContents(grimoire, parent, project, projectKey, branch, fi
|
|||
|
||||
const MAX_SLACK_MSG_LENGTH = 7000;
|
||||
|
||||
function maybeTruncate(longContents) {
|
||||
if (longContents.length <= MAX_SLACK_MSG_LENGTH) return longContents
|
||||
function maybeTruncate(longContents: string) {
|
||||
if (longContents.length <= MAX_SLACK_MSG_LENGTH) return longContents;
|
||||
return longContents.slice(0, MAX_SLACK_MSG_LENGTH) + '...';
|
||||
}
|
||||
|
||||
const INDENT_BREAKPOINT = 2;
|
||||
|
||||
function indentLength(line) {
|
||||
function indentLength(line: string): number {
|
||||
let i = 0;
|
||||
while (line[i] === ' ') {
|
||||
i++;
|
||||
|
@ -65,7 +102,7 @@ function indentLength(line) {
|
|||
return i;
|
||||
}
|
||||
|
||||
function removeOverIndent(contents) {
|
||||
function removeOverIndent(contents: string): string {
|
||||
const lines = contents.split('\n');
|
||||
if (!lines.length) return contents;
|
||||
|
||||
|
@ -76,18 +113,20 @@ function removeOverIndent(contents) {
|
|||
|
||||
if (minIndent - INDENT_BREAKPOINT <= 0) return contents;
|
||||
|
||||
return lines.map(l => l.slice(minIndent)).join('\n');
|
||||
return lines.map((l) => l.slice(minIndent)).join('\n');
|
||||
}
|
||||
|
||||
module.exports = async function handleChromiumSourceUnfurl(url, message_ts, channel) {
|
||||
export async function handleChromiumSourceUnfurl(url: string, message_ts: string, channel: string) {
|
||||
const parsed = new URL(url);
|
||||
if (parsed.hostname !== 'source.chromium.org') return false;
|
||||
|
||||
const match = /^https:\/\/source\.chromium\.org\/([a-z0-9]+)\/([a-z0-9]+)\/([a-z0-9]+)\/\+\/([a-z0-9]+):([^;]+)(?:;l=([0-9]+(?:-[0-9]+)?))?/.exec(url);
|
||||
const match = /^https:\/\/source\.chromium\.org\/([a-z0-9]+)\/([a-z0-9]+)\/([a-z0-9]+)\/\+\/([a-z0-9]+):([^;]+)(?:;l=([0-9]+(?:-[0-9]+)?))?/.exec(
|
||||
url,
|
||||
);
|
||||
if (!match) return false;
|
||||
|
||||
const [,parent, project, projectKey, branch, fileName, lineRange] = match;
|
||||
|
||||
const [, parent, project, projectKey, branch, fileName, lineRange] = match;
|
||||
|
||||
const grimoire = await getGrimoireMetadata();
|
||||
let contents = await getFileContents(grimoire, parent, project, projectKey, branch, fileName);
|
||||
if (lineRange) {
|
||||
|
@ -95,7 +134,10 @@ module.exports = async function handleChromiumSourceUnfurl(url, message_ts, chan
|
|||
if (!isNaN(start)) {
|
||||
let end = parseInt(lineRange.split('-')[1], 10);
|
||||
if (isNaN(end)) end = start;
|
||||
contents = contents.split('\n').slice(start - 1, end).join('\n');
|
||||
contents = contents
|
||||
.split('\n')
|
||||
.slice(start - 1, end)
|
||||
.join('\n');
|
||||
contents = removeOverIndent(contents);
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +145,7 @@ module.exports = async function handleChromiumSourceUnfurl(url, message_ts, chan
|
|||
const unfurl = await fetch('https://slack.com/api/chat.unfurl', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${process.env.SLACK_TOKEN}`,
|
||||
Authorization: `Bearer ${process.env.SLACK_TOKEN}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
|
@ -119,9 +161,9 @@ module.exports = async function handleChromiumSourceUnfurl(url, message_ts, chan
|
|||
text: `\`\`\`\n${maybeTruncate(contents)}\n\`\`\``,
|
||||
footer: `<https://source.chromium.org/${parent}/${project}/${projectKey}/+/${branch}|${project}/${projectKey}>`,
|
||||
mrkdwn_in: ['text'],
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (unfurl.status === 200) {
|
||||
const resp = await unfurl.json();
|
||||
|
@ -129,6 +171,6 @@ module.exports = async function handleChromiumSourceUnfurl(url, message_ts, chan
|
|||
console.error('Failed to unfurl', resp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
const express = require('express');
|
||||
import * as express from 'express';
|
||||
|
||||
const handleChromiumReviewUnfurl = require('./chromium-review');
|
||||
const handleChromiumBugUnfurl = require('./crbug');
|
||||
const handleChromiumSourceUnfurl = require('./crsource');
|
||||
import { handleChromiumReviewUnfurl } from './chromium-review';
|
||||
import { handleChromiumBugUnfurl } from './crbug';
|
||||
import { handleChromiumSourceUnfurl } from './crsource';
|
||||
|
||||
const app = express();
|
||||
app.use(require('body-parser').json());
|
||||
|
@ -12,8 +12,8 @@ app.post('/slack-event', (req, res) => {
|
|||
if (type === 'url_verification') {
|
||||
return res.send(req.body.challenge);
|
||||
} else if (type === 'event_callback') {
|
||||
const { team_id, event, token } = req.body;
|
||||
handleChromiumLink(team_id, event, token).catch(console.error);
|
||||
const { team_id, event } = req.body;
|
||||
handleChromiumLink(team_id, event).catch(console.error);
|
||||
res.send('');
|
||||
} else {
|
||||
res.send('');
|
||||
|
@ -24,7 +24,14 @@ app.listen(process.env.PORT || 8080, () => {
|
|||
console.log('App listening');
|
||||
});
|
||||
|
||||
async function handleChromiumLink(teamId, event, token) {
|
||||
type SlackEvent = {
|
||||
message_ts: string;
|
||||
type: string;
|
||||
channel: string;
|
||||
links: { url: string }[];
|
||||
};
|
||||
|
||||
async function handleChromiumLink(teamId: string, event: SlackEvent) {
|
||||
if (event.type !== 'link_shared') return;
|
||||
|
||||
const { message_ts, channel, links } = event;
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es2020",
|
||||
"lib": [
|
||||
"es2017",
|
||||
"dom"
|
||||
],
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"outDir": "dist",
|
||||
"types": [
|
||||
"node"
|
||||
],
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"moduleResolution": "node",
|
||||
"incremental": true
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
}
|
118
yarn.lock
118
yarn.lock
|
@ -2,6 +2,76 @@
|
|||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@types/body-parser@*":
|
||||
version "1.19.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f"
|
||||
integrity sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==
|
||||
dependencies:
|
||||
"@types/connect" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/connect@*":
|
||||
version "3.4.34"
|
||||
resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.34.tgz#170a40223a6d666006d93ca128af2beb1d9b1901"
|
||||
integrity sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/express-serve-static-core@^4.17.18":
|
||||
version "4.17.19"
|
||||
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.19.tgz#00acfc1632e729acac4f1530e9e16f6dd1508a1d"
|
||||
integrity sha512-DJOSHzX7pCiSElWaGR8kCprwibCB/3yW6vcT8VG3P0SJjnv19gnWG/AZMfM60Xj/YJIp/YCaDHyvzsFVeniARA==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
"@types/qs" "*"
|
||||
"@types/range-parser" "*"
|
||||
|
||||
"@types/express@^4.17.11":
|
||||
version "4.17.11"
|
||||
resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.11.tgz#debe3caa6f8e5fcda96b47bd54e2f40c4ee59545"
|
||||
integrity sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg==
|
||||
dependencies:
|
||||
"@types/body-parser" "*"
|
||||
"@types/express-serve-static-core" "^4.17.18"
|
||||
"@types/qs" "*"
|
||||
"@types/serve-static" "*"
|
||||
|
||||
"@types/mime@^1":
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a"
|
||||
integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==
|
||||
|
||||
"@types/node-fetch@^2.5.9":
|
||||
version "2.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.9.tgz#c04a12115aa436f189e39579272b305e477621b4"
|
||||
integrity sha512-6cUyqLK+JBsATAqNQqk10jURoBFrzfRCDh4kaYxg8ivKhRPIpyBgAvuY7zM/3E4AwsYJSh5HCHBCJRM4DsCTaQ==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
form-data "^3.0.0"
|
||||
|
||||
"@types/node@*", "@types/node@^14.14.37":
|
||||
version "14.14.37"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.37.tgz#a3dd8da4eb84a996c36e331df98d82abd76b516e"
|
||||
integrity sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==
|
||||
|
||||
"@types/qs@*":
|
||||
version "6.9.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.6.tgz#df9c3c8b31a247ec315e6996566be3171df4b3b1"
|
||||
integrity sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==
|
||||
|
||||
"@types/range-parser@*":
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
|
||||
integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==
|
||||
|
||||
"@types/serve-static@*":
|
||||
version "1.13.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.9.tgz#aacf28a85a05ee29a11fb7c3ead935ac56f33e4e"
|
||||
integrity sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==
|
||||
dependencies:
|
||||
"@types/mime" "^1"
|
||||
"@types/node" "*"
|
||||
|
||||
accepts@~1.3.7:
|
||||
version "1.3.7"
|
||||
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
|
||||
|
@ -15,6 +85,11 @@ array-flatten@1.1.1:
|
|||
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
|
||||
integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
|
||||
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
|
||||
|
||||
body-parser@1.19.0, body-parser@^1.19.0:
|
||||
version "1.19.0"
|
||||
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
|
||||
|
@ -41,6 +116,13 @@ cockatiel@^2.0.1:
|
|||
resolved "https://registry.yarnpkg.com/cockatiel/-/cockatiel-2.0.1.tgz#2b59587d54d53d33ed49b601cfaab97cad9cc6e7"
|
||||
integrity sha512-fAw5ToPGZSnoYl5NpW2zKnY/d4gAUeP4GuGnxm7W23ayTtZipwPrIv7h3z8pq0NMDISuCEkKGsXCk3bKkzb13A==
|
||||
|
||||
combined-stream@^1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||
dependencies:
|
||||
delayed-stream "~1.0.0"
|
||||
|
||||
content-disposition@0.5.3:
|
||||
version "0.5.3"
|
||||
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
|
||||
|
@ -70,6 +152,11 @@ debug@2.6.9:
|
|||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
delayed-stream@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
|
||||
|
||||
depd@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
|
||||
|
@ -149,6 +236,15 @@ finalhandler@~1.1.2:
|
|||
statuses "~1.5.0"
|
||||
unpipe "~1.0.0"
|
||||
|
||||
form-data@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f"
|
||||
integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "^1.0.8"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
forwarded@~0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
|
||||
|
@ -223,6 +319,18 @@ mime-db@1.45.0:
|
|||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.45.0.tgz#cceeda21ccd7c3a745eba2decd55d4b73e7879ea"
|
||||
integrity sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==
|
||||
|
||||
mime-db@1.47.0:
|
||||
version "1.47.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.47.0.tgz#8cb313e59965d3c05cfbf898915a267af46a335c"
|
||||
integrity sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==
|
||||
|
||||
mime-types@^2.1.12:
|
||||
version "2.1.30"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.30.tgz#6e7be8b4c479825f85ed6326695db73f9305d62d"
|
||||
integrity sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==
|
||||
dependencies:
|
||||
mime-db "1.47.0"
|
||||
|
||||
mime-types@~2.1.24:
|
||||
version "2.1.28"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.28.tgz#1160c4757eab2c5363888e005273ecf79d2a0ecd"
|
||||
|
@ -272,6 +380,11 @@ path-to-regexp@0.1.7:
|
|||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
|
||||
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
|
||||
|
||||
prettier@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5"
|
||||
integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==
|
||||
|
||||
proxy-addr@~2.0.5:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf"
|
||||
|
@ -362,6 +475,11 @@ type-is@~1.6.17, type-is@~1.6.18:
|
|||
media-typer "0.3.0"
|
||||
mime-types "~2.1.24"
|
||||
|
||||
typescript@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.3.tgz#39062d8019912d43726298f09493d598048c1ce3"
|
||||
integrity sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==
|
||||
|
||||
unpipe@1.0.0, unpipe@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
|
||||
|
|
Загрузка…
Ссылка в новой задаче