mirror of
https://github.com/matrix-org/matrix-hookshot.git
synced 2025-03-10 13:17:08 +00:00
Lots of changes
This commit is contained in:
parent
8b584f2622
commit
39c6e81cbb
@ -1,10 +1,12 @@
|
||||
node_modules/
|
||||
lib/
|
||||
tests/
|
||||
config.yml
|
||||
public/
|
||||
.github/
|
||||
logging.txt
|
||||
tsconfig.tsbuildinfo
|
||||
*.pem
|
||||
registration.yml
|
||||
config.yml
|
||||
lib/
|
||||
node_modules/
|
||||
public/
|
||||
registration.yml
|
||||
tests/
|
||||
tsconfig.tsbuildinfo
|
||||
|
||||
# Added by cargo
|
||||
/target
|
11
.gitignore
vendored
11
.gitignore
vendored
@ -1,9 +1,10 @@
|
||||
node_modules/
|
||||
lib/
|
||||
|
||||
config.yml
|
||||
*.pem
|
||||
config.yml
|
||||
lib/
|
||||
node_modules/
|
||||
public/
|
||||
registration.yml
|
||||
tsconfig.tsbuildinfo
|
||||
|
||||
public/
|
||||
# Added by cargo
|
||||
/target
|
223
Cargo.lock
generated
Normal file
223
Cargo.lock
generated
Normal file
@ -0,0 +1,223 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
|
||||
dependencies = [
|
||||
"matches",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
|
||||
dependencies = [
|
||||
"matches",
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
|
||||
|
||||
[[package]]
|
||||
name = "matrix-github"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"napi",
|
||||
"napi-build",
|
||||
"napi-derive",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "napi"
|
||||
version = "1.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9050238b713b3c5dd5ae1613da1ccefe4061c03992f9e9bbe43b7d473ba4bd3c"
|
||||
dependencies = [
|
||||
"napi-sys",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "napi-build"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87375bacff0768dd606ccf870eae936efd21e3245af9e7b37ae44f969d48be8a"
|
||||
|
||||
[[package]]
|
||||
name = "napi-derive"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ee880798e942fc785e2e234544b9db578019a1d7676f45dad7f38d432ab0fe4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "napi-sys"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67cf20e0081fea04e044aa4adf74cfea8ddc0324eec2894b1c700f4cafc72a56"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.130"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.130"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "063bf466a64011ac24040a49009724ee60a57da1b437617ceb32e53ad61bfb19"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"matches",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
18
Cargo.toml
Normal file
18
Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "matrix-github"
|
||||
version = "0.0.1"
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
napi = {version="1", features=["serde-json"]}
|
||||
napi-derive = "1"
|
||||
url = "2"
|
||||
serde_json = "1"
|
||||
serde = "1"
|
||||
serde_derive = "*"
|
||||
|
||||
[build-dependencies]
|
||||
napi-build = "1"
|
10
Dockerfile
10
Dockerfile
@ -1,11 +1,17 @@
|
||||
# Stage 0: Build the thing
|
||||
FROM node:16-alpine AS builder
|
||||
# Need debian based image to make node happy
|
||||
FROM node:16 AS builder
|
||||
|
||||
COPY . /src
|
||||
WORKDIR /src
|
||||
|
||||
RUN apk add rustup
|
||||
RUN rustup-init -y --target x86_64-unknown-linux-gnu
|
||||
ENV PATH="/root/.cargo/bin:${PATH}"
|
||||
|
||||
|
||||
# will also build
|
||||
RUN yarn
|
||||
RUN yarn
|
||||
|
||||
# Stage 1: The actual container
|
||||
FROM node:16-alpine
|
||||
|
5
build.rs
Normal file
5
build.rs
Normal file
@ -0,0 +1,5 @@
|
||||
extern crate napi_build;
|
||||
|
||||
fn main() {
|
||||
napi_build::setup();
|
||||
}
|
14
package.json
14
package.json
@ -7,21 +7,26 @@
|
||||
"author": "Half-Shot",
|
||||
"license": "MIT",
|
||||
"private": false,
|
||||
"napi": {
|
||||
"name": "matrix-github-rs"
|
||||
},
|
||||
"scripts": {
|
||||
"build:web": "snowpack build",
|
||||
"build:app": "tsc --project tsconfig.json",
|
||||
"build:app:rs": "napi build --release ./lib",
|
||||
"dev:web": "snowpack dev",
|
||||
"build": "yarn run build:web && yarn run build:app",
|
||||
"build": "yarn run build:web && yarn run build:app:rs && yarn run build:app",
|
||||
"prepare": "yarn build",
|
||||
"start": "node --require source-map-support/register lib/App/BridgeApp.js",
|
||||
"start:app": "node --require source-map-support/register lib/App/BridgeApp.js",
|
||||
"start:webhooks": "node --require source-map-support/register lib/App/GithubWebhookApp.js",
|
||||
"start:matrixsender": "node --require source-map-support/register lib/App/MatrixSenderApp.js",
|
||||
"test": "mocha -r ts-node/register tests/*.ts",
|
||||
"test": "mocha -r ts-node/register tests/*.ts tests/**/*.ts",
|
||||
"lint": "eslint -c .eslintrc.js src/**/*.ts",
|
||||
"generate-default-config": "node lib/Config/Defaults.js --config > config.sample.yml"
|
||||
},
|
||||
"dependencies": {
|
||||
"@node-rs/helper": "^1.2.1",
|
||||
"@octokit/auth-app": "^3.3.0",
|
||||
"@octokit/auth-token": "^2.4.5",
|
||||
"@octokit/rest": "^18.10.0",
|
||||
@ -47,6 +52,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@fontsource/open-sans": "^4.2.2",
|
||||
"@napi-rs/cli": "^1.3.5",
|
||||
"@prefresh/snowpack": "^3.1.2",
|
||||
"@snowpack/plugin-typescript": "^1.2.1",
|
||||
"@types/chai": "^4.2.16",
|
||||
@ -57,14 +63,14 @@
|
||||
"@types/micromatch": "^4.0.1",
|
||||
"@types/mime": "^2.0.3",
|
||||
"@types/mocha": "^8.2.2",
|
||||
"@types/node": "^12",
|
||||
"@types/node-emoji": "^1.8.1",
|
||||
"@types/node": "^12",
|
||||
"@types/uuid": "^8.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.21.0",
|
||||
"@typescript-eslint/parser": "^4.21.0",
|
||||
"chai": "^4.3.4",
|
||||
"eslint": "^7.24.0",
|
||||
"eslint-plugin-mocha": "^8.1.0",
|
||||
"eslint": "^7.24.0",
|
||||
"mini.css": "^3.0.1",
|
||||
"preact": "^10.5.13",
|
||||
"snowpack": "^3.2.2",
|
||||
|
245
src/ConnectionManager.ts
Normal file
245
src/ConnectionManager.ts
Normal file
@ -0,0 +1,245 @@
|
||||
|
||||
|
||||
/**
|
||||
* Manages connections between Matrix rooms and the remote side.
|
||||
*/
|
||||
|
||||
import { Appservice, StateEvent } from "matrix-bot-sdk";
|
||||
import { CommentProcessor } from "./CommentProcessor";
|
||||
import { BridgeConfig, GitLabInstance } from "./Config/Config";
|
||||
import { GitHubDiscussionConnection, GitHubDiscussionSpace, GitHubIssueConnection, GitHubRepoConnection, GitHubUserSpace, GitLabIssueConnection, GitLabRepoConnection, IConnection } from "./Connections";
|
||||
import { GenericHookConnection } from "./Connections/GenericHook";
|
||||
import { JiraProjectConnection } from "./Connections/JiraProject";
|
||||
import { GithubInstance } from "./Github/GithubInstance";
|
||||
import { GitLabClient } from "./Gitlab/Client";
|
||||
import LogWrapper from "./LogWrapper";
|
||||
import { MessageSenderClient } from "./MatrixSender";
|
||||
import { UserTokenStore } from "./UserTokenStore";
|
||||
|
||||
const log = new LogWrapper("ConnectionManager");
|
||||
|
||||
export class ConnectionManager {
|
||||
private connections: IConnection[] = [];
|
||||
|
||||
constructor(
|
||||
private readonly as: Appservice,
|
||||
private readonly config: BridgeConfig,
|
||||
private readonly tokenStore: UserTokenStore,
|
||||
private readonly commentProcessor: CommentProcessor,
|
||||
private readonly messageClient: MessageSenderClient,
|
||||
private readonly github?: GithubInstance) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Push a new connection to the manager, if this connection already
|
||||
* exists then this will no-op.
|
||||
* NOTE: The comparison only checks that the same object instance isn't present,
|
||||
* but not if two instances exist with the same type/state.
|
||||
* @param connection The connection instance to push.
|
||||
*/
|
||||
public push(...connections: IConnection[]) {
|
||||
// NOTE: Double loop
|
||||
for (const connection of connections) {
|
||||
if (this.connections.find((c) => c !== connection)) {
|
||||
this.connections.push(connection);
|
||||
}
|
||||
}
|
||||
// Already exists, noop.
|
||||
}
|
||||
|
||||
public async createConnectionForState(roomId: string, state: StateEvent<any>) {
|
||||
log.debug(`Looking to create connection for ${roomId}`);
|
||||
if (state.content.disabled === false) {
|
||||
log.debug(`${roomId} has disabled state for ${state.type}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GitHubRepoConnection.EventTypes.includes(state.type)) {
|
||||
if (!this.github) {
|
||||
throw Error('GitHub is not configured');
|
||||
}
|
||||
return new GitHubRepoConnection(roomId, this.as, state.content, this.tokenStore, state.stateKey);
|
||||
}
|
||||
|
||||
if (GitHubDiscussionConnection.EventTypes.includes(state.type)) {
|
||||
if (!this.github) {
|
||||
throw Error('GitHub is not configured');
|
||||
}
|
||||
return new GitHubDiscussionConnection(
|
||||
roomId, this.as, state.content, state.stateKey, this.tokenStore, this.commentProcessor,
|
||||
this.messageClient,
|
||||
);
|
||||
}
|
||||
|
||||
if (GitHubDiscussionSpace.EventTypes.includes(state.type)) {
|
||||
if (!this.github) {
|
||||
throw Error('GitHub is not configured');
|
||||
}
|
||||
|
||||
return new GitHubDiscussionSpace(
|
||||
await this.as.botClient.getSpace(roomId), state.content, state.stateKey
|
||||
);
|
||||
}
|
||||
|
||||
if (GitHubIssueConnection.EventTypes.includes(state.type)) {
|
||||
if (!this.github) {
|
||||
throw Error('GitHub is not configured');
|
||||
}
|
||||
const issue = new GitHubIssueConnection(roomId, this.as, state.content, state.stateKey || "", this.tokenStore, this.commentProcessor, this.messageClient, this.github);
|
||||
await issue.syncIssueState();
|
||||
return issue;
|
||||
}
|
||||
|
||||
if (GitHubUserSpace.EventTypes.includes(state.type)) {
|
||||
if (!this.github) {
|
||||
throw Error('GitHub is not configured');
|
||||
}
|
||||
return new GitHubUserSpace(
|
||||
await this.as.botClient.getSpace(roomId), state.content, state.stateKey
|
||||
);
|
||||
}
|
||||
|
||||
if (GitLabRepoConnection.EventTypes.includes(state.type)) {
|
||||
if (!this.config.gitlab) {
|
||||
throw Error('GitLab is not configured');
|
||||
}
|
||||
const instance = this.config.gitlab.instances[state.content.instance];
|
||||
if (!instance) {
|
||||
throw Error('Instance name not recognised');
|
||||
}
|
||||
return new GitLabRepoConnection(roomId, this.as, state.content, this.tokenStore, instance);
|
||||
}
|
||||
|
||||
if (GitLabIssueConnection.EventTypes.includes(state.type)) {
|
||||
if (!this.config.gitlab) {
|
||||
throw Error('GitLab is not configured');
|
||||
}
|
||||
const instance = this.config.gitlab.instances[state.content.instance];
|
||||
return new GitLabIssueConnection(
|
||||
roomId,
|
||||
this.as,
|
||||
state.content,
|
||||
state.stateKey as string,
|
||||
this.tokenStore,
|
||||
this.commentProcessor,
|
||||
this.messageClient,
|
||||
instance);
|
||||
}
|
||||
|
||||
if (JiraProjectConnection.EventTypes.includes(state.type)) {
|
||||
if (!this.config.jira) {
|
||||
throw Error('JIRA is not configured');
|
||||
}
|
||||
return new JiraProjectConnection(roomId, this.as, state.content, state.stateKey, this.commentProcessor, this.messageClient);
|
||||
}
|
||||
|
||||
if (GenericHookConnection.EventTypes.includes(state.type) && this.config.generic?.enabled) {
|
||||
return new GenericHookConnection(
|
||||
roomId,
|
||||
state.content,
|
||||
state.stateKey,
|
||||
this.messageClient,
|
||||
this.config.generic.allowJsTransformationFunctions
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
public async createConnectionsForRoomId(roomId: string): Promise<IConnection[]> {
|
||||
const state = await this.as.botClient.getRoomState(roomId);
|
||||
const connections: IConnection[] = [];
|
||||
for (const event of state) {
|
||||
const conn = await this.createConnectionForState(roomId, new StateEvent(event));
|
||||
if (conn) { connections.push(conn); }
|
||||
}
|
||||
return connections;
|
||||
}
|
||||
|
||||
public getConnectionsForGithubIssue(org: string, repo: string, issueNumber: number): (GitHubIssueConnection|GitLabRepoConnection)[] {
|
||||
org = org.toLowerCase();
|
||||
repo = repo.toLowerCase();
|
||||
return this.connections.filter((c) => (c instanceof GitHubIssueConnection && c.org === org && c.repo === repo && c.issueNumber === issueNumber) ||
|
||||
(c instanceof GitHubRepoConnection && c.org === org && c.repo === repo)) as (GitHubIssueConnection|GitLabRepoConnection)[];
|
||||
}
|
||||
|
||||
public getConnectionsForGithubRepo(org: string, repo: string): GitHubRepoConnection[] {
|
||||
org = org.toLowerCase();
|
||||
repo = repo.toLowerCase();
|
||||
return this.connections.filter((c) => (c instanceof GitHubRepoConnection && c.org === org && c.repo === repo)) as GitHubRepoConnection[];
|
||||
}
|
||||
|
||||
public getConnectionsForGithubRepoDiscussion(owner: string, repo: string): GitHubDiscussionSpace[] {
|
||||
owner = owner.toLowerCase();
|
||||
repo = repo.toLowerCase();
|
||||
return this.connections.filter((c) => (c instanceof GitHubDiscussionSpace && c.owner === owner && c.repo === repo)) as GitHubDiscussionSpace[];
|
||||
}
|
||||
|
||||
public getConnectionForGithubUser(user: string): GitHubUserSpace {
|
||||
return this.connections.find(c => c instanceof GitHubUserSpace && c.owner === user.toLowerCase()) as GitHubUserSpace;
|
||||
}
|
||||
|
||||
public getConnectionsForGithubDiscussion(owner: string, repo: string, discussionNumber: number) {
|
||||
owner = owner.toLowerCase();
|
||||
repo = repo.toLowerCase();
|
||||
return this.connections.filter(
|
||||
(c) => (
|
||||
c instanceof GitHubDiscussionConnection &&
|
||||
c.owner === owner &&
|
||||
c.repo === repo &&
|
||||
c.discussionNumber === discussionNumber
|
||||
)
|
||||
) as GitHubDiscussionConnection[];
|
||||
}
|
||||
|
||||
public getConnectionsForGitLabIssueWebhook(repoHome: string, issueId: number) {
|
||||
if (!this.config.gitlab) {
|
||||
throw Error('GitLab configuration missing, cannot handle note');
|
||||
}
|
||||
const res = GitLabClient.splitUrlIntoParts(this.config.gitlab.instances, repoHome);
|
||||
if (!res) {
|
||||
throw Error('No instance found for note');
|
||||
}
|
||||
const instance = this.config.gitlab.instances[res[0]];
|
||||
return this.getConnectionsForGitLabIssue(instance, res[1], issueId);
|
||||
}
|
||||
|
||||
public getConnectionsForGitLabIssue(instance: GitLabInstance, projects: string[], issueNumber: number): GitLabIssueConnection[] {
|
||||
return this.connections.filter((c) => (
|
||||
c instanceof GitLabIssueConnection &&
|
||||
c.issueNumber == issueNumber &&
|
||||
c.instanceUrl == instance.url &&
|
||||
c.projectPath == projects.join("/")
|
||||
)) as GitLabIssueConnection[];
|
||||
}
|
||||
|
||||
public getConnectionsForGitLabRepo(pathWithNamespace: string): GitLabRepoConnection[] {
|
||||
pathWithNamespace = pathWithNamespace.toLowerCase();
|
||||
return this.connections.filter((c) => (c instanceof GitLabRepoConnection && c.path === pathWithNamespace)) as GitLabRepoConnection[];
|
||||
}
|
||||
|
||||
public getConnectionsForJiraProject(projectId: string, eventName: string): JiraProjectConnection[] {
|
||||
return this.connections.filter((c) => (c instanceof JiraProjectConnection && c.projectId === projectId && c.isInterestedInHookEvent(eventName))) as JiraProjectConnection[];
|
||||
}
|
||||
|
||||
public getConnectionsForGenericWebhook(hookId: string): GenericHookConnection[] {
|
||||
return this.connections.filter((c) => (c instanceof GenericHookConnection && c.hookId === hookId)) as GenericHookConnection[];
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
public getAllConnectionsOfType<T extends IConnection>(typeT: new (...params : any[]) => T): T[] {
|
||||
return this.connections.filter((c) => (c instanceof typeT)) as T[];
|
||||
}
|
||||
|
||||
public isRoomConnected(roomId: string): boolean {
|
||||
return !!this.connections.find(c => c.roomId === roomId);
|
||||
}
|
||||
|
||||
public getAllConnectionsForRoom(roomId: string): IConnection[] {
|
||||
return this.connections.filter(c => c.roomId === roomId);
|
||||
}
|
||||
|
||||
public getInterestedForRoomState(roomId: string, eventType: string, stateKey: string): IConnection[] {
|
||||
return this.connections.filter(c => c.roomId === roomId && c.isInterestedInStateEvent(eventType, stateKey));
|
||||
}
|
||||
}
|
@ -25,5 +25,10 @@ export interface IConnection {
|
||||
|
||||
isInterestedInStateEvent: (eventType: string, stateKey: string) => boolean;
|
||||
|
||||
/**
|
||||
* Is the connection interested in the event that is being sent from the remote side?
|
||||
*/
|
||||
isInterestedInHookEvent?: (eventType: string) => boolean;
|
||||
|
||||
toString(): string;
|
||||
}
|
@ -6,10 +6,13 @@ import { MessageSenderClient } from "../MatrixSender"
|
||||
import { JiraIssueEvent } from "../Jira/WebhookTypes";
|
||||
import { FormatUtil } from "../FormatUtil";
|
||||
import markdownit from "markdown-it";
|
||||
import { generateWebLinkFromIssue } from "../Jira/Utils";
|
||||
import { generateJiraWebLinkFromIssue } from "../Jira/Utils";
|
||||
|
||||
type JiraAllowedEventsNames = "issue.created";
|
||||
const JiraAllowedEvents: JiraAllowedEventsNames[] = ["issue.created"];
|
||||
export interface JiraProjectConnectionState {
|
||||
id: string;
|
||||
events?: JiraAllowedEventsNames[],
|
||||
}
|
||||
|
||||
const log = new LogWrapper("JiraProjectConnection");
|
||||
@ -33,6 +36,10 @@ export class JiraProjectConnection implements IConnection {
|
||||
return this.state.id;
|
||||
}
|
||||
|
||||
public isInterestedInHookEvent(eventName: string) {
|
||||
return !this.state.events || this.state.events?.includes(eventName as JiraAllowedEventsNames);
|
||||
}
|
||||
|
||||
constructor(public readonly roomId: string,
|
||||
private readonly as: Appservice,
|
||||
private state: JiraProjectConnectionState,
|
||||
@ -47,11 +54,12 @@ export class JiraProjectConnection implements IConnection {
|
||||
|
||||
public async onJiraIssueCreated(data: JiraIssueEvent) {
|
||||
log.info(`onIssueCreated ${this.roomId} ${this.projectId} ${data.issue.id}`);
|
||||
|
||||
const creator = data.issue.fields.creator;
|
||||
if (!creator) {
|
||||
throw Error('No creator field');
|
||||
}
|
||||
const url = generateWebLinkFromIssue(data.issue);
|
||||
const url = generateJiraWebLinkFromIssue(data.issue);
|
||||
const content = `${creator.displayName} created a new JIRA issue [${data.issue.key}](${url}): "${data.issue.fields.summary}"`;
|
||||
await this.as.botIntent.sendEvent(this.roomId, {
|
||||
msgtype: "m.notice",
|
||||
|
41
src/FormatUtil.rs
Normal file
41
src/FormatUtil.rs
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
use napi::{CallContext, Env, Error as NapiError, JsObject, JsUnknown};
|
||||
|
||||
use crate::Jira::types::{JiraIssue, JiraIssueLight};
|
||||
use crate::Jira;
|
||||
|
||||
|
||||
pub fn get_module(env: Env) -> Result<JsObject, NapiError> {
|
||||
let mut root_module = env.create_object()?;
|
||||
root_module.create_named_method("get_partial_body_for_jira_issue", get_partial_body_for_jira_issue)?;
|
||||
Ok(root_module)
|
||||
}
|
||||
|
||||
/// Generate a URL for a given Jira Issue object.
|
||||
#[js_function(1)]
|
||||
pub fn get_partial_body_for_jira_issue(ctx: CallContext) -> Result<JsObject, NapiError> {
|
||||
let jira_issue: JiraIssue = ctx.env.from_js_value(ctx.get::<JsUnknown>(0)?)?;
|
||||
let light = JiraIssueLight {
|
||||
_self: jira_issue._self,
|
||||
key: jira_issue.key,
|
||||
};
|
||||
let mut body = ctx.env.create_object()?;
|
||||
let url = Jira::utils::generate_jira_web_link_from_issue(&light)?;
|
||||
body.set_named_property("external_url", ctx.env.create_string_from_std(url)?)?;
|
||||
|
||||
let mut jira_issue_result = ctx.env.create_object()?;
|
||||
let mut jira_project = ctx.env.create_object()?;
|
||||
|
||||
|
||||
jira_issue_result.set_named_property("id", ctx.env.create_string_from_std(jira_issue.id)?)?;
|
||||
jira_issue_result.set_named_property("key", ctx.env.create_string_from_std(light.key)?)?;
|
||||
jira_issue_result.set_named_property("api_url", ctx.env.create_string_from_std(light._self)?)?;
|
||||
|
||||
jira_project.set_named_property("id", ctx.env.create_string_from_std(jira_issue.fields.project.id)?)?;
|
||||
jira_project.set_named_property("key", ctx.env.create_string_from_std(jira_issue.fields.project.key)?)?;
|
||||
jira_project.set_named_property("api_url", ctx.env.create_string_from_std(jira_issue.fields.project._self)?)?;
|
||||
|
||||
body.set_named_property("uk.half-shot.matrix-github.jira.issue", jira_issue_result)?;
|
||||
body.set_named_property("uk.half-shot.matrix-github.jira.project", jira_project)?;
|
||||
Ok(body)
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
/* eslint-disable camelcase */
|
||||
import { ProjectsListResponseData } from './Github/Types';
|
||||
import emoji from "node-emoji";
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
import { contrastColor } from "contrast-color";
|
||||
import { JiraIssue } from './Jira/Types';
|
||||
import { generateWebLinkFromIssue } from './Jira/Utils';
|
||||
import { format_util } from "./libRs";
|
||||
|
||||
interface IMinimalRepository {
|
||||
id: number;
|
||||
full_name: string;
|
||||
@ -104,19 +106,6 @@ export class FormatUtil {
|
||||
}
|
||||
|
||||
public static getPartialBodyForJiraIssue(issue: JiraIssue) {
|
||||
const url = generateWebLinkFromIssue(issue);
|
||||
return {
|
||||
"external_url": url,
|
||||
"uk.half-shot.matrix-github.jira.issue": {
|
||||
id: issue.id,
|
||||
key: issue.key,
|
||||
api_url: issue.self,
|
||||
},
|
||||
"uk.half-shot.matrix-github.jira.project": {
|
||||
id: issue.fields.project.id,
|
||||
key: issue.fields.project.key,
|
||||
api_url: issue.fields.project.self,
|
||||
},
|
||||
};
|
||||
return format_util.get_partial_body_for_jira_issue(issue);
|
||||
}
|
||||
}
|
||||
|
@ -31,10 +31,12 @@ import { UserNotificationsEvent } from "./Notifications/UserNotificationWatcher"
|
||||
import { UserTokenStore } from "./UserTokenStore";
|
||||
import * as GitHubWebhookTypes from "@octokit/webhooks-types";
|
||||
import LogWrapper from "./LogWrapper";
|
||||
import { ConnectionManager } from "./ConnectionManager";
|
||||
|
||||
const log = new LogWrapper("GithubBridge");
|
||||
|
||||
export class GithubBridge {
|
||||
private connectionManager?: ConnectionManager;
|
||||
private github?: GithubInstance;
|
||||
private as!: Appservice;
|
||||
private encryptedMatrixClient?: MatrixClient;
|
||||
@ -45,193 +47,11 @@ export class GithubBridge {
|
||||
private tokenStore!: UserTokenStore;
|
||||
private messageClient!: MessageSenderClient;
|
||||
private widgetApi!: BridgeWidgetApi;
|
||||
private connections: IConnection[] = [];
|
||||
|
||||
private ready = false;
|
||||
|
||||
constructor(private config: BridgeConfig, private registration: IAppserviceRegistration) { }
|
||||
|
||||
private async createConnectionForState(roomId: string, state: StateEvent<any>) {
|
||||
log.debug(`Looking to create connection for ${roomId}`);
|
||||
if (state.content.disabled === false) {
|
||||
log.debug(`${roomId} has disabled state for ${state.type}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GitHubRepoConnection.EventTypes.includes(state.type)) {
|
||||
if (!this.github) {
|
||||
throw Error('GitHub is not configured');
|
||||
}
|
||||
return new GitHubRepoConnection(roomId, this.as, state.content, this.tokenStore, state.stateKey);
|
||||
}
|
||||
|
||||
if (GitHubDiscussionConnection.EventTypes.includes(state.type)) {
|
||||
if (!this.github) {
|
||||
throw Error('GitHub is not configured');
|
||||
}
|
||||
return new GitHubDiscussionConnection(
|
||||
roomId, this.as, state.content, state.stateKey, this.tokenStore, this.commentProcessor,
|
||||
this.messageClient,
|
||||
);
|
||||
}
|
||||
|
||||
if (GitHubDiscussionSpace.EventTypes.includes(state.type)) {
|
||||
if (!this.github) {
|
||||
throw Error('GitHub is not configured');
|
||||
}
|
||||
|
||||
return new GitHubDiscussionSpace(
|
||||
await this.as.botClient.getSpace(roomId), state.content, state.stateKey
|
||||
);
|
||||
}
|
||||
|
||||
if (GitHubIssueConnection.EventTypes.includes(state.type)) {
|
||||
if (!this.github) {
|
||||
throw Error('GitHub is not configured');
|
||||
}
|
||||
const issue = new GitHubIssueConnection(roomId, this.as, state.content, state.stateKey || "", this.tokenStore, this.commentProcessor, this.messageClient, this.github);
|
||||
await issue.syncIssueState();
|
||||
return issue;
|
||||
}
|
||||
|
||||
if (GitHubUserSpace.EventTypes.includes(state.type)) {
|
||||
if (!this.github) {
|
||||
throw Error('GitHub is not configured');
|
||||
}
|
||||
return new GitHubUserSpace(
|
||||
await this.as.botClient.getSpace(roomId), state.content, state.stateKey
|
||||
);
|
||||
}
|
||||
|
||||
if (GitLabRepoConnection.EventTypes.includes(state.type)) {
|
||||
if (!this.config.gitlab) {
|
||||
throw Error('GitLab is not configured');
|
||||
}
|
||||
const instance = this.config.gitlab.instances[state.content.instance];
|
||||
if (!instance) {
|
||||
throw Error('Instance name not recognised');
|
||||
}
|
||||
return new GitLabRepoConnection(roomId, this.as, state.content, this.tokenStore, instance);
|
||||
}
|
||||
|
||||
if (GitLabIssueConnection.EventTypes.includes(state.type)) {
|
||||
if (!this.config.gitlab) {
|
||||
throw Error('GitLab is not configured');
|
||||
}
|
||||
const instance = this.config.gitlab.instances[state.content.instance];
|
||||
return new GitLabIssueConnection(
|
||||
roomId,
|
||||
this.as,
|
||||
state.content,
|
||||
state.stateKey as string,
|
||||
this.tokenStore,
|
||||
this.commentProcessor,
|
||||
this.messageClient,
|
||||
instance);
|
||||
}
|
||||
|
||||
if (JiraProjectConnection.EventTypes.includes(state.type)) {
|
||||
if (!this.config.jira) {
|
||||
throw Error('JIRA is not configured');
|
||||
}
|
||||
return new JiraProjectConnection(roomId, this.as, state.content, state.stateKey, this.commentProcessor, this.messageClient);
|
||||
}
|
||||
|
||||
if (GenericHookConnection.EventTypes.includes(state.type) && this.config.generic?.enabled) {
|
||||
return new GenericHookConnection(
|
||||
roomId,
|
||||
state.content,
|
||||
state.stateKey,
|
||||
this.messageClient,
|
||||
this.config.generic.allowJsTransformationFunctions
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
private async createConnectionsForRoomId(roomId: string): Promise<IConnection[]> {
|
||||
const state = await this.as.botClient.getRoomState(roomId);
|
||||
const connections: IConnection[] = [];
|
||||
for (const event of state) {
|
||||
const conn = await this.createConnectionForState(roomId, new StateEvent(event));
|
||||
if (conn) { connections.push(conn); }
|
||||
}
|
||||
return connections;
|
||||
}
|
||||
|
||||
private getConnectionsForGithubIssue(org: string, repo: string, issueNumber: number): (GitHubIssueConnection|GitLabRepoConnection)[] {
|
||||
org = org.toLowerCase();
|
||||
repo = repo.toLowerCase();
|
||||
return this.connections.filter((c) => (c instanceof GitHubIssueConnection && c.org === org && c.repo === repo && c.issueNumber === issueNumber) ||
|
||||
(c instanceof GitHubRepoConnection && c.org === org && c.repo === repo)) as (GitHubIssueConnection|GitLabRepoConnection)[];
|
||||
}
|
||||
|
||||
private getConnectionsForGithubRepo(org: string, repo: string): GitHubRepoConnection[] {
|
||||
org = org.toLowerCase();
|
||||
repo = repo.toLowerCase();
|
||||
return this.connections.filter((c) => (c instanceof GitHubRepoConnection && c.org === org && c.repo === repo)) as GitHubRepoConnection[];
|
||||
}
|
||||
|
||||
private getConnectionsForGithubRepoDiscussion(owner: string, repo: string): GitHubDiscussionSpace[] {
|
||||
owner = owner.toLowerCase();
|
||||
repo = repo.toLowerCase();
|
||||
return this.connections.filter((c) => (c instanceof GitHubDiscussionSpace && c.owner === owner && c.repo === repo)) as GitHubDiscussionSpace[];
|
||||
}
|
||||
|
||||
private getConnectionForGithubUser(user: string): GitHubUserSpace {
|
||||
return this.connections.find(c => c instanceof GitHubUserSpace && c.owner === user.toLowerCase()) as GitHubUserSpace;
|
||||
}
|
||||
|
||||
|
||||
private getConnectionsForGithubDiscussion(owner: string, repo: string, discussionNumber: number) {
|
||||
owner = owner.toLowerCase();
|
||||
repo = repo.toLowerCase();
|
||||
return this.connections.filter(
|
||||
(c) => (
|
||||
c instanceof GitHubDiscussionConnection &&
|
||||
c.owner === owner &&
|
||||
c.repo === repo &&
|
||||
c.discussionNumber === discussionNumber
|
||||
)
|
||||
) as GitHubDiscussionConnection[];
|
||||
}
|
||||
|
||||
private getConnectionsForGitLabIssueWebhook(repoHome: string, issueId: number) {
|
||||
if (!this.config.gitlab) {
|
||||
throw Error('GitLab configuration missing, cannot handle note');
|
||||
}
|
||||
const res = GitLabClient.splitUrlIntoParts(this.config.gitlab.instances, repoHome);
|
||||
if (!res) {
|
||||
throw Error('No instance found for note');
|
||||
}
|
||||
const instance = this.config.gitlab.instances[res[0]];
|
||||
return this.getConnectionsForGitLabIssue(instance, res[1], issueId);
|
||||
}
|
||||
|
||||
private getConnectionsForGitLabIssue(instance: GitLabInstance, projects: string[], issueNumber: number): GitLabIssueConnection[] {
|
||||
return this.connections.filter((c) => (
|
||||
c instanceof GitLabIssueConnection &&
|
||||
c.issueNumber == issueNumber &&
|
||||
c.instanceUrl == instance.url &&
|
||||
c.projectPath == projects.join("/")
|
||||
)) as GitLabIssueConnection[];
|
||||
}
|
||||
|
||||
private getConnectionsForGitLabRepo(pathWithNamespace: string): GitLabRepoConnection[] {
|
||||
pathWithNamespace = pathWithNamespace.toLowerCase();
|
||||
return this.connections.filter((c) => (c instanceof GitLabRepoConnection && c.path === pathWithNamespace)) as GitLabRepoConnection[];
|
||||
}
|
||||
|
||||
private getConnectionsForJiraProject(projectId: string): JiraProjectConnection[] {
|
||||
return this.connections.filter((c) => (c instanceof JiraProjectConnection && c.projectId === projectId)) as JiraProjectConnection[];
|
||||
}
|
||||
|
||||
private getConnectionsForGenericWebhook(hookId: string): GenericHookConnection[] {
|
||||
return this.connections.filter((c) => (c instanceof GenericHookConnection && c.hookId === hookId)) as GenericHookConnection[];
|
||||
}
|
||||
|
||||
|
||||
public stop() {
|
||||
this.as.stop();
|
||||
if(this.queue.stop) this.queue.stop();
|
||||
@ -300,6 +120,8 @@ export class GithubBridge {
|
||||
|
||||
this.tokenStore = new UserTokenStore(this.config.passFile || "./passkey.pem", this.as.botIntent);
|
||||
await this.tokenStore.load();
|
||||
const connManager = this.connectionManager = new ConnectionManager(this.as,
|
||||
this.config, this.tokenStore, this.commentProcessor, this.messageClient, this.github);
|
||||
|
||||
this.as.on("query.room", async (roomAlias, cb) => {
|
||||
try {
|
||||
@ -347,7 +169,7 @@ export class GithubBridge {
|
||||
|
||||
this.queue.on<GitHubWebhookTypes.IssueCommentCreatedEvent>("github.issue_comment.created", async ({ data }) => {
|
||||
const { repository, issue, owner } = validateRepoIssue(data);
|
||||
const connections = this.getConnectionsForGithubIssue(owner, repository.name, issue.number);
|
||||
const connections = connManager.getConnectionsForGithubIssue(owner, repository.name, issue.number);
|
||||
connections.map(async (c) => {
|
||||
try {
|
||||
if (c instanceof GitHubIssueConnection)
|
||||
@ -360,7 +182,7 @@ export class GithubBridge {
|
||||
|
||||
this.queue.on<GitHubWebhookTypes.IssuesOpenedEvent>("github.issues.opened", async ({ data }) => {
|
||||
const { repository, owner } = validateRepoIssue(data);
|
||||
const connections = this.getConnectionsForGithubRepo(owner, repository.name);
|
||||
const connections = connManager.getConnectionsForGithubRepo(owner, repository.name);
|
||||
connections.map(async (c) => {
|
||||
try {
|
||||
await c.onIssueCreated(data);
|
||||
@ -372,7 +194,7 @@ export class GithubBridge {
|
||||
|
||||
this.queue.on<GitHubWebhookTypes.IssuesEditedEvent>("github.issues.edited", async ({ data }) => {
|
||||
const { repository, issue, owner } = validateRepoIssue(data);
|
||||
const connections = this.getConnectionsForGithubIssue(owner, repository.name, issue.number);
|
||||
const connections = connManager.getConnectionsForGithubIssue(owner, repository.name, issue.number);
|
||||
connections.map(async (c) => {
|
||||
try {
|
||||
// TODO: Needs impls
|
||||
@ -386,7 +208,7 @@ export class GithubBridge {
|
||||
|
||||
this.queue.on<GitHubWebhookTypes.IssuesClosedEvent>("github.issues.closed", async ({ data }) => {
|
||||
const { repository, issue, owner } = validateRepoIssue(data);
|
||||
const connections = this.getConnectionsForGithubIssue(owner, repository.name, issue.number);
|
||||
const connections = connManager.getConnectionsForGithubIssue(owner, repository.name, issue.number);
|
||||
connections.map(async (c) => {
|
||||
try {
|
||||
if (c instanceof GitHubIssueConnection || c instanceof GitHubRepoConnection)
|
||||
@ -399,7 +221,7 @@ export class GithubBridge {
|
||||
|
||||
this.queue.on<GitHubWebhookTypes.IssuesReopenedEvent>("github.issues.reopened", async ({ data }) => {
|
||||
const { repository, issue, owner } = validateRepoIssue(data);
|
||||
const connections = this.getConnectionsForGithubIssue(owner, repository.name, issue.number);
|
||||
const connections = connManager.getConnectionsForGithubIssue(owner, repository.name, issue.number);
|
||||
connections.map(async (c) => {
|
||||
try {
|
||||
if (c instanceof GitHubIssueConnection || c instanceof GitHubRepoConnection)
|
||||
@ -412,7 +234,7 @@ export class GithubBridge {
|
||||
|
||||
this.queue.on<GitHubWebhookTypes.IssuesEditedEvent>("github.issues.edited", async ({ data }) => {
|
||||
const { repository, issue, owner } = validateRepoIssue(data);
|
||||
const connections = this.getConnectionsForGithubRepo(owner, repository.name);
|
||||
const connections = connManager.getConnectionsForGithubRepo(owner, repository.name);
|
||||
connections.map(async (c) => {
|
||||
try {
|
||||
await c.onIssueEdited(data);
|
||||
@ -423,7 +245,7 @@ export class GithubBridge {
|
||||
});
|
||||
|
||||
this.queue.on<GitHubWebhookTypes.PullRequestOpenedEvent>("github.pull_request.opened", async ({ data }) => {
|
||||
const connections = this.getConnectionsForGithubRepo(data.repository.owner.login, data.repository.name);
|
||||
const connections = connManager.getConnectionsForGithubRepo(data.repository.owner.login, data.repository.name);
|
||||
connections.map(async (c) => {
|
||||
try {
|
||||
await c.onPROpened(data);
|
||||
@ -434,7 +256,7 @@ export class GithubBridge {
|
||||
});
|
||||
|
||||
this.queue.on<GitHubWebhookTypes.PullRequestClosedEvent>("github.pull_request.closed", async ({ data }) => {
|
||||
const connections = this.getConnectionsForGithubRepo(data.repository.owner.login, data.repository.name);
|
||||
const connections = connManager.getConnectionsForGithubRepo(data.repository.owner.login, data.repository.name);
|
||||
connections.map(async (c) => {
|
||||
try {
|
||||
await c.onPRClosed(data);
|
||||
@ -445,7 +267,7 @@ export class GithubBridge {
|
||||
});
|
||||
|
||||
this.queue.on<GitHubWebhookTypes.PullRequestReadyForReviewEvent>("github.pull_request.ready_for_review", async ({ data }) => {
|
||||
const connections = this.getConnectionsForGithubRepo(data.repository.owner.login, data.repository.name);
|
||||
const connections = connManager.getConnectionsForGithubRepo(data.repository.owner.login, data.repository.name);
|
||||
connections.map(async (c) => {
|
||||
try {
|
||||
await c.onPRReadyForReview(data);
|
||||
@ -456,7 +278,7 @@ export class GithubBridge {
|
||||
});
|
||||
|
||||
this.queue.on<GitHubWebhookTypes.PullRequestReviewSubmittedEvent>("github.pull_request_review.submitted", async ({ data }) => {
|
||||
const connections = this.getConnectionsForGithubRepo(data.repository.owner.login, data.repository.name);
|
||||
const connections = connManager.getConnectionsForGithubRepo(data.repository.owner.login, data.repository.name);
|
||||
connections.map(async (c) => {
|
||||
try {
|
||||
await c.onPRReviewed(data);
|
||||
@ -467,7 +289,7 @@ export class GithubBridge {
|
||||
});
|
||||
|
||||
this.queue.on<GitHubWebhookTypes.ReleaseCreatedEvent>("github.release.created", async ({ data }) => {
|
||||
const connections = this.getConnectionsForGithubRepo(data.repository.owner.login, data.repository.name);
|
||||
const connections = connManager.getConnectionsForGithubRepo(data.repository.owner.login, data.repository.name);
|
||||
connections.map(async (c) => {
|
||||
try {
|
||||
await c.onReleaseCreated(data);
|
||||
@ -478,7 +300,7 @@ export class GithubBridge {
|
||||
});
|
||||
|
||||
this.queue.on<IGitLabWebhookMREvent>("gitlab.merge_request.open", async (msg) => {
|
||||
const connections = this.getConnectionsForGitLabRepo(msg.data.project.path_with_namespace);
|
||||
const connections = connManager.getConnectionsForGitLabRepo(msg.data.project.path_with_namespace);
|
||||
connections.map(async (c) => {
|
||||
try {
|
||||
await c.onMergeRequestOpened(msg.data);
|
||||
@ -489,7 +311,7 @@ export class GithubBridge {
|
||||
});
|
||||
|
||||
this.queue.on<IGitLabWebhookMREvent>("gitlab.tag_push", async (msg) => {
|
||||
const connections = this.getConnectionsForGitLabRepo(msg.data.project.path_with_namespace);
|
||||
const connections = connManager.getConnectionsForGitLabRepo(msg.data.project.path_with_namespace);
|
||||
connections.map(async (c) => {
|
||||
try {
|
||||
await c.onMergeRequestOpened(msg.data);
|
||||
@ -529,7 +351,7 @@ export class GithubBridge {
|
||||
});
|
||||
|
||||
this.queue.on<IGitLabWebhookNoteEvent>("gitlab.note.created", async ({data}) => {
|
||||
const connections = this.getConnectionsForGitLabIssueWebhook(data.repository.homepage, data.issue.iid);
|
||||
const connections = connManager.getConnectionsForGitLabIssueWebhook(data.repository.homepage, data.issue.iid);
|
||||
connections.map(async (c) => {
|
||||
try {
|
||||
if (c.onCommentCreated)
|
||||
@ -541,7 +363,7 @@ export class GithubBridge {
|
||||
});
|
||||
|
||||
this.queue.on<IGitLabWebhookIssueStateEvent>("gitlab.issue.reopen", async ({data}) => {
|
||||
const connections = this.getConnectionsForGitLabIssueWebhook(data.repository.homepage, data.object_attributes.iid);
|
||||
const connections = connManager.getConnectionsForGitLabIssueWebhook(data.repository.homepage, data.object_attributes.iid);
|
||||
connections.map(async (c) => {
|
||||
try {
|
||||
await c.onIssueReopened();
|
||||
@ -552,7 +374,7 @@ export class GithubBridge {
|
||||
});
|
||||
|
||||
this.queue.on<IGitLabWebhookIssueStateEvent>("gitlab.issue.close", async ({data}) => {
|
||||
const connections = this.getConnectionsForGitLabIssueWebhook(data.repository.homepage, data.object_attributes.iid);
|
||||
const connections = connManager.getConnectionsForGitLabIssueWebhook(data.repository.homepage, data.object_attributes.iid);
|
||||
connections.map(async (c) => {
|
||||
try {
|
||||
await c.onIssueClosed();
|
||||
@ -563,7 +385,7 @@ export class GithubBridge {
|
||||
});
|
||||
|
||||
this.queue.on<GitHubWebhookTypes.DiscussionCommentCreatedEvent>("github.discussion_comment.created", async ({data}) => {
|
||||
const connections = this.getConnectionsForGithubDiscussion(data.repository.owner.login, data.repository.name, data.discussion.number);
|
||||
const connections = connManager.getConnectionsForGithubDiscussion(data.repository.owner.login, data.repository.name, data.discussion.number);
|
||||
connections.map(async (c) => {
|
||||
try {
|
||||
await c.onDiscussionCommentCreated(data);
|
||||
@ -577,13 +399,13 @@ export class GithubBridge {
|
||||
if (!this.github) {
|
||||
return;
|
||||
}
|
||||
const spaces = this.getConnectionsForGithubRepoDiscussion(data.repository.owner.login, data.repository.name);
|
||||
const spaces = connManager.getConnectionsForGithubRepoDiscussion(data.repository.owner.login, data.repository.name);
|
||||
if (spaces.length === 0) {
|
||||
log.info(`Not creating discussion ${data.discussion.id} ${data.repository.owner.login}/${data.repository.name}, no target spaces`);
|
||||
// We don't want to create any discussions if we have no target spaces.
|
||||
return;
|
||||
}
|
||||
let [discussionConnection] = this.getConnectionsForGithubDiscussion(data.repository.owner.login, data.repository.name, data.discussion.id);
|
||||
let [discussionConnection] = connManager.getConnectionsForGithubDiscussion(data.repository.owner.login, data.repository.name, data.discussion.id);
|
||||
if (!discussionConnection) {
|
||||
try {
|
||||
// If we don't have an existing connection for this discussion (likely), then create one.
|
||||
@ -597,7 +419,7 @@ export class GithubBridge {
|
||||
this.commentProcessor,
|
||||
this.messageClient,
|
||||
);
|
||||
this.connections.push(discussionConnection);
|
||||
connManager.push(discussionConnection);
|
||||
} catch (ex) {
|
||||
log.error(ex);
|
||||
throw Error('Failed to create discussion room');
|
||||
@ -616,7 +438,7 @@ export class GithubBridge {
|
||||
this.queue.on<JiraIssueEvent>("jira.issue_created", async ({data}) => {
|
||||
log.info(`JIRA issue created for project ${data.issue.fields.project.id}, issue id ${data.issue.id}`);
|
||||
const projectId = data.issue.fields.project.id;
|
||||
const connections = this.getConnectionsForJiraProject(projectId);
|
||||
const connections = connManager.getConnectionsForJiraProject(projectId, "jira.issue_created");
|
||||
|
||||
connections.forEach(async (c) => {
|
||||
try {
|
||||
@ -629,7 +451,7 @@ export class GithubBridge {
|
||||
|
||||
this.queue.on<GenericWebhookEvent>("generic-webhook.event", async ({data}) => {
|
||||
log.info(`Incoming generic hook ${data.hookId}`);
|
||||
const connections = this.getConnectionsForGenericWebhook(data.hookId);
|
||||
const connections = connManager.getConnectionsForGenericWebhook(data.hookId);
|
||||
|
||||
connections.forEach(async (c) => {
|
||||
try {
|
||||
@ -678,14 +500,14 @@ export class GithubBridge {
|
||||
log.debug("Fetching state for " + roomId);
|
||||
let connections: IConnection[];
|
||||
try {
|
||||
connections = await this.createConnectionsForRoomId(roomId);
|
||||
connections = await connManager.createConnectionsForRoomId(roomId);
|
||||
} catch (ex) {
|
||||
log.error(`Unable to create connection for ${roomId}`, ex);
|
||||
continue;
|
||||
}
|
||||
if (connections.length) {
|
||||
log.info(`Room ${roomId} is connected to: ${connections.join(',')}`);
|
||||
this.connections.push(...connections);
|
||||
connManager.push(...connections);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -717,8 +539,8 @@ export class GithubBridge {
|
||||
}
|
||||
|
||||
// Handle spaces
|
||||
for (const discussion of this.connections.filter((c) => c instanceof GitHubDiscussionSpace) as GitHubDiscussionSpace[]) {
|
||||
const user = this.getConnectionForGithubUser(discussion.owner);
|
||||
for (const discussion of connManager.getAllConnectionsOfType(GitHubDiscussionSpace)) {
|
||||
const user = connManager.getConnectionForGithubUser(discussion.owner);
|
||||
if (user) {
|
||||
await user.ensureDiscussionInSpace(discussion);
|
||||
}
|
||||
@ -753,6 +575,10 @@ export class GithubBridge {
|
||||
}
|
||||
|
||||
private async onRoomMessage(roomId: string, event: MatrixEvent<MatrixMessageContent>) {
|
||||
if (!this.connectionManager) {
|
||||
// Not ready yet.
|
||||
return;
|
||||
}
|
||||
if (this.as.isNamespacedUser(event.sender)) {
|
||||
/* We ignore messages from our users */
|
||||
return;
|
||||
@ -762,7 +588,6 @@ export class GithubBridge {
|
||||
return;
|
||||
}
|
||||
log.info(`Got message roomId=${roomId} type=${event.type} from=${event.sender}`);
|
||||
console.log(event);
|
||||
log.debug("Content:", JSON.stringify(event));
|
||||
const adminRoom = this.adminRooms.get(roomId);
|
||||
|
||||
@ -784,7 +609,7 @@ export class GithubBridge {
|
||||
const issueNumber = ev.content["uk.half-shot.matrix-github.issue"]?.number;
|
||||
if (splitParts && issueNumber) {
|
||||
log.info(`Handling reply for ${splitParts}${issueNumber}`);
|
||||
const connections = this.getConnectionsForGithubIssue(splitParts[0], splitParts[1], issueNumber);
|
||||
const connections = this.connectionManager.getConnectionsForGithubIssue(splitParts[0], splitParts[1], issueNumber);
|
||||
await Promise.all(connections.map(async c => {
|
||||
if (c instanceof GitHubIssueConnection) {
|
||||
return c.onMatrixIssueComment(processedReply);
|
||||
@ -806,7 +631,7 @@ export class GithubBridge {
|
||||
}
|
||||
}
|
||||
|
||||
for (const connection of this.connections.filter((c) => c.roomId === roomId)) {
|
||||
for (const connection of this.connectionManager.getAllConnectionsForRoom(roomId)) {
|
||||
try {
|
||||
if (connection.onMessageEvent) {
|
||||
await connection.onMessageEvent(event);
|
||||
@ -822,44 +647,59 @@ export class GithubBridge {
|
||||
// Only act on bot joins
|
||||
return;
|
||||
}
|
||||
|
||||
const isRoomConnected = !!this.connections.find(c => c.roomId === roomId);
|
||||
if (!this.connectionManager) {
|
||||
// Not ready yet.
|
||||
return;
|
||||
}
|
||||
|
||||
// Only fetch rooms we have no connections in yet.
|
||||
if (!isRoomConnected) {
|
||||
const connections = await this.createConnectionsForRoomId(roomId);
|
||||
this.connections.push(...connections);
|
||||
if (!this.connectionManager.isRoomConnected(roomId)) {
|
||||
const connections = await this.connectionManager.createConnectionsForRoomId(roomId);
|
||||
this.connectionManager.push(...connections);
|
||||
}
|
||||
}
|
||||
|
||||
private async onRoomEvent(roomId: string, event: MatrixEvent<unknown>) {
|
||||
if (!this.connectionManager) {
|
||||
// Not ready yet.
|
||||
return;
|
||||
}
|
||||
if (event.state_key) {
|
||||
// A state update, hurrah!
|
||||
const existingConnection = this.connections.find((c) => c.roomId === roomId && c.isInterestedInStateEvent(event.type, event.state_key || ""));
|
||||
if (existingConnection?.onStateUpdate) {
|
||||
existingConnection.onStateUpdate(event);
|
||||
} else if (!existingConnection) {
|
||||
const existingConnections = this.connectionManager.getInterestedForRoomState(roomId, event.type, event.state_key);
|
||||
for (const connection of existingConnections) {
|
||||
try {
|
||||
if (connection?.onStateUpdate) {
|
||||
connection.onStateUpdate(event);
|
||||
}
|
||||
} catch (ex) {
|
||||
log.warn(`Connection ${connection.toString()} failed to handle onStateUpdate:`, ex);
|
||||
}
|
||||
}
|
||||
if (!existingConnections.length) {
|
||||
// Is anyone interested in this state?
|
||||
const connection = await this.createConnectionForState(roomId, new StateEvent(event));
|
||||
const connection = await this.connectionManager.createConnectionForState(roomId, new StateEvent(event));
|
||||
if (connection) {
|
||||
log.info(`New connected added to ${roomId}: ${connection.toString()}`);
|
||||
this.connections.push(connection);
|
||||
this.connectionManager.push(connection);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// We still want to react to our own state events.
|
||||
if (event.sender === this.as.botUserId) {
|
||||
// It's us
|
||||
return;
|
||||
}
|
||||
|
||||
for (const connection of this.connections.filter((c) => c.roomId === roomId)) {
|
||||
for (const connection of this.connectionManager.getAllConnectionsForRoom(roomId)) {
|
||||
try {
|
||||
if (connection.onEvent) {
|
||||
await connection.onEvent(event);
|
||||
}
|
||||
} catch (ex) {
|
||||
log.warn(`Connection ${connection.toString()} failed to handle event:`, ex);
|
||||
log.warn(`Connection ${connection.toString()} failed to handle onEvent:`, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -922,7 +762,6 @@ export class GithubBridge {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
res = GitHubUserSpace.QueryRoomRegex.exec(roomAlias);
|
||||
if (res) {
|
||||
if (!this.github) {
|
||||
@ -1019,7 +858,8 @@ export class GithubBridge {
|
||||
adminRoom.on("settings.changed", this.onAdminRoomSettingsChanged.bind(this));
|
||||
adminRoom.on("open.project", async (project: ProjectsGetResponseData) => {
|
||||
const connection = await GitHubProjectConnection.onOpenProject(project, this.as, adminRoom.userId);
|
||||
this.connections.push(connection);
|
||||
// TODO: Surely we only do this if we don't have one already?
|
||||
this.connectionManager?.push(connection);
|
||||
});
|
||||
// adminRoom.on("open.discussion", async (owner: string, repo: string, discussions: Discussion) => {
|
||||
// const connection = await GitHubDiscussionConnection.createDiscussionRoom(
|
||||
@ -1028,7 +868,7 @@ export class GithubBridge {
|
||||
// this.connections.push(connection);
|
||||
// });
|
||||
adminRoom.on("open.gitlab-issue", async (issueInfo: GetIssueOpts, res: GetIssueResponse, instanceName: string, instance: GitLabInstance) => {
|
||||
const [ connection ] = this.getConnectionsForGitLabIssue(instance, issueInfo.projects, issueInfo.issue);
|
||||
const [ connection ] = this.connectionManager?.getConnectionsForGitLabIssue(instance, issueInfo.projects, issueInfo.issue) || [];
|
||||
if (connection) {
|
||||
return this.as.botClient.inviteUser(adminRoom.userId, connection.roomId);
|
||||
}
|
||||
@ -1042,7 +882,7 @@ export class GithubBridge {
|
||||
this.commentProcessor,
|
||||
this.messageClient
|
||||
);
|
||||
this.connections.push(newConnection);
|
||||
this.connectionManager?.push(newConnection);
|
||||
return this.as.botClient.inviteUser(adminRoom.userId, newConnection.roomId);
|
||||
});
|
||||
this.adminRooms.set(roomId, adminRoom);
|
||||
|
@ -1,6 +1,3 @@
|
||||
import { JiraIssue } from "./Types";
|
||||
import { jira } from "../libRs";
|
||||
|
||||
export function generateWebLinkFromIssue(issue: JiraIssue) {
|
||||
const { origin } = new URL(issue.self);
|
||||
return `${origin}/browse/${issue.key}`
|
||||
}
|
||||
export const generateJiraWebLinkFromIssue = jira.utils.generate_jira_web_link_from_issue;
|
11
src/Jira/mod.rs
Normal file
11
src/Jira/mod.rs
Normal file
@ -0,0 +1,11 @@
|
||||
use napi::{Env, Error as NapiError, JsObject};
|
||||
pub mod utils;
|
||||
pub mod types;
|
||||
|
||||
pub fn get_module(env: Env) -> Result<JsObject, NapiError> {
|
||||
let mut root_module = env.create_object()?;
|
||||
let mut utils_module = env.create_object()?;
|
||||
utils_module.create_named_method("generate_jira_web_link_from_issue", utils::js_generate_jira_web_link_from_issue)?;
|
||||
root_module.set_named_property("utils", utils_module)?;
|
||||
Ok(root_module)
|
||||
}
|
29
src/Jira/types.rs
Normal file
29
src/Jira/types.rs
Normal file
@ -0,0 +1,29 @@
|
||||
#[derive(Serialize, Debug, Deserialize)]
|
||||
pub struct JiraProject {
|
||||
#[serde(rename = "self")]
|
||||
pub _self: String,
|
||||
pub id: String,
|
||||
pub key: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Deserialize)]
|
||||
|
||||
pub struct JiraIssue {
|
||||
#[serde(rename = "self")]
|
||||
pub _self: String,
|
||||
pub id: String,
|
||||
pub key: String,
|
||||
pub fields: JiraIssueFields,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Deserialize)]
|
||||
pub struct JiraIssueFields {
|
||||
pub project: JiraProject
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Deserialize)]
|
||||
pub struct JiraIssueLight {
|
||||
#[serde(rename = "self")]
|
||||
pub _self: String,
|
||||
pub key: String,
|
||||
}
|
22
src/Jira/utils.rs
Normal file
22
src/Jira/utils.rs
Normal file
@ -0,0 +1,22 @@
|
||||
use napi::{CallContext, Error as NapiError, JsString, JsUnknown, Status};
|
||||
use url::{Url};
|
||||
use super::types::{JiraIssueLight};
|
||||
|
||||
/// Generate a URL for a given Jira Issue object.
|
||||
#[js_function(1)]
|
||||
pub fn js_generate_jira_web_link_from_issue(ctx: CallContext) -> Result<JsString, NapiError> {
|
||||
let jira_issue: JiraIssueLight = ctx.env.from_js_value(ctx.get::<JsUnknown>(0)?)?;
|
||||
match generate_jira_web_link_from_issue(&jira_issue) {
|
||||
Ok(url) => ctx.env.create_string_from_std(url),
|
||||
Err(err) => Err(NapiError::new(Status::Unknown, err.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a URL for a given Jira Issue object.
|
||||
pub fn generate_jira_web_link_from_issue(jira_issue: &JiraIssueLight) -> Result<String, NapiError> {
|
||||
let result = Url::parse(&jira_issue._self);
|
||||
match result {
|
||||
Ok(url) => Ok(format!("{}://{}/browse/{}", url.scheme(), url.host_str().unwrap(), jira_issue.key)),
|
||||
Err(err) => Err(NapiError::new(Status::Unknown, err.to_string())),
|
||||
}
|
||||
}
|
16
src/lib.rs
Normal file
16
src/lib.rs
Normal file
@ -0,0 +1,16 @@
|
||||
use napi::{Env, Error as NapiError, JsObject};
|
||||
mod Jira;
|
||||
mod FormatUtil;
|
||||
|
||||
#[macro_use]
|
||||
extern crate napi_derive;
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[module_exports]
|
||||
fn init(mut exports: JsObject, env: Env) -> Result<(), NapiError> {
|
||||
exports.set_named_property("jira", Jira::get_module(env)?)?;
|
||||
exports.set_named_property("format_util", FormatUtil::get_module(env)?)?;
|
||||
Ok(())
|
||||
}
|
19
src/libRs.ts
Normal file
19
src/libRs.ts
Normal file
@ -0,0 +1,19 @@
|
||||
/* eslint-disable camelcase */
|
||||
import { JiraIssue } from "./Jira/Types";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const rootModule = require('../lib/matrix-github-rs.node');
|
||||
|
||||
interface FormatUtil {
|
||||
get_partial_body_for_jira_issue: (issue: JiraIssue) => Record<string, unknown>
|
||||
}
|
||||
|
||||
interface JiraModule {
|
||||
utils: {
|
||||
generate_jira_web_link_from_issue: (issue: {self: string, key: string}) => string;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const format_util = rootModule.format_util as FormatUtil;
|
||||
export const jira = rootModule.jira as JiraModule;
|
@ -1,5 +1,6 @@
|
||||
import { FormatUtil } from "../src/FormatUtil";
|
||||
import { expect } from "chai";
|
||||
import { JiraIssue, JiraProject } from "../src/Jira/Types";
|
||||
|
||||
const SIMPLE_ISSUE = {
|
||||
id: 123,
|
||||
@ -19,6 +20,27 @@ const SIMPLE_REPO = {
|
||||
html_url: "https://github.com/evilcorp/lab/issues/123",
|
||||
};
|
||||
|
||||
const SIMPLE_JIRA_ISSUE = {
|
||||
id: "test-issue",
|
||||
self: "http://example-api.url.com/issue-url",
|
||||
key: "TEST-001",
|
||||
fields: {
|
||||
summary: "summary",
|
||||
issuetype: "foo",
|
||||
project: {
|
||||
self: "http://example-api.url.com/project-url",
|
||||
id: "test-project",
|
||||
key: "TEST",
|
||||
name: "Test Project",
|
||||
projectTypeKey: "project-type-key",
|
||||
simplified: false,
|
||||
avatarUrls: {}
|
||||
} as JiraProject,
|
||||
assignee: null,
|
||||
priority: "1",
|
||||
status: "open",
|
||||
},
|
||||
} as JiraIssue;
|
||||
|
||||
describe("FormatUtilTest", () => {
|
||||
it("correctly formats a repo room name", () => {
|
||||
@ -36,4 +58,19 @@ describe("FormatUtilTest", () => {
|
||||
"Status: open | https://github.com/evilcorp/lab/issues/123",
|
||||
);
|
||||
});
|
||||
it("should correctly format a JIRA issue", () => {
|
||||
expect(FormatUtil.getPartialBodyForJiraIssue(SIMPLE_JIRA_ISSUE)).to.deep.equal({
|
||||
"external_url": "http://example-api.url.com/browse/TEST-001",
|
||||
"uk.half-shot.matrix-github.jira.issue": {
|
||||
"api_url": "http://example-api.url.com/issue-url",
|
||||
"id": "test-issue",
|
||||
"key": "TEST-001",
|
||||
},
|
||||
"uk.half-shot.matrix-github.jira.project": {
|
||||
"api_url": "http://example-api.url.com/project-url",
|
||||
"id": "test-project",
|
||||
"key": "TEST",
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
13
tests/jira/Utils.ts
Normal file
13
tests/jira/Utils.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { expect } from "chai";
|
||||
import { generateJiraWebLinkFromIssue } from "../../src/Jira/Utils";
|
||||
|
||||
describe("Jira", () => {
|
||||
describe("Utils", () => {
|
||||
it("processes a jira issue into a URL", () => {
|
||||
expect(generateJiraWebLinkFromIssue({
|
||||
self: "https://my-test-jira/",
|
||||
key: "TEST-111",
|
||||
})).to.equal("https://my-test-jira/browse/TEST-111");
|
||||
});
|
||||
});
|
||||
});
|
229
yarn.lock
229
yarn.lock
@ -266,6 +266,25 @@
|
||||
resolved "https://registry.yarnpkg.com/@fontsource/open-sans/-/open-sans-4.2.2.tgz#59046f772136a44c5999e0189d33c6a26676630c"
|
||||
integrity sha512-NbsL1a9asJO6N/5kRxYPCy0kNhKMi9T75kl4QfIGtmpd/5IfB+UIAUxd9AICmCLaH4Osc2TImeTJj94xc9MNKg==
|
||||
|
||||
"@napi-rs/cli@^1.3.5":
|
||||
version "1.3.5"
|
||||
resolved "https://registry.yarnpkg.com/@napi-rs/cli/-/cli-1.3.5.tgz#89e4d97127edc4ed10a06637a43d27a1ed3c288d"
|
||||
integrity sha512-Z0KZIciemioYODTyO908v2AtL8Zg4sohQDD+dyHeHmOiOfaez/y/xQ8XnpOHc2W5fRidKUW+MVWyTtpLTbKsqw==
|
||||
dependencies:
|
||||
inquirer "^8.1.3"
|
||||
|
||||
"@napi-rs/triples@^1.0.3":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@napi-rs/triples/-/triples-1.0.3.tgz#76d6d0c3f4d16013c61e45dfca5ff1e6c31ae53c"
|
||||
integrity sha512-jDJTpta+P4p1NZTFVLHJ/TLFVYVcOqv6l8xwOeBKNPMgY/zDYH/YH7SJbvrr/h1RcS9GzbPcLKGzpuK9cV56UA==
|
||||
|
||||
"@node-rs/helper@^1.2.1":
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@node-rs/helper/-/helper-1.2.1.tgz#e079b05f21ff4329d82c4e1f71c0290e4ecdc70c"
|
||||
integrity sha512-R5wEmm8nbuQU0YGGmYVjEc0OHtYsuXdpRG+Ut/3wZ9XAvQWyThN08bTh2cBJgoZxHQUPtvRfeQuxcAgLuiBISg==
|
||||
dependencies:
|
||||
"@napi-rs/triples" "^1.0.3"
|
||||
|
||||
"@nodelib/fs.scandir@2.1.4":
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz#d4b3549a5db5de2683e0c1071ab4f140904bbf69"
|
||||
@ -856,6 +875,13 @@ ansi-colors@4.1.1, ansi-colors@^4.1.1:
|
||||
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
|
||||
integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
|
||||
|
||||
ansi-escapes@^4.2.1:
|
||||
version "4.3.2"
|
||||
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e"
|
||||
integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==
|
||||
dependencies:
|
||||
type-fest "^0.21.3"
|
||||
|
||||
ansi-regex@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
|
||||
@ -999,6 +1025,11 @@ balanced-match@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
||||
|
||||
base64-js@^1.3.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
||||
|
||||
basic-auth@~2.0.0, basic-auth@~2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a"
|
||||
@ -1035,6 +1066,15 @@ bitsyntax@~0.0.4:
|
||||
dependencies:
|
||||
buffer-more-ints "0.0.2"
|
||||
|
||||
bl@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
|
||||
integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
|
||||
dependencies:
|
||||
buffer "^5.5.0"
|
||||
inherits "^2.0.4"
|
||||
readable-stream "^3.4.0"
|
||||
|
||||
bluebird@^3.4.6, bluebird@^3.5.0:
|
||||
version "3.7.2"
|
||||
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
|
||||
@ -1130,6 +1170,14 @@ buffer-more-ints@0.0.2:
|
||||
resolved "https://registry.yarnpkg.com/buffer-more-ints/-/buffer-more-ints-0.0.2.tgz#26b3885d10fa13db7fc01aae3aab870199e0124c"
|
||||
integrity sha1-JrOIXRD6E9t/wBquOquHAZngEkw=
|
||||
|
||||
buffer@^5.5.0:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
|
||||
integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
|
||||
dependencies:
|
||||
base64-js "^1.3.1"
|
||||
ieee754 "^1.1.13"
|
||||
|
||||
bytes@3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
|
||||
@ -1206,6 +1254,19 @@ chalk@^4.0.0, chalk@^4.1.0:
|
||||
ansi-styles "^4.1.0"
|
||||
supports-color "^7.1.0"
|
||||
|
||||
chalk@^4.1.1:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
|
||||
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
|
||||
dependencies:
|
||||
ansi-styles "^4.1.0"
|
||||
supports-color "^7.1.0"
|
||||
|
||||
chardet@^0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
|
||||
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
|
||||
|
||||
check-error@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
|
||||
@ -1231,11 +1292,23 @@ clean-stack@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
|
||||
integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
|
||||
|
||||
cli-cursor@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
|
||||
integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==
|
||||
dependencies:
|
||||
restore-cursor "^3.1.0"
|
||||
|
||||
cli-spinners@^2.5.0:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.0.tgz#36c7dc98fb6a9a76bd6238ec3f77e2425627e939"
|
||||
integrity sha512-t+4/y50K/+4xcCRosKkA7W4gTr1MySvLV0q+PxmG7FJ5g+66ChKurYjxBCjHggHH3HA5Hh9cy+lcUGWDqVH+4Q==
|
||||
|
||||
cli-width@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
|
||||
integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
|
||||
|
||||
cliui@^7.0.2:
|
||||
version "7.0.4"
|
||||
resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
|
||||
@ -1245,6 +1318,11 @@ cliui@^7.0.2:
|
||||
strip-ansi "^6.0.0"
|
||||
wrap-ansi "^7.0.0"
|
||||
|
||||
clone@^1.0.2:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
|
||||
integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
|
||||
|
||||
cluster-key-slot@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d"
|
||||
@ -1505,6 +1583,13 @@ default-browser-id@^2.0.0:
|
||||
pify "^2.3.0"
|
||||
untildify "^2.0.0"
|
||||
|
||||
defaults@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d"
|
||||
integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=
|
||||
dependencies:
|
||||
clone "^1.0.2"
|
||||
|
||||
define-properties@^1.1.2, define-properties@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
|
||||
@ -1970,6 +2055,15 @@ extend@~3.0.2:
|
||||
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
||||
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
|
||||
|
||||
external-editor@^3.0.3:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
|
||||
integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==
|
||||
dependencies:
|
||||
chardet "^0.7.0"
|
||||
iconv-lite "^0.4.24"
|
||||
tmp "^0.0.33"
|
||||
|
||||
extsprintf@1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
|
||||
@ -2034,6 +2128,13 @@ fecha@^4.2.0:
|
||||
resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.0.tgz#3ffb6395453e3f3efff850404f0a59b6747f5f41"
|
||||
integrity sha512-aN3pcx/DSmtyoovUudctc8+6Hl4T+hI9GBBHLjA76jdZl7+b1sgh5g4k+u/GL3dTy1/pnYzKp69FpJ0OicE3Wg==
|
||||
|
||||
figures@^3.0.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
|
||||
integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==
|
||||
dependencies:
|
||||
escape-string-regexp "^1.0.5"
|
||||
|
||||
file-entry-cache@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
|
||||
@ -2440,13 +2541,18 @@ iconv-lite@0.4.23:
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3"
|
||||
|
||||
iconv-lite@0.4.24:
|
||||
iconv-lite@0.4.24, iconv-lite@^0.4.24:
|
||||
version "0.4.24"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3"
|
||||
|
||||
ieee754@^1.1.13:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
|
||||
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
|
||||
|
||||
ignore@^4.0.6:
|
||||
version "4.0.6"
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
|
||||
@ -2483,7 +2589,7 @@ inflight@^1.0.4:
|
||||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3:
|
||||
inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
@ -2493,6 +2599,26 @@ inherits@2.0.3:
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
||||
|
||||
inquirer@^8.1.3:
|
||||
version "8.2.0"
|
||||
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.0.tgz#f44f008dd344bbfc4b30031f45d984e034a3ac3a"
|
||||
integrity sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ==
|
||||
dependencies:
|
||||
ansi-escapes "^4.2.1"
|
||||
chalk "^4.1.1"
|
||||
cli-cursor "^3.1.0"
|
||||
cli-width "^3.0.0"
|
||||
external-editor "^3.0.3"
|
||||
figures "^3.0.0"
|
||||
lodash "^4.17.21"
|
||||
mute-stream "0.0.8"
|
||||
ora "^5.4.1"
|
||||
run-async "^2.4.0"
|
||||
rxjs "^7.2.0"
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
through "^2.3.6"
|
||||
|
||||
ioredis@^4.26.0:
|
||||
version "4.26.0"
|
||||
resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.26.0.tgz#dbbfb5e5da085fc2b1de8174db50fa42f9fed66a"
|
||||
@ -2582,6 +2708,11 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1:
|
||||
dependencies:
|
||||
is-extglob "^2.1.1"
|
||||
|
||||
is-interactive@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e"
|
||||
integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==
|
||||
|
||||
is-negative-zero@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24"
|
||||
@ -2652,6 +2783,11 @@ is-typedarray@~1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
|
||||
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
|
||||
|
||||
is-unicode-supported@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
|
||||
integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
|
||||
|
||||
is-wsl@^2.1.1:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271"
|
||||
@ -2919,6 +3055,14 @@ log-symbols@4.0.0:
|
||||
dependencies:
|
||||
chalk "^4.0.0"
|
||||
|
||||
log-symbols@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503"
|
||||
integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==
|
||||
dependencies:
|
||||
chalk "^4.1.0"
|
||||
is-unicode-supported "^0.1.0"
|
||||
|
||||
logform@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/logform/-/logform-2.2.0.tgz#40f036d19161fc76b68ab50fdc7fe495544492f2"
|
||||
@ -3174,6 +3318,11 @@ ms@2.1.3, ms@^2.1.1:
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
|
||||
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
||||
|
||||
mute-stream@0.0.8:
|
||||
version "0.0.8"
|
||||
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
|
||||
integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
|
||||
|
||||
nanoid@3.1.20:
|
||||
version "3.1.20"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788"
|
||||
@ -3305,7 +3454,7 @@ one-time@^1.0.0:
|
||||
dependencies:
|
||||
fn.name "1.x.x"
|
||||
|
||||
onetime@^5.1.2:
|
||||
onetime@^5.1.0, onetime@^5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
|
||||
integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
|
||||
@ -3332,11 +3481,31 @@ optionator@^0.9.1:
|
||||
type-check "^0.4.0"
|
||||
word-wrap "^1.2.3"
|
||||
|
||||
ora@^5.4.1:
|
||||
version "5.4.1"
|
||||
resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18"
|
||||
integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==
|
||||
dependencies:
|
||||
bl "^4.1.0"
|
||||
chalk "^4.1.0"
|
||||
cli-cursor "^3.1.0"
|
||||
cli-spinners "^2.5.0"
|
||||
is-interactive "^1.0.0"
|
||||
is-unicode-supported "^0.1.0"
|
||||
log-symbols "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
wcwidth "^1.0.1"
|
||||
|
||||
os-homedir@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
|
||||
integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
|
||||
|
||||
os-tmpdir@~1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
|
||||
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
|
||||
|
||||
p-limit@^3.0.2:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
|
||||
@ -3681,6 +3850,14 @@ resolve@^1.20.0:
|
||||
is-core-module "^2.2.0"
|
||||
path-parse "^1.0.6"
|
||||
|
||||
restore-cursor@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
|
||||
integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==
|
||||
dependencies:
|
||||
onetime "^5.1.0"
|
||||
signal-exit "^3.0.2"
|
||||
|
||||
retry@0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
|
||||
@ -3705,6 +3882,11 @@ rollup@^2.34.0:
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.1"
|
||||
|
||||
run-async@^2.4.0:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
|
||||
integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==
|
||||
|
||||
run-parallel@^1.1.9:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
|
||||
@ -3712,6 +3894,13 @@ run-parallel@^1.1.9:
|
||||
dependencies:
|
||||
queue-microtask "^1.2.2"
|
||||
|
||||
rxjs@^7.2.0:
|
||||
version "7.4.0"
|
||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.4.0.tgz#a12a44d7eebf016f5ff2441b87f28c9a51cebc68"
|
||||
integrity sha512-7SQDi7xeTMCJpqViXh8gL/lebcwlp3d831F05+9B44A4B0WfsEwUQHR64gsH1kvJ+Ep/J9K2+n1hVl1CsGN23w==
|
||||
dependencies:
|
||||
tslib "~2.1.0"
|
||||
|
||||
safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||
@ -3849,6 +4038,11 @@ shebang-regex@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
|
||||
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
|
||||
|
||||
signal-exit@^3.0.2:
|
||||
version "3.0.6"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af"
|
||||
integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==
|
||||
|
||||
signal-exit@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
|
||||
@ -4144,11 +4338,23 @@ text-table@^0.2.0:
|
||||
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
|
||||
integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
|
||||
|
||||
through@^2.3.6:
|
||||
version "2.3.8"
|
||||
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
|
||||
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
|
||||
|
||||
timer2@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/timer2/-/timer2-1.0.0.tgz#7a2441569c6564cb891f605788eef0377d89f5de"
|
||||
integrity sha512-UOZql+P2ET0da+B7V3/RImN3IhC5ghb+9cpecfUhmYGIm0z73dDr3A781nBLnFYmRzeT1AmoT4w9Lgr8n7n7xg==
|
||||
|
||||
tmp@^0.0.33:
|
||||
version "0.0.33"
|
||||
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
|
||||
integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
|
||||
dependencies:
|
||||
os-tmpdir "~1.0.2"
|
||||
|
||||
to-fast-properties@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
|
||||
@ -4196,6 +4402,11 @@ tslib@^1.8.1:
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||
|
||||
tslib@~2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
|
||||
integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
|
||||
|
||||
tsscmp@^1.0.5:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb"
|
||||
@ -4237,6 +4448,11 @@ type-fest@^0.20.2:
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
|
||||
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
|
||||
|
||||
type-fest@^0.21.3:
|
||||
version "0.21.3"
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
|
||||
integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
|
||||
|
||||
type-fest@^0.8.1:
|
||||
version "0.8.1"
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
|
||||
@ -4379,6 +4595,13 @@ verror@1.10.0:
|
||||
core-util-is "1.0.2"
|
||||
extsprintf "^1.2.0"
|
||||
|
||||
wcwidth@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"
|
||||
integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=
|
||||
dependencies:
|
||||
defaults "^1.0.3"
|
||||
|
||||
which-boxed-primitive@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"
|
||||
|
Loading…
x
Reference in New Issue
Block a user