baseline working
parent
c80700ac67
commit
eb38d1402e
|
|
@ -1 +1,2 @@
|
|||
node_modules
|
||||
.env
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
pipeline:
|
||||
build:
|
||||
image: node
|
||||
commands:
|
||||
- yarn
|
||||
- yarn dev
|
||||
secrets: [ ]
|
||||
11
Dockerfile
11
Dockerfile
|
|
@ -7,12 +7,13 @@ RUN npm --version
|
|||
RUN npm install -g npm yarn
|
||||
|
||||
WORKDIR /app
|
||||
COPY . /app
|
||||
COPY ./dist /app
|
||||
COPY ./package.json /app/package.json
|
||||
COPY ./node_modules /app/node_modules
|
||||
|
||||
RUN yarn
|
||||
RUN yarn tsc
|
||||
RUN find /app
|
||||
|
||||
EXPOSE 52310
|
||||
EXPOSE 6969
|
||||
|
||||
CMD node /app/dist/main.js
|
||||
CMD node /app/main.js
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
import { buildDockerImage, createContainer } from "../apis/docker.js";
|
||||
import { createCertificate, createProxyHost, deleteProxyHostByDomain, getCertificateByDomains, hasCerficateByDomains, isDomainRegistered } from "../apis/npm.js";
|
||||
import { BASE_DOMAIN, INTERNAL_ADDRESS } from "../config.js";
|
||||
export default async function deploy(options) {
|
||||
const { cloneUrl, branch } = options;
|
||||
const [, user, name] = /http[s]{0,1}:\/\/.*\/(.*)\/(.*)\.git/.exec(cloneUrl);
|
||||
console.log(`deploying ${user}/${name}`);
|
||||
const imageName = await buildDockerImage({
|
||||
user,
|
||||
name,
|
||||
cloneUrl,
|
||||
branch
|
||||
});
|
||||
const containerName = `deploy-${user}-${name}-${branch}`;
|
||||
const { port } = await createContainer(imageName, containerName);
|
||||
const domain = `${branch}.${name}.${user}.${BASE_DOMAIN}`;
|
||||
await ensureDomainConfig(domain, port);
|
||||
console.log(`${user}/${name} available at https://${domain}/`);
|
||||
}
|
||||
async function ensureDomainConfig(domain, port) {
|
||||
// === certificate info
|
||||
let certId = null;
|
||||
if (await hasCerficateByDomains([domain])) {
|
||||
certId = (await getCertificateByDomains([domain])).id;
|
||||
console.log('certificate for', domain, 'already exists');
|
||||
}
|
||||
else {
|
||||
const newCert = await createCertificate([domain]);
|
||||
certId = newCert.id;
|
||||
}
|
||||
if (await isDomainRegistered(domain)) {
|
||||
await deleteProxyHostByDomain(domain);
|
||||
}
|
||||
await createProxyHost([domain], port, INTERNAL_ADDRESS, {
|
||||
ssl_forced: true,
|
||||
block_exploits: true,
|
||||
allow_websocket_upgrade: true,
|
||||
http2_support: true,
|
||||
certificate_id: certId
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,225 @@
|
|||
import Docker from "dockerode";
|
||||
import { writeFileSync } from "fs";
|
||||
import * as process from "process";
|
||||
import rimraf from "rimraf";
|
||||
import * as tmp from 'tmp';
|
||||
import getPort, { portNumbers } from 'get-port';
|
||||
import { INTERNAL_IP } from "../config.js";
|
||||
const docker = new Docker();
|
||||
export async function createContainer(imageName, containerName) {
|
||||
const port = await getPort({ host: INTERNAL_IP, port: portNumbers(52300, 52399) });
|
||||
if (await isContainerNameInUse(containerName)) {
|
||||
await stopAndRemoveContainerByName(containerName);
|
||||
}
|
||||
const containerOptions = {
|
||||
Image: imageName,
|
||||
name: containerName,
|
||||
WorkingDir: '/app',
|
||||
HostConfig: {
|
||||
AutoRemove: false,
|
||||
RestartPolicy: {
|
||||
Name: "always"
|
||||
},
|
||||
PortBindings: {
|
||||
'3000/tcp': [{ HostPort: '' + port }]
|
||||
}
|
||||
},
|
||||
};
|
||||
try {
|
||||
const container = await docker.createContainer(containerOptions);
|
||||
await container.start();
|
||||
console.log("Started", containerName, "with port", port, '> 3000');
|
||||
await checkContainerStatus(container.id);
|
||||
return {
|
||||
id: container.id,
|
||||
port
|
||||
};
|
||||
}
|
||||
catch (err) {
|
||||
console.error("Error creating container:", err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
export async function listContainers() {
|
||||
return (await docker.listContainers())
|
||||
.map(v => v.Names[0])
|
||||
.filter((full) => {
|
||||
return full.startsWith('deploy-');
|
||||
});
|
||||
}
|
||||
export async function getContainerInfo(containerId) {
|
||||
const docker = new Docker();
|
||||
const container = docker.getContainer(containerId);
|
||||
const containerInfo = await container.inspect();
|
||||
return containerInfo;
|
||||
}
|
||||
export async function checkImageExists(imageName) {
|
||||
const images = await docker.listImages();
|
||||
const imageExists = images.some(image => {
|
||||
if (image.RepoTags) {
|
||||
return image.RepoTags.includes(imageName);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return imageExists;
|
||||
}
|
||||
export async function pullImage(imageName) {
|
||||
const imageExists = await checkImageExists(imageName);
|
||||
if (!imageExists) {
|
||||
console.log(`Pulling image ${imageName}`);
|
||||
return new Promise((resolve, reject) => {
|
||||
docker.pull(imageName, (err, stream) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
docker.modem.followProgress(stream, (err, output) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
console.log(`Image ${imageName} has been pulled`);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
console.log(`Image ${imageName} already exists`);
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
export async function attachLogs(containerId) {
|
||||
const container = docker.getContainer(containerId);
|
||||
const logsStream = await container.logs({
|
||||
follow: true,
|
||||
stdout: true,
|
||||
stderr: true,
|
||||
});
|
||||
return logsStream;
|
||||
}
|
||||
export async function isContainerNameInUse(name) {
|
||||
const containers = await docker.listContainers({ all: true });
|
||||
return containers.some((container) => container.Names.includes(`/${name}`));
|
||||
}
|
||||
async function stopAndRemoveContainerByName(name) {
|
||||
const containers = await docker.listContainers({ all: true });
|
||||
const matchingContainers = containers.filter(container => container.Names.includes(`/${name}`));
|
||||
if (matchingContainers.length === 0) {
|
||||
throw new Error(`No container with name '${name}' was found`);
|
||||
}
|
||||
const stoppedContainer = docker.getContainer(matchingContainers[0].Id);
|
||||
try {
|
||||
await stoppedContainer.stop();
|
||||
}
|
||||
catch (error) {
|
||||
console.error(`Failed to stop container ${name}: ${error.message}`);
|
||||
}
|
||||
try {
|
||||
await stoppedContainer.remove();
|
||||
console.log(`Container ${name} removed`);
|
||||
}
|
||||
catch (error) {
|
||||
console.error(`Failed to remove container ${name}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
async function checkContainerStatus(containerId) {
|
||||
const container = docker.getContainer(containerId);
|
||||
const containerInfo = await container.inspect();
|
||||
const status = containerInfo.State.Status;
|
||||
console.log(`Container status: ${status}`);
|
||||
return status;
|
||||
}
|
||||
export async function runCommandInContainer(containerId, command) {
|
||||
console.log('$', ...command);
|
||||
const container = await docker.getContainer(containerId);
|
||||
const exec = await container.exec({
|
||||
Cmd: command,
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
});
|
||||
const stream = await exec.start({});
|
||||
await new Promise((resolve, reject) => {
|
||||
container.modem.demuxStream(stream, process.stdout, process.stderr);
|
||||
stream.on('end', resolve);
|
||||
stream.on('error', reject);
|
||||
});
|
||||
}
|
||||
export async function restartContainer(containerId) {
|
||||
const docker = new Docker();
|
||||
const container = await docker.getContainer(containerId);
|
||||
console.log(`Restarting container ${containerId}...`);
|
||||
await container.restart();
|
||||
await checkContainerStatus(containerId);
|
||||
}
|
||||
export async function stopContainer(id) {
|
||||
const docker = new Docker();
|
||||
const container = await docker.getContainer(id);
|
||||
await container.stop();
|
||||
await checkContainerStatus(id);
|
||||
}
|
||||
export async function startContainer(id) {
|
||||
const docker = new Docker();
|
||||
const container = await docker.getContainer(id);
|
||||
await container.start();
|
||||
await checkContainerStatus(id);
|
||||
}
|
||||
function createDockerfile(cloneUrl, branch) {
|
||||
return `
|
||||
FROM node:lts-alpine3.17
|
||||
|
||||
RUN apk add git
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN git clone "${cloneUrl}" /app --depth 1 -b ${branch}
|
||||
|
||||
RUN yarn && yarn build
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD yarn start`.trim();
|
||||
}
|
||||
export async function buildDockerImage(options) {
|
||||
const { name: context } = tmp.dirSync();
|
||||
const { user, name, branch, cloneUrl } = options;
|
||||
const imageName = `${user}/${name}:${branch}`;
|
||||
let id = null;
|
||||
try {
|
||||
writeFileSync(context + '/Dockerfile', createDockerfile(cloneUrl, branch));
|
||||
const stream = await docker.buildImage({
|
||||
src: ['Dockerfile'],
|
||||
context,
|
||||
}, {
|
||||
//@ts-ignore
|
||||
nocache: true,
|
||||
t: imageName
|
||||
});
|
||||
//@ts-ignore
|
||||
stream.on('data', d => {
|
||||
const data = JSON.parse(d);
|
||||
const text = data.stream ?? '';
|
||||
process.stdout.write(text);
|
||||
if (text.startsWith("Successfully built")) {
|
||||
const potentialId = text.split(" ")[2];
|
||||
id = potentialId;
|
||||
}
|
||||
});
|
||||
await new Promise((resolve) => {
|
||||
//@ts-ignore
|
||||
docker.modem.followProgress(stream, () => {
|
||||
resolve(void 0);
|
||||
});
|
||||
});
|
||||
if (id === null)
|
||||
throw new Error("Unable to generate image " + imageName);
|
||||
console.log("Built Image", imageName);
|
||||
}
|
||||
catch (e) {
|
||||
console.log('do we get here?');
|
||||
await rimraf(context);
|
||||
throw e;
|
||||
}
|
||||
await rimraf(context);
|
||||
return imageName;
|
||||
}
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
import * as console from "console";
|
||||
import { NPM_BASE_URL, NPM_EMAIL, NPM_PASSWORD } from "../config.js";
|
||||
let bearer = null;
|
||||
const headers = () => {
|
||||
const headers = {
|
||||
Authorization: "Bearer " + bearer,
|
||||
"Content-Type": "application/json"
|
||||
};
|
||||
return headers;
|
||||
};
|
||||
async function _post(url, body) {
|
||||
const res = await fetch(NPM_BASE_URL + url, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(body),
|
||||
headers: headers()
|
||||
});
|
||||
if (Math.floor(res.status / 100) !== 2) {
|
||||
throw new Error(JSON.stringify(await res.json(), null, 2));
|
||||
}
|
||||
return await res.json();
|
||||
}
|
||||
async function _get(url) {
|
||||
const res = await fetch(NPM_BASE_URL + url, {
|
||||
method: 'GET',
|
||||
headers: headers()
|
||||
});
|
||||
return await res.json();
|
||||
}
|
||||
async function _delete(url) {
|
||||
const res = await fetch(NPM_BASE_URL + url, {
|
||||
method: 'DELETE',
|
||||
headers: headers()
|
||||
});
|
||||
return await res.json();
|
||||
}
|
||||
function setToHappen(fn, date) {
|
||||
var now = new Date().getTime();
|
||||
var diff = date.getTime() - now;
|
||||
return setTimeout(fn, diff);
|
||||
}
|
||||
async function auth() {
|
||||
console.log("Attempting authentication against nginx");
|
||||
const { token, expires } = await _post('/tokens', {
|
||||
identity: NPM_EMAIL,
|
||||
secret: NPM_PASSWORD
|
||||
});
|
||||
setToHappen(auth, new Date(new Date(expires).getTime() - 60 * 1000));
|
||||
bearer = token;
|
||||
}
|
||||
export function getProxyHosts() {
|
||||
return _get('/nginx/proxy-hosts');
|
||||
}
|
||||
export const ready = auth();
|
||||
export async function isDomainRegistered(domain) {
|
||||
const hosts = await getProxyHosts();
|
||||
return hosts.map(h => h.domain_names).flat().some(d => d === domain);
|
||||
}
|
||||
export async function getProxyHostIdByDomain(domain) {
|
||||
const hosts = await getProxyHosts();
|
||||
for (const host of hosts) {
|
||||
for (const d of host.domain_names) {
|
||||
if (domain === d) {
|
||||
return host.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
export async function createProxyHost(domains, port, host, additionalConfig) {
|
||||
const registered = (await Promise.all(domains.map(d => isDomainRegistered(d)))).some(v => v);
|
||||
if (registered) {
|
||||
throw new Error("Domain is already registered as a proxy host");
|
||||
}
|
||||
const res = await _post('/nginx/proxy-hosts', {
|
||||
domain_names: domains,
|
||||
forward_scheme: "http",
|
||||
forward_host: host,
|
||||
forward_port: port,
|
||||
block_exploits: false,
|
||||
allow_websocket_upgrade: false,
|
||||
access_list_id: "0",
|
||||
certificate_id: 0,
|
||||
ssl_forced: false,
|
||||
http2_support: false,
|
||||
meta: {
|
||||
letsencrypt_agree: false,
|
||||
dns_challenge: false
|
||||
},
|
||||
advanced_config: "",
|
||||
locations: [],
|
||||
caching_enabled: false,
|
||||
hsts_enabled: false,
|
||||
hsts_subdomains: false,
|
||||
...additionalConfig
|
||||
});
|
||||
console.log('Created proxy host for', domains.join(', '));
|
||||
return res;
|
||||
}
|
||||
export async function createCertificate(domains) {
|
||||
const certReq = {
|
||||
domain_names: domains,
|
||||
meta: {
|
||||
dns_challenge: false,
|
||||
letsencrypt_agree: true,
|
||||
letsencrypt_email: NPM_EMAIL
|
||||
},
|
||||
provider: "letsencrypt"
|
||||
};
|
||||
const res = await _post('/nginx/certificates', certReq);
|
||||
return res;
|
||||
}
|
||||
export async function getCertificates() {
|
||||
return await _get('/nginx/certificates');
|
||||
}
|
||||
function compareSets(a, b) {
|
||||
if (a.length !== b.length)
|
||||
return false;
|
||||
const _a = a.sort();
|
||||
const _b = b.sort();
|
||||
for (let i = 0; i < _a.length; i++) {
|
||||
if (_a[i] !== _b[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
export async function deleteCertificate(id) {
|
||||
const success = await _delete(`/nginx/certificate/${id}`);
|
||||
if (success !== 'true') {
|
||||
throw Error('Failed to delete certificate ' + id);
|
||||
}
|
||||
}
|
||||
export async function getCertificateByDomains(domains) {
|
||||
const certs = await getCertificates();
|
||||
for (const cert of certs) {
|
||||
if (compareSets(cert.domain_names, domains)) {
|
||||
return cert;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
export async function hasCerficateByDomains(domains) {
|
||||
return (await getCertificateByDomains(domains)) !== null;
|
||||
}
|
||||
export async function deleteProxyHostByDomain(domain) {
|
||||
const id = await getProxyHostIdByDomain(domain);
|
||||
await _delete(`/nginx/proxy-hosts/${id}`);
|
||||
console.log('deleted proxy host for', domain);
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
import dotenv from 'dotenv';
|
||||
dotenv.config();
|
||||
const getFlag = (name) => {
|
||||
return (!!process.env[name] && /^true$/i.test(process.env[name]));
|
||||
};
|
||||
const getNumber = (name, fallback) => {
|
||||
const n = parseInt(process.env[name]);
|
||||
if (Number.isNaN(n) || typeof n !== 'number')
|
||||
return fallback;
|
||||
return n;
|
||||
};
|
||||
export const URL_AUTH = getFlag('URL_AUTH');
|
||||
export const BASE_DOMAIN = process.env.BASE_DOMAIN;
|
||||
export const DEPLOY_TOKEN = process.env.DEPLOY_TOKEN;
|
||||
export const NPM_EMAIL = process.env.NPM_EMAIL;
|
||||
export const NPM_PASSWORD = process.env.NPM_PASSWORD;
|
||||
export const NPM_BASE_URL = process.env.NPM_BASE_URL;
|
||||
export const INTERNAL_IP = process.env.INTERNAL_IP;
|
||||
// generally you should use host unless DNS is skipped, then IP as fallback.
|
||||
// but an ip is an address, so fallback to it here.
|
||||
export const INTERNAL_ADDRESS = process.env.INTERNAL_ADDRESS ?? INTERNAL_IP;
|
||||
export const PORT = getNumber('PORT', 6969);
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import { listen } from './routes.js';
|
||||
import { PORT } from './config.js';
|
||||
import * as npm from './apis/npm.js';
|
||||
// const id = await createContainer('hello-world');
|
||||
// const stream = await attachLogs(id)
|
||||
// stream.pipe(process.stdout);
|
||||
// await new Promise(res => {
|
||||
// stream.on('close', () => {
|
||||
// res(void 0);
|
||||
// })
|
||||
// })
|
||||
await npm.ready;
|
||||
listen(PORT);
|
||||
// console.log(await getProxyHosts());
|
||||
// console.log((await listContainers()).map(container => container.Names));
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
import express from 'express';
|
||||
import deploy from './actions/deploy.js';
|
||||
import { DEPLOY_TOKEN } from './config.js';
|
||||
export function listen(port) {
|
||||
const app = express();
|
||||
app.use((req, res, next) => {
|
||||
let givenToken = req.query.token;
|
||||
if (givenToken !== DEPLOY_TOKEN) {
|
||||
res.statusCode = 403;
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
next();
|
||||
});
|
||||
app.post('/deploy', async (req, res) => {
|
||||
try {
|
||||
const { cloneUrl, branch = 'HEAD' } = req.query;
|
||||
res.json({ status: "Acknowledged", cloneUrl, branch });
|
||||
await deploy({
|
||||
cloneUrl: cloneUrl,
|
||||
branch: branch
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e);
|
||||
// res.json(e);
|
||||
}
|
||||
});
|
||||
app.listen(port, () => {
|
||||
console.log('Listening on port', port);
|
||||
});
|
||||
}
|
||||
|
|
@ -2,4 +2,17 @@ version: '3'
|
|||
|
||||
services:
|
||||
app:
|
||||
image: valdeploy
|
||||
build: .
|
||||
network_mode: "host"
|
||||
environment:
|
||||
- DEPLOY_TOKEN=BtR4mh3TDTScwRPukKpfLPtpW2NqYunWRQ2BQJk5
|
||||
- BASE_DOMAIN=static.valnet.xyz
|
||||
- URL_AUTH=true
|
||||
- PORT=42069
|
||||
- NPM_BASE_URL=http://192.168.1.2:81/api
|
||||
- NPM_EMAIL=deploy@valnet.xyz
|
||||
- NPM_PASSWORD=QttLfDY8WwkTSRLEYLy93pRKmww3zoiRXSbBNm93
|
||||
- INTERNAL_IP=192.168.1.2
|
||||
- INTERNAL_ADDRESS=serafina
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
13
package.json
13
package.json
|
|
@ -5,14 +5,23 @@
|
|||
"license": "MIT",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "yarn ts-node --esm ./src/main.ts",
|
||||
"deploy": "docker build . -t valdeploy:0.1 && docker-compose down && docker-compose up"
|
||||
"dev": "nodemon -e ts,env,json -x yarn -- ts-node --esm ./src/main.ts",
|
||||
"deploy": "docker-compose down && docker-compose build && docker-compose up -d",
|
||||
"build": "DOCKER_BUILDKIT=0 docker-compose build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/dockerode": "^3.3.14",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/node": "^18.14.6",
|
||||
"@types/tmp": "^0.2.3",
|
||||
"dockerode": "^3.3.4",
|
||||
"dotenv": "^16.0.3",
|
||||
"express": "^4.18.2",
|
||||
"get-port": "^6.1.2",
|
||||
"node-fetch": "^3.3.0",
|
||||
"nodemon": "^2.0.21",
|
||||
"rimraf": "^4.4.0",
|
||||
"tmp": "^0.2.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
import { attachLogs, buildDockerImage, createContainer, listContainers, restartContainer, runCommandInContainer, startContainer, stopContainer } from "../apis/docker.js";
|
||||
import { createCertificate, createProxyHost, deleteProxyHostByDomain, getCertificateByDomains, getCertificates, hasCerficateByDomains, isDomainRegistered } from "../apis/npm.js";
|
||||
import { BASE_DOMAIN, INTERNAL_ADDRESS, INTERNAL_IP } from "../config.js";
|
||||
|
||||
interface Options {
|
||||
cloneUrl: string;
|
||||
branch: string;
|
||||
}
|
||||
|
||||
export default async function deploy(options: Options) {
|
||||
const { cloneUrl, branch } = options;
|
||||
const [, user, name] = /http[s]{0,1}:\/\/.*\/(.*)\/(.*)\.git/.exec(cloneUrl);
|
||||
console.log(`deploying ${user}/${name}`);
|
||||
const imageName = await buildDockerImage({
|
||||
user,
|
||||
name,
|
||||
cloneUrl,
|
||||
branch
|
||||
});
|
||||
const containerName = `deploy-${user}-${name}-${branch}`;
|
||||
|
||||
const { port } = await createContainer(imageName, containerName);
|
||||
|
||||
const domain = `${branch}.${name}.${user}.${BASE_DOMAIN}`;
|
||||
|
||||
await ensureDomainConfig(domain, port);
|
||||
|
||||
console.log(`${user}/${name} available at https://${domain}/`);
|
||||
}
|
||||
|
||||
async function ensureDomainConfig(domain: string, port: number) {
|
||||
// === certificate info
|
||||
|
||||
let certId = null;
|
||||
|
||||
if(await hasCerficateByDomains([domain])) {
|
||||
certId = (await getCertificateByDomains([domain])).id;
|
||||
console.log('certificate for', domain, 'already exists');
|
||||
} else {
|
||||
const newCert = await createCertificate([domain]);
|
||||
certId = newCert.id;
|
||||
}
|
||||
|
||||
if(await isDomainRegistered(domain)) {
|
||||
await deleteProxyHostByDomain(domain);
|
||||
}
|
||||
|
||||
await createProxyHost([domain], port, INTERNAL_ADDRESS, {
|
||||
ssl_forced: true,
|
||||
block_exploits: true,
|
||||
allow_websocket_upgrade: true,
|
||||
http2_support: true,
|
||||
certificate_id: certId
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,274 @@
|
|||
import Docker, { ContainerInfo } from "dockerode";
|
||||
import { writeFileSync } from "fs";
|
||||
import * as process from "process";
|
||||
import rimraf from "rimraf";
|
||||
import * as tmp from 'tmp';import getPort, {portNumbers} from 'get-port';
|
||||
import { INTERNAL_IP } from "../config.js";
|
||||
|
||||
|
||||
const docker = new Docker();
|
||||
|
||||
export async function createContainer(imageName: string, containerName: string): Promise<{
|
||||
id: string,
|
||||
port: number
|
||||
}> {
|
||||
|
||||
const port = await getPort({ host: INTERNAL_IP, port: portNumbers(52300, 52399)});
|
||||
|
||||
if(await isContainerNameInUse(containerName)) {
|
||||
await stopAndRemoveContainerByName(containerName);
|
||||
}
|
||||
|
||||
const containerOptions: Docker.ContainerCreateOptions = {
|
||||
Image: imageName,
|
||||
name: containerName,
|
||||
WorkingDir: '/app',
|
||||
HostConfig: {
|
||||
AutoRemove: false,
|
||||
RestartPolicy: {
|
||||
Name: "always"
|
||||
},
|
||||
PortBindings: {
|
||||
'3000/tcp': [{ HostPort: '' + port }]
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
const container = await docker.createContainer(containerOptions);
|
||||
await container.start();
|
||||
console.log("Started", containerName, "with port", port, '> 3000');
|
||||
await checkContainerStatus(container.id);
|
||||
return {
|
||||
id: container.id,
|
||||
port
|
||||
};
|
||||
} catch (err) {
|
||||
console.error("Error creating container:", err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
export async function listContainers() {
|
||||
return (await docker.listContainers())
|
||||
.map(v => v.Names[0])
|
||||
.filter((full: string) => {
|
||||
return full.startsWith('deploy-');
|
||||
});
|
||||
}
|
||||
|
||||
export async function getContainerInfo(containerId: string): Promise<Docker.ContainerInspectInfo> {
|
||||
const docker = new Docker();
|
||||
const container = docker.getContainer(containerId);
|
||||
const containerInfo = await container.inspect();
|
||||
return containerInfo;
|
||||
}
|
||||
|
||||
export async function checkImageExists(imageName: string) {
|
||||
const images = await docker.listImages();
|
||||
const imageExists = images.some(image => {
|
||||
if (image.RepoTags) {
|
||||
return image.RepoTags.includes(imageName);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return imageExists;
|
||||
}
|
||||
|
||||
export async function pullImage(imageName: string): Promise<void> {
|
||||
const imageExists = await checkImageExists(imageName);
|
||||
|
||||
if (!imageExists) {
|
||||
console.log(`Pulling image ${imageName}`);
|
||||
return new Promise((resolve, reject) => {
|
||||
docker.pull(imageName, (err, stream) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
docker.modem.followProgress(stream, (err: Error | null, output: unknown[]) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
console.log(`Image ${imageName} has been pulled`);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
console.log(`Image ${imageName} already exists`);
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
export async function attachLogs(containerId: string): Promise<NodeJS.ReadableStream> {
|
||||
const container = docker.getContainer(containerId);
|
||||
const logsStream = await container.logs({
|
||||
follow: true,
|
||||
stdout: true,
|
||||
stderr: true,
|
||||
});
|
||||
return logsStream;
|
||||
}
|
||||
|
||||
export async function isContainerNameInUse(name: string): Promise<boolean> {
|
||||
const containers = await docker.listContainers({ all: true });
|
||||
return containers.some((container: ContainerInfo) =>
|
||||
container.Names.includes(`/${name}`)
|
||||
);
|
||||
}
|
||||
|
||||
async function stopAndRemoveContainerByName(name) {
|
||||
const containers = await docker.listContainers({ all: true });
|
||||
const matchingContainers = containers.filter(container => container.Names.includes(`/${name}`));
|
||||
if (matchingContainers.length === 0) {
|
||||
throw new Error(`No container with name '${name}' was found`);
|
||||
}
|
||||
const stoppedContainer = docker.getContainer(matchingContainers[0].Id);
|
||||
try {
|
||||
await stoppedContainer.stop();
|
||||
} catch (error) {
|
||||
console.error(`Failed to stop container ${name}: ${error.message}`);
|
||||
}
|
||||
try {
|
||||
await stoppedContainer.remove();
|
||||
console.log(`Container ${name} removed`);
|
||||
} catch (error) {
|
||||
console.error(`Failed to remove container ${name}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function checkContainerStatus(containerId) {
|
||||
const container = docker.getContainer(containerId);
|
||||
const containerInfo = await container.inspect();
|
||||
const status = containerInfo.State.Status;
|
||||
console.log(`Container status: ${status}`);
|
||||
return status;
|
||||
}
|
||||
|
||||
export async function runCommandInContainer(containerId: string, command: string[]) {
|
||||
console.log('$', ...command);
|
||||
const container = await docker.getContainer(containerId);
|
||||
|
||||
const exec = await container.exec({
|
||||
Cmd: command,
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
});
|
||||
|
||||
const stream = await exec.start({});
|
||||
await new Promise((resolve, reject) => {
|
||||
container.modem.demuxStream(stream, process.stdout, process.stderr);
|
||||
stream.on('end', resolve);
|
||||
stream.on('error', reject);
|
||||
});
|
||||
}
|
||||
|
||||
export async function restartContainer(containerId: string) {
|
||||
const docker = new Docker();
|
||||
const container = await docker.getContainer(containerId);
|
||||
|
||||
console.log(`Restarting container ${containerId}...`);
|
||||
await container.restart();
|
||||
|
||||
await checkContainerStatus(containerId);
|
||||
}
|
||||
|
||||
export async function stopContainer(id: string) {
|
||||
const docker = new Docker();
|
||||
const container = await docker.getContainer(id);
|
||||
await container.stop();
|
||||
await checkContainerStatus(id);
|
||||
}
|
||||
|
||||
export async function startContainer(id: string) {
|
||||
const docker = new Docker();
|
||||
const container = await docker.getContainer(id);
|
||||
await container.start();
|
||||
await checkContainerStatus(id);
|
||||
}
|
||||
|
||||
interface BuildDockerImageOptions {
|
||||
cloneUrl: string;
|
||||
user: string;
|
||||
name: string;
|
||||
branch: string;
|
||||
}
|
||||
|
||||
function createDockerfile(cloneUrl: string, branch: string) {
|
||||
return `
|
||||
FROM node:lts-alpine3.17
|
||||
|
||||
RUN apk add git
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN git clone "${cloneUrl}" /app --depth 1 -b ${branch}
|
||||
|
||||
RUN yarn && yarn build
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD yarn start`.trim();
|
||||
}
|
||||
|
||||
export async function buildDockerImage(options: BuildDockerImageOptions) {
|
||||
|
||||
const {
|
||||
name: context
|
||||
} = tmp.dirSync();
|
||||
|
||||
const {
|
||||
user,
|
||||
name,
|
||||
branch,
|
||||
cloneUrl
|
||||
} = options;
|
||||
|
||||
const imageName = `${user}/${name}:${branch}`;
|
||||
|
||||
let id = null;
|
||||
|
||||
try {
|
||||
|
||||
writeFileSync(context + '/Dockerfile', createDockerfile(cloneUrl, branch));
|
||||
|
||||
const stream = await docker.buildImage({
|
||||
src: [ 'Dockerfile' ],
|
||||
context,
|
||||
}, {
|
||||
//@ts-ignore
|
||||
nocache: true,
|
||||
t: imageName
|
||||
});
|
||||
|
||||
//@ts-ignore
|
||||
stream.on('data', d => {
|
||||
const data = JSON.parse(d);
|
||||
const text = data.stream ?? '';
|
||||
process.stdout.write(text);
|
||||
if(text.startsWith("Successfully built")) {
|
||||
const potentialId = text.split(" ")[2];
|
||||
id = potentialId;
|
||||
}
|
||||
});
|
||||
|
||||
await new Promise((resolve) => {
|
||||
//@ts-ignore
|
||||
docker.modem.followProgress(stream, () => {
|
||||
resolve(void 0);
|
||||
});
|
||||
});
|
||||
|
||||
if(id === null) throw new Error("Unable to generate image " + imageName)
|
||||
|
||||
console.log("Built Image", imageName);
|
||||
|
||||
} catch (e) {
|
||||
console.log('do we get here?')
|
||||
await rimraf(context);
|
||||
throw e;
|
||||
}
|
||||
await rimraf(context);
|
||||
return imageName
|
||||
}
|
||||
|
|
@ -0,0 +1,283 @@
|
|||
import * as console from "console";
|
||||
import { INTERNAL_ADDRESS, NPM_BASE_URL, NPM_EMAIL, NPM_PASSWORD } from "../config.js";
|
||||
|
||||
let bearer = null;
|
||||
|
||||
const headers = () => {
|
||||
const headers: HeadersInit = {
|
||||
Authorization: "Bearer " + bearer,
|
||||
"Content-Type": "application/json"
|
||||
};
|
||||
return headers;
|
||||
}
|
||||
|
||||
async function _post(url: string, body: any) {
|
||||
const res = await fetch(NPM_BASE_URL + url, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(body),
|
||||
headers: headers()
|
||||
});
|
||||
|
||||
if(Math.floor(res.status / 100) !== 2) {
|
||||
throw new Error(JSON.stringify(await res.json(), null, 2));
|
||||
}
|
||||
|
||||
return await res.json();
|
||||
}
|
||||
|
||||
async function _get(url: string) {
|
||||
const res = await fetch(NPM_BASE_URL + url, {
|
||||
method: 'GET',
|
||||
headers: headers()
|
||||
});
|
||||
|
||||
return await res.json();
|
||||
}
|
||||
|
||||
async function _delete(url: string) {
|
||||
const res = await fetch(NPM_BASE_URL + url, {
|
||||
method: 'DELETE',
|
||||
headers: headers()
|
||||
});
|
||||
|
||||
return await res.json();
|
||||
}
|
||||
|
||||
function setToHappen(fn: () => void, date: Date) {
|
||||
var now = new Date().getTime();
|
||||
var diff = date.getTime() - now;
|
||||
return setTimeout(fn, diff);
|
||||
}
|
||||
|
||||
async function auth() {
|
||||
console.log("Attempting authentication against nginx");
|
||||
const {token, expires} = await _post('/tokens', {
|
||||
identity: NPM_EMAIL,
|
||||
secret: NPM_PASSWORD
|
||||
});
|
||||
setToHappen(auth, new Date(new Date(expires).getTime() - 60 * 1000));
|
||||
bearer = token;
|
||||
}
|
||||
|
||||
export function getProxyHosts(): Promise<ProxyHost[]> {
|
||||
return _get('/nginx/proxy-hosts')
|
||||
}
|
||||
|
||||
export const ready = auth();
|
||||
|
||||
export async function isDomainRegistered(domain: string) {
|
||||
const hosts = await getProxyHosts();
|
||||
return hosts.map(h => h.domain_names).flat().some(d => d === domain);
|
||||
}
|
||||
|
||||
export async function getProxyHostIdByDomain(domain: string): Promise<number | null> {
|
||||
const hosts = await getProxyHosts();
|
||||
for(const host of hosts) {
|
||||
for(const d of host.domain_names) {
|
||||
if(domain === d) {
|
||||
return host.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function createProxyHost(
|
||||
domains: string[],
|
||||
port: number,
|
||||
host: string,
|
||||
additionalConfig: Partial<NewProxyHostRequest>
|
||||
) {
|
||||
const registered = (await Promise.all(domains.map(d => isDomainRegistered(d)))).some(v => v);
|
||||
if(registered) {
|
||||
throw new Error("Domain is already registered as a proxy host");
|
||||
}
|
||||
|
||||
const res = await _post('/nginx/proxy-hosts', {
|
||||
domain_names: domains,
|
||||
forward_scheme: "http",
|
||||
forward_host: host,
|
||||
forward_port: port,
|
||||
block_exploits: false,
|
||||
allow_websocket_upgrade: false,
|
||||
access_list_id: "0",
|
||||
certificate_id: 0,
|
||||
ssl_forced: false,
|
||||
http2_support: false,
|
||||
meta: {
|
||||
letsencrypt_agree: false,
|
||||
dns_challenge: false
|
||||
},
|
||||
advanced_config: "",
|
||||
locations: [],
|
||||
caching_enabled: false,
|
||||
hsts_enabled: false,
|
||||
hsts_subdomains: false,
|
||||
...additionalConfig
|
||||
});
|
||||
|
||||
console.log('Created proxy host for', domains.join(', '));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
export async function createCertificate(domains: Domain[]): Promise<Certificate> {
|
||||
const certReq: NewCertificateRequest = {
|
||||
domain_names: domains,
|
||||
meta: {
|
||||
dns_challenge: false,
|
||||
letsencrypt_agree: true,
|
||||
letsencrypt_email: NPM_EMAIL
|
||||
},
|
||||
provider: "letsencrypt"
|
||||
}
|
||||
|
||||
const res = await _post('/nginx/certificates', certReq);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
export async function getCertificates(): Promise<Certificate[]> {
|
||||
return await _get('/nginx/certificates');
|
||||
}
|
||||
|
||||
function compareSets<T>(a: T[], b: T[]) {
|
||||
if(a.length !== b.length) return false;
|
||||
const _a = a.sort();
|
||||
const _b = b.sort();
|
||||
for(let i = 0; i < _a.length; i ++) {
|
||||
if(_a[i] !== _b[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export async function deleteCertificate(id: number) {
|
||||
const success = await _delete(`/nginx/certificate/${id}`);
|
||||
if(success !== 'true') {
|
||||
throw Error('Failed to delete certificate ' + id);
|
||||
}
|
||||
}
|
||||
|
||||
export async function getCertificateByDomains(domains: Domain[]) {
|
||||
const certs = await getCertificates();
|
||||
for(const cert of certs) {
|
||||
if(compareSets(cert.domain_names, domains)) {
|
||||
return cert;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function hasCerficateByDomains(domains: Domain[]) {
|
||||
return (await getCertificateByDomains(domains)) !== null;
|
||||
}
|
||||
|
||||
export async function deleteProxyHostByDomain(domain: string) {
|
||||
const id = await getProxyHostIdByDomain(domain);
|
||||
await _delete(`/nginx/proxy-hosts/${id}`);
|
||||
console.log('deleted proxy host for', domain);
|
||||
}
|
||||
|
||||
type Domain = 'sub.example.com' | string;
|
||||
type IP = '192.168.1.10' | string;
|
||||
type Scheme = "http" | "https";
|
||||
type Email = "user@example.com" | string;
|
||||
|
||||
interface NewProxyHostRequest {
|
||||
domain_names: Domain[],
|
||||
forward_scheme: Scheme,
|
||||
forward_host: Domain | IP,
|
||||
forward_port: number,
|
||||
allow_websocket_upgrade: boolean,
|
||||
access_list_id: "0",
|
||||
certificate_id: "new" | number,
|
||||
ssl_forced: boolean,
|
||||
http2_support: boolean,
|
||||
advanced_config: "",
|
||||
locations: [],
|
||||
block_exploits: boolean,
|
||||
caching_enabled: boolean,
|
||||
hsts_enabled: boolean,
|
||||
hsts_subdomains: boolean
|
||||
}
|
||||
|
||||
type BinaryNumber = 0 | 1;
|
||||
|
||||
interface ProxyHost {
|
||||
id: number,
|
||||
created_on: string, // datestring
|
||||
modified_on: string, //datestring
|
||||
owner_user_id: number,
|
||||
domain_names: Domain[],
|
||||
forward_host: string,
|
||||
forward_port: number,
|
||||
access_list_id: number,
|
||||
certificate_id: number,
|
||||
ssl_forced: BinaryNumber,
|
||||
caching_enabled: BinaryNumber,
|
||||
block_exploits: BinaryNumber,
|
||||
advanced_config: '',
|
||||
meta: {
|
||||
letsencrypt_email: Email,
|
||||
letsencrypt_agree: boolean,
|
||||
dns_challenge: boolean,
|
||||
nginx_online: boolean,
|
||||
nginx_err: null
|
||||
},
|
||||
allow_websocket_upgrade: BinaryNumber,
|
||||
http2_support: BinaryNumber,
|
||||
forward_scheme: Scheme,
|
||||
enabled: BinaryNumber,
|
||||
locations: [],
|
||||
hsts_enabled: BinaryNumber,
|
||||
hsts_subdomains: BinaryNumber,
|
||||
certificate: {
|
||||
owner_user_id: number,
|
||||
provider: 'letsencrypt',
|
||||
nice_name: string,
|
||||
domain_names: Domain[],
|
||||
expires_on: string, //datestring
|
||||
meta: {}
|
||||
},
|
||||
owner: {
|
||||
is_disabled: BinaryNumber,
|
||||
name: string,
|
||||
nickname: string,
|
||||
avatar: string
|
||||
},
|
||||
access_list: null,
|
||||
use_default_location: boolean,
|
||||
ipv6: boolean
|
||||
}
|
||||
|
||||
interface Certificate {
|
||||
id: number,
|
||||
created_on: string, //datestring
|
||||
modified_on: string, //datestring
|
||||
owner_user_id: 2,
|
||||
provider: "letsencrypt",
|
||||
nice_name: string,
|
||||
domain_names: Domain[],
|
||||
expires_on: string, //datestring
|
||||
meta: {
|
||||
letsencrypt_email: Email,
|
||||
letsencrypt_agree: boolean,
|
||||
dns_challenge: boolean
|
||||
},
|
||||
owner: {
|
||||
is_disabled: 0,
|
||||
name: "Static Deploy Robot",
|
||||
nickname: "deploy",
|
||||
avatar: "//www.gravatar.com/avatar/005a487e1c25024ddaa5972f33aa4dcc?default=mm"
|
||||
}
|
||||
}
|
||||
|
||||
interface NewCertificateRequest {
|
||||
domain_names: Domain[],
|
||||
meta: {
|
||||
dns_challenge: boolean,
|
||||
letsencrypt_email: Email,
|
||||
letsencrypt_agree: true
|
||||
},
|
||||
provider: 'letsencrypt'
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import dotenv from 'dotenv';
|
||||
dotenv.config();
|
||||
|
||||
const getFlag = (name: string) => {
|
||||
return (!!process.env[name] && /^true$/i.test(process.env[name]));
|
||||
}
|
||||
|
||||
const getNumber = (name: string, fallback: number) => {
|
||||
const n = parseInt(process.env[name]);
|
||||
if(Number.isNaN(n) || typeof n !== 'number') return fallback;
|
||||
return n;
|
||||
}
|
||||
|
||||
export const URL_AUTH = getFlag('URL_AUTH');
|
||||
export const BASE_DOMAIN = process.env.BASE_DOMAIN;
|
||||
export const DEPLOY_TOKEN = process.env.DEPLOY_TOKEN;
|
||||
export const NPM_EMAIL = process.env.NPM_EMAIL;
|
||||
export const NPM_PASSWORD = process.env.NPM_PASSWORD;
|
||||
export const NPM_BASE_URL = process.env.NPM_BASE_URL;
|
||||
export const INTERNAL_IP = process.env.INTERNAL_IP;
|
||||
// generally you should use host unless DNS is skipped, then IP as fallback.
|
||||
// but an ip is an address, so fallback to it here.
|
||||
export const INTERNAL_ADDRESS = process.env.INTERNAL_ADDRESS ?? INTERNAL_IP;
|
||||
export const PORT = getNumber('PORT', 6969);
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
import Docker from "dockerode";
|
||||
|
||||
const docker = new Docker();
|
||||
|
||||
export async function createContainer(imageName: string): Promise<string> {
|
||||
|
||||
await pullImage(imageName);
|
||||
|
||||
const containerOptions: Docker.ContainerCreateOptions = {
|
||||
Image: imageName,
|
||||
// HostConfig: {
|
||||
// AutoRemove: false,
|
||||
// },
|
||||
};
|
||||
|
||||
try {
|
||||
const container = await docker.createContainer(containerOptions);
|
||||
await container.start();
|
||||
console.log("Container started:", container.id);
|
||||
return container.id;
|
||||
} catch (err) {
|
||||
console.error("Error creating container:", err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
export function listContainers() {
|
||||
return docker.listContainers();
|
||||
}
|
||||
|
||||
export async function getContainerInfo(containerId: string): Promise<Docker.ContainerInspectInfo> {
|
||||
const docker = new Docker();
|
||||
const container = docker.getContainer(containerId);
|
||||
const containerInfo = await container.inspect();
|
||||
return containerInfo;
|
||||
}
|
||||
|
||||
export async function checkImageExists(imageName: string) {
|
||||
const images = await docker.listImages();
|
||||
const imageExists = images.some(image => {
|
||||
if (image.RepoTags) {
|
||||
return image.RepoTags.includes(imageName);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return imageExists;
|
||||
}
|
||||
|
||||
export async function pullImage(imageName: string): Promise<void> {
|
||||
const imageExists = await checkImageExists(imageName);
|
||||
|
||||
if (!imageExists) {
|
||||
console.log(`Pulling image ${imageName}`);
|
||||
return new Promise((resolve, reject) => {
|
||||
docker.pull(imageName, (err, stream) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
docker.modem.followProgress(stream, (err: Error | null, output: unknown[]) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
console.log(`Image ${imageName} has been pulled`);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
console.log(`Image ${imageName} already exists`);
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
export async function attachLogs(containerId: string): Promise<NodeJS.ReadableStream> {
|
||||
const docker = new Docker();
|
||||
const container = docker.getContainer(containerId);
|
||||
const logsStream = await container.logs({
|
||||
follow: true,
|
||||
stdout: true,
|
||||
stderr: true,
|
||||
});
|
||||
return logsStream;
|
||||
}
|
||||
17
src/main.ts
17
src/main.ts
|
|
@ -1,4 +1,10 @@
|
|||
import { attachLogs, createContainer, listContainers, pullImage } from './docker.js';
|
||||
|
||||
|
||||
import { attachLogs, createContainer, listContainers, pullImage } from './apis/docker.js';
|
||||
import { listen } from './routes.js';
|
||||
import { PORT } from './config.js';
|
||||
import * as npm from './apis/npm.js';
|
||||
import { getProxyHosts } from './apis/npm.js';
|
||||
|
||||
// const id = await createContainer('hello-world');
|
||||
// const stream = await attachLogs(id)
|
||||
|
|
@ -8,4 +14,11 @@ import { attachLogs, createContainer, listContainers, pullImage } from './docker
|
|||
// res(void 0);
|
||||
// })
|
||||
// })
|
||||
console.log((await listContainers()).map(container => container.Names));
|
||||
|
||||
|
||||
await npm.ready;
|
||||
listen(PORT);
|
||||
// console.log(await getProxyHosts());
|
||||
|
||||
|
||||
// console.log((await listContainers()).map(container => container.Names));
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
import express from 'express';
|
||||
import deploy from './actions/deploy.js';
|
||||
import { DEPLOY_TOKEN } from './config.js';
|
||||
|
||||
export function listen(port: number) {
|
||||
const app = express();
|
||||
app.use((req, res, next) => {
|
||||
console.log('incomming request', req.query, req.url, req.body);
|
||||
let givenToken = req.query.token
|
||||
if(givenToken !== DEPLOY_TOKEN) {
|
||||
res.statusCode = 403;
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
app.post('/deploy', async (req, res) => {
|
||||
try {
|
||||
const { cloneUrl, branch = 'HEAD' } = req.query;
|
||||
res.json({ status: "Acknowledged", cloneUrl, branch })
|
||||
await deploy({
|
||||
cloneUrl: cloneUrl as string,
|
||||
branch: branch as string
|
||||
});
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
// res.json(e);
|
||||
}
|
||||
})
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log('Listening on port', port);
|
||||
});
|
||||
}
|
||||
|
|
@ -4,5 +4,6 @@
|
|||
"module": "ESNext",
|
||||
"moduleResolution": "nodenext",
|
||||
"outDir": "dist"
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*.*"]
|
||||
}
|
||||
975
yarn-error.log
975
yarn-error.log
File diff suppressed because it is too large
Load Diff
807
yarn.lock
807
yarn.lock
|
|
@ -52,6 +52,21 @@
|
|||
resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e"
|
||||
integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==
|
||||
|
||||
"@types/body-parser@*":
|
||||
version "1.19.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0"
|
||||
integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==
|
||||
dependencies:
|
||||
"@types/connect" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/connect@*":
|
||||
version "3.4.35"
|
||||
resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1"
|
||||
integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/docker-modem@*":
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/docker-modem/-/docker-modem-3.0.2.tgz#c49c902e17364fc724e050db5c1d2b298c6379d4"
|
||||
|
|
@ -68,11 +83,53 @@
|
|||
"@types/docker-modem" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/express-serve-static-core@^4.17.33":
|
||||
version "4.17.33"
|
||||
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz#de35d30a9d637dc1450ad18dd583d75d5733d543"
|
||||
integrity sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
"@types/qs" "*"
|
||||
"@types/range-parser" "*"
|
||||
|
||||
"@types/express@^4.17.17":
|
||||
version "4.17.17"
|
||||
resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.17.tgz#01d5437f6ef9cfa8668e616e13c2f2ac9a491ae4"
|
||||
integrity sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==
|
||||
dependencies:
|
||||
"@types/body-parser" "*"
|
||||
"@types/express-serve-static-core" "^4.17.33"
|
||||
"@types/qs" "*"
|
||||
"@types/serve-static" "*"
|
||||
|
||||
"@types/mime@*":
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10"
|
||||
integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==
|
||||
|
||||
"@types/node@*", "@types/node@^18.11.18", "@types/node@^18.14.6":
|
||||
version "18.14.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.14.6.tgz#ae1973dd2b1eeb1825695bb11ebfb746d27e3e93"
|
||||
integrity sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==
|
||||
|
||||
"@types/qs@*":
|
||||
version "6.9.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb"
|
||||
integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==
|
||||
|
||||
"@types/range-parser@*":
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc"
|
||||
integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==
|
||||
|
||||
"@types/serve-static@*":
|
||||
version "1.15.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.1.tgz#86b1753f0be4f9a1bee68d459fcda5be4ea52b5d"
|
||||
integrity sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==
|
||||
dependencies:
|
||||
"@types/mime" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/ssh2@*":
|
||||
version "1.11.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/ssh2/-/ssh2-1.11.7.tgz#41b7477787a7fcb07b5d16cf907ed545ff0c1017"
|
||||
|
|
@ -80,6 +137,24 @@
|
|||
dependencies:
|
||||
"@types/node" "^18.11.18"
|
||||
|
||||
"@types/tmp@^0.2.3":
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.2.3.tgz#908bfb113419fd6a42273674c00994d40902c165"
|
||||
integrity sha512-dDZH/tXzwjutnuk4UacGgFRwV+JSLaXL1ikvidfJprkb7L9Nx1njcRHHmi3Dsvt7pgqqTEeucQuOrWHPFgzVHA==
|
||||
|
||||
abbrev@1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
|
||||
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
|
||||
|
||||
accepts@~1.3.8:
|
||||
version "1.3.8"
|
||||
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
|
||||
integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
|
||||
dependencies:
|
||||
mime-types "~2.1.34"
|
||||
negotiator "0.6.3"
|
||||
|
||||
acorn-walk@^8.1.1:
|
||||
version "8.2.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
|
||||
|
|
@ -90,11 +165,24 @@ acorn@^8.4.1:
|
|||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a"
|
||||
integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
|
||||
|
||||
anymatch@~3.1.2:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
|
||||
integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
|
||||
dependencies:
|
||||
normalize-path "^3.0.0"
|
||||
picomatch "^2.0.4"
|
||||
|
||||
arg@^4.1.0:
|
||||
version "4.1.3"
|
||||
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
|
||||
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
|
||||
|
||||
array-flatten@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
|
||||
integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==
|
||||
|
||||
asn1@^0.2.4:
|
||||
version "0.2.6"
|
||||
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d"
|
||||
|
|
@ -102,6 +190,11 @@ asn1@^0.2.4:
|
|||
dependencies:
|
||||
safer-buffer "~2.1.0"
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
||||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
||||
|
||||
base64-js@^1.3.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||
|
|
@ -114,6 +207,11 @@ bcrypt-pbkdf@^1.0.2:
|
|||
dependencies:
|
||||
tweetnacl "^0.14.3"
|
||||
|
||||
binary-extensions@^2.0.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
|
||||
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
|
||||
|
||||
bl@^4.0.3:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
|
||||
|
|
@ -123,6 +221,46 @@ bl@^4.0.3:
|
|||
inherits "^2.0.4"
|
||||
readable-stream "^3.4.0"
|
||||
|
||||
body-parser@1.20.1:
|
||||
version "1.20.1"
|
||||
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668"
|
||||
integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==
|
||||
dependencies:
|
||||
bytes "3.1.2"
|
||||
content-type "~1.0.4"
|
||||
debug "2.6.9"
|
||||
depd "2.0.0"
|
||||
destroy "1.2.0"
|
||||
http-errors "2.0.0"
|
||||
iconv-lite "0.4.24"
|
||||
on-finished "2.4.1"
|
||||
qs "6.11.0"
|
||||
raw-body "2.5.1"
|
||||
type-is "~1.6.18"
|
||||
unpipe "1.0.0"
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
|
||||
dependencies:
|
||||
balanced-match "^1.0.0"
|
||||
concat-map "0.0.1"
|
||||
|
||||
brace-expansion@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
|
||||
integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
|
||||
dependencies:
|
||||
balanced-match "^1.0.0"
|
||||
|
||||
braces@~3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
|
||||
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
|
||||
dependencies:
|
||||
fill-range "^7.0.1"
|
||||
|
||||
buffer@^5.5.0:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
|
||||
|
|
@ -136,11 +274,66 @@ buildcheck@0.0.3:
|
|||
resolved "https://registry.yarnpkg.com/buildcheck/-/buildcheck-0.0.3.tgz#70451897a95d80f7807e68fc412eb2e7e35ff4d5"
|
||||
integrity sha512-pziaA+p/wdVImfcbsZLNF32EiWyujlQLwolMqUQE8xpKNOH7KmZQaY8sXN7DGOEzPAElo9QTaeNRfGnf3iOJbA==
|
||||
|
||||
bytes@3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
|
||||
integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
|
||||
|
||||
call-bind@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
|
||||
integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
|
||||
dependencies:
|
||||
function-bind "^1.1.1"
|
||||
get-intrinsic "^1.0.2"
|
||||
|
||||
chokidar@^3.5.2:
|
||||
version "3.5.3"
|
||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
|
||||
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
|
||||
dependencies:
|
||||
anymatch "~3.1.2"
|
||||
braces "~3.0.2"
|
||||
glob-parent "~5.1.2"
|
||||
is-binary-path "~2.1.0"
|
||||
is-glob "~4.0.1"
|
||||
normalize-path "~3.0.0"
|
||||
readdirp "~3.6.0"
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
chownr@^1.1.1:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
|
||||
integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
|
||||
|
||||
content-disposition@0.5.4:
|
||||
version "0.5.4"
|
||||
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
|
||||
integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
|
||||
dependencies:
|
||||
safe-buffer "5.2.1"
|
||||
|
||||
content-type@~1.0.4:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
|
||||
integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
|
||||
|
||||
cookie-signature@1.0.6:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
|
||||
integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==
|
||||
|
||||
cookie@0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
|
||||
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
|
||||
|
||||
cpu-features@~0.0.4:
|
||||
version "0.0.4"
|
||||
resolved "https://registry.yarnpkg.com/cpu-features/-/cpu-features-0.0.4.tgz#0023475bb4f4c525869c162e4108099e35bf19d8"
|
||||
|
|
@ -154,6 +347,25 @@ create-require@^1.1.0:
|
|||
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
|
||||
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
|
||||
|
||||
data-uri-to-buffer@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e"
|
||||
integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==
|
||||
|
||||
debug@2.6.9:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@^3.2.7:
|
||||
version "3.2.7"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
|
||||
integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
debug@^4.1.1:
|
||||
version "4.3.4"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
||||
|
|
@ -161,6 +373,16 @@ debug@^4.1.1:
|
|||
dependencies:
|
||||
ms "2.1.2"
|
||||
|
||||
depd@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
|
||||
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
|
||||
|
||||
destroy@1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
|
||||
integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
|
||||
|
||||
diff@^4.0.1:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
|
||||
|
|
@ -190,6 +412,16 @@ dotenv@^16.0.3:
|
|||
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.3.tgz#115aec42bac5053db3c456db30cc243a5a836a07"
|
||||
integrity sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==
|
||||
|
||||
ee-first@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
|
||||
integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
|
||||
|
||||
encodeurl@~1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
|
||||
integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
|
||||
|
||||
end-of-stream@^1.1.0, end-of-stream@^1.4.1:
|
||||
version "1.4.4"
|
||||
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
|
||||
|
|
@ -197,48 +429,441 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1:
|
|||
dependencies:
|
||||
once "^1.4.0"
|
||||
|
||||
escape-html@~1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
||||
integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
|
||||
|
||||
etag@~1.8.1:
|
||||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
|
||||
integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
|
||||
|
||||
express@^4.18.2:
|
||||
version "4.18.2"
|
||||
resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59"
|
||||
integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==
|
||||
dependencies:
|
||||
accepts "~1.3.8"
|
||||
array-flatten "1.1.1"
|
||||
body-parser "1.20.1"
|
||||
content-disposition "0.5.4"
|
||||
content-type "~1.0.4"
|
||||
cookie "0.5.0"
|
||||
cookie-signature "1.0.6"
|
||||
debug "2.6.9"
|
||||
depd "2.0.0"
|
||||
encodeurl "~1.0.2"
|
||||
escape-html "~1.0.3"
|
||||
etag "~1.8.1"
|
||||
finalhandler "1.2.0"
|
||||
fresh "0.5.2"
|
||||
http-errors "2.0.0"
|
||||
merge-descriptors "1.0.1"
|
||||
methods "~1.1.2"
|
||||
on-finished "2.4.1"
|
||||
parseurl "~1.3.3"
|
||||
path-to-regexp "0.1.7"
|
||||
proxy-addr "~2.0.7"
|
||||
qs "6.11.0"
|
||||
range-parser "~1.2.1"
|
||||
safe-buffer "5.2.1"
|
||||
send "0.18.0"
|
||||
serve-static "1.15.0"
|
||||
setprototypeof "1.2.0"
|
||||
statuses "2.0.1"
|
||||
type-is "~1.6.18"
|
||||
utils-merge "1.0.1"
|
||||
vary "~1.1.2"
|
||||
|
||||
fetch-blob@^3.1.2, fetch-blob@^3.1.4:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9"
|
||||
integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==
|
||||
dependencies:
|
||||
node-domexception "^1.0.0"
|
||||
web-streams-polyfill "^3.0.3"
|
||||
|
||||
fill-range@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
|
||||
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
|
||||
dependencies:
|
||||
to-regex-range "^5.0.1"
|
||||
|
||||
finalhandler@1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32"
|
||||
integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==
|
||||
dependencies:
|
||||
debug "2.6.9"
|
||||
encodeurl "~1.0.2"
|
||||
escape-html "~1.0.3"
|
||||
on-finished "2.4.1"
|
||||
parseurl "~1.3.3"
|
||||
statuses "2.0.1"
|
||||
unpipe "~1.0.0"
|
||||
|
||||
formdata-polyfill@^4.0.10:
|
||||
version "4.0.10"
|
||||
resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423"
|
||||
integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==
|
||||
dependencies:
|
||||
fetch-blob "^3.1.2"
|
||||
|
||||
forwarded@0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
|
||||
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
|
||||
|
||||
fresh@0.5.2:
|
||||
version "0.5.2"
|
||||
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
|
||||
integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==
|
||||
|
||||
fs-constants@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
|
||||
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
|
||||
|
||||
fs.realpath@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
||||
|
||||
fsevents@~2.3.2:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
|
||||
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
|
||||
|
||||
function-bind@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
|
||||
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
|
||||
|
||||
get-intrinsic@^1.0.2:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f"
|
||||
integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==
|
||||
dependencies:
|
||||
function-bind "^1.1.1"
|
||||
has "^1.0.3"
|
||||
has-symbols "^1.0.3"
|
||||
|
||||
get-port@^6.1.2:
|
||||
version "6.1.2"
|
||||
resolved "https://registry.yarnpkg.com/get-port/-/get-port-6.1.2.tgz#c1228abb67ba0e17fb346da33b15187833b9c08a"
|
||||
integrity sha512-BrGGraKm2uPqurfGVj/z97/zv8dPleC6x9JBNRTrDNtCkkRF4rPwrQXFgL7+I+q8QSdU4ntLQX2D7KIxSy8nGw==
|
||||
|
||||
glob-parent@~5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
|
||||
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
|
||||
dependencies:
|
||||
is-glob "^4.0.1"
|
||||
|
||||
glob@^7.1.3:
|
||||
version "7.2.3"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
|
||||
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.1.1"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@^9.2.0:
|
||||
version "9.2.1"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-9.2.1.tgz#f47e34e1119e7d4f93a546e75851ba1f1e68de50"
|
||||
integrity sha512-Pxxgq3W0HyA3XUvSXcFhRSs+43Jsx0ddxcFrbjxNGkL2Ak5BAUBxLqI5G6ADDeCHLfzzXFhe0b1yYcctGmytMA==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
minimatch "^7.4.1"
|
||||
minipass "^4.2.4"
|
||||
path-scurry "^1.6.1"
|
||||
|
||||
has-flag@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
|
||||
integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
|
||||
|
||||
has-symbols@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
|
||||
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
|
||||
|
||||
has@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
|
||||
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
|
||||
dependencies:
|
||||
function-bind "^1.1.1"
|
||||
|
||||
http-errors@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
|
||||
integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
|
||||
dependencies:
|
||||
depd "2.0.0"
|
||||
inherits "2.0.4"
|
||||
setprototypeof "1.2.0"
|
||||
statuses "2.0.1"
|
||||
toidentifier "1.0.1"
|
||||
|
||||
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==
|
||||
|
||||
inherits@^2.0.3, inherits@^2.0.4:
|
||||
ignore-by-default@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09"
|
||||
integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==
|
||||
|
||||
inflight@^1.0.4:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
|
||||
integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
|
||||
dependencies:
|
||||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
ipaddr.js@1.9.1:
|
||||
version "1.9.1"
|
||||
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
|
||||
integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
|
||||
|
||||
is-binary-path@~2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
|
||||
integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
|
||||
dependencies:
|
||||
binary-extensions "^2.0.0"
|
||||
|
||||
is-extglob@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
|
||||
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
|
||||
|
||||
is-glob@^4.0.1, is-glob@~4.0.1:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
|
||||
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
|
||||
dependencies:
|
||||
is-extglob "^2.1.1"
|
||||
|
||||
is-number@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
|
||||
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
|
||||
|
||||
lru-cache@^7.14.1:
|
||||
version "7.18.3"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89"
|
||||
integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==
|
||||
|
||||
make-error@^1.1.1:
|
||||
version "1.3.6"
|
||||
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
|
||||
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
|
||||
|
||||
media-typer@0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
||||
integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
|
||||
|
||||
merge-descriptors@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
|
||||
integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==
|
||||
|
||||
methods@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
|
||||
integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==
|
||||
|
||||
mime-db@1.52.0:
|
||||
version "1.52.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
|
||||
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
|
||||
|
||||
mime-types@~2.1.24, mime-types@~2.1.34:
|
||||
version "2.1.35"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
|
||||
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
|
||||
dependencies:
|
||||
mime-db "1.52.0"
|
||||
|
||||
mime@1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
|
||||
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
|
||||
|
||||
minimatch@^3.1.1, minimatch@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
|
||||
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimatch@^7.4.1:
|
||||
version "7.4.2"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-7.4.2.tgz#157e847d79ca671054253b840656720cb733f10f"
|
||||
integrity sha512-xy4q7wou3vUoC9k1xGTXc+awNdGaGVHtFUaey8tiX4H1QRc04DZ/rmDFwNm2EBsuYEhAZ6SgMmYf3InGY6OauA==
|
||||
dependencies:
|
||||
brace-expansion "^2.0.1"
|
||||
|
||||
minipass@^4.0.2, minipass@^4.2.4:
|
||||
version "4.2.4"
|
||||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.4.tgz#7d0d97434b6a19f59c5c3221698b48bbf3b2cd06"
|
||||
integrity sha512-lwycX3cBMTvcejsHITUgYj6Gy6A7Nh4Q6h9NP4sTHY1ccJlC7yKzDmiShEHsJ16Jf1nKGDEaiHxiltsJEvk0nQ==
|
||||
|
||||
mkdirp-classic@^0.5.2:
|
||||
version "0.5.3"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113"
|
||||
integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
|
||||
|
||||
ms@2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||
|
||||
ms@2.1.3, ms@^2.1.1:
|
||||
version "2.1.3"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
|
||||
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
||||
|
||||
nan@^2.15.0, nan@^2.16.0:
|
||||
version "2.17.0"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb"
|
||||
integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==
|
||||
|
||||
once@^1.3.1, once@^1.4.0:
|
||||
negotiator@0.6.3:
|
||||
version "0.6.3"
|
||||
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
|
||||
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
|
||||
|
||||
node-domexception@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5"
|
||||
integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==
|
||||
|
||||
node-fetch@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.3.0.tgz#37e71db4ecc257057af828d523a7243d651d91e4"
|
||||
integrity sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==
|
||||
dependencies:
|
||||
data-uri-to-buffer "^4.0.0"
|
||||
fetch-blob "^3.1.4"
|
||||
formdata-polyfill "^4.0.10"
|
||||
|
||||
nodemon@^2.0.21:
|
||||
version "2.0.21"
|
||||
resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.21.tgz#267edff25578da91075d6aa54346ef77ecb7b302"
|
||||
integrity sha512-djN/n2549DUtY33S7o1djRCd7dEm0kBnj9c7S9XVXqRUbuggN1MZH/Nqa+5RFQr63Fbefq37nFXAE9VU86yL1A==
|
||||
dependencies:
|
||||
chokidar "^3.5.2"
|
||||
debug "^3.2.7"
|
||||
ignore-by-default "^1.0.1"
|
||||
minimatch "^3.1.2"
|
||||
pstree.remy "^1.1.8"
|
||||
semver "^5.7.1"
|
||||
simple-update-notifier "^1.0.7"
|
||||
supports-color "^5.5.0"
|
||||
touch "^3.1.0"
|
||||
undefsafe "^2.0.5"
|
||||
|
||||
nopt@~1.0.10:
|
||||
version "1.0.10"
|
||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee"
|
||||
integrity sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==
|
||||
dependencies:
|
||||
abbrev "1"
|
||||
|
||||
normalize-path@^3.0.0, normalize-path@~3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
|
||||
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
|
||||
|
||||
object-inspect@^1.9.0:
|
||||
version "1.12.3"
|
||||
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9"
|
||||
integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==
|
||||
|
||||
on-finished@2.4.1:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
|
||||
integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
|
||||
dependencies:
|
||||
ee-first "1.1.1"
|
||||
|
||||
once@^1.3.0, once@^1.3.1, once@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
parseurl@~1.3.3:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
|
||||
integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
|
||||
|
||||
path-is-absolute@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||
integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
|
||||
|
||||
path-scurry@^1.6.1:
|
||||
version "1.6.1"
|
||||
resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.6.1.tgz#dab45f7bb1d3f45a0e271ab258999f4ab7e23132"
|
||||
integrity sha512-OW+5s+7cw6253Q4E+8qQ/u1fVvcJQCJo/VFD8pje+dbJCF1n5ZRMV2AEHbGp+5Q7jxQIYJxkHopnj6nzdGeZLA==
|
||||
dependencies:
|
||||
lru-cache "^7.14.1"
|
||||
minipass "^4.0.2"
|
||||
|
||||
path-to-regexp@0.1.7:
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
|
||||
integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==
|
||||
|
||||
picomatch@^2.0.4, picomatch@^2.2.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
|
||||
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||
|
||||
proxy-addr@~2.0.7:
|
||||
version "2.0.7"
|
||||
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
|
||||
integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
|
||||
dependencies:
|
||||
forwarded "0.2.0"
|
||||
ipaddr.js "1.9.1"
|
||||
|
||||
pstree.remy@^1.1.8:
|
||||
version "1.1.8"
|
||||
resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a"
|
||||
integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==
|
||||
|
||||
pump@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
|
||||
|
|
@ -247,6 +872,28 @@ pump@^3.0.0:
|
|||
end-of-stream "^1.1.0"
|
||||
once "^1.3.1"
|
||||
|
||||
qs@6.11.0:
|
||||
version "6.11.0"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
|
||||
integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
|
||||
dependencies:
|
||||
side-channel "^1.0.4"
|
||||
|
||||
range-parser@~1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
|
||||
integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
|
||||
|
||||
raw-body@2.5.1:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857"
|
||||
integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==
|
||||
dependencies:
|
||||
bytes "3.1.2"
|
||||
http-errors "2.0.0"
|
||||
iconv-lite "0.4.24"
|
||||
unpipe "1.0.0"
|
||||
|
||||
readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0:
|
||||
version "3.6.1"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.1.tgz#f9f9b5f536920253b3d26e7660e7da4ccff9bb62"
|
||||
|
|
@ -256,16 +903,97 @@ readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0:
|
|||
string_decoder "^1.1.1"
|
||||
util-deprecate "^1.0.1"
|
||||
|
||||
safe-buffer@~5.2.0:
|
||||
readdirp@~3.6.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
|
||||
integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
|
||||
dependencies:
|
||||
picomatch "^2.2.1"
|
||||
|
||||
rimraf@^3.0.0:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
|
||||
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
|
||||
dependencies:
|
||||
glob "^7.1.3"
|
||||
|
||||
rimraf@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-4.4.0.tgz#c7a9f45bb2ec058d2e60ef9aca5167974313d605"
|
||||
integrity sha512-X36S+qpCUR0HjXlkDe4NAOhS//aHH0Z+h8Ckf2auGJk3PTnx5rLmrHkwNdbVQuCSUhOyFrlRvFEllZOYE+yZGQ==
|
||||
dependencies:
|
||||
glob "^9.2.0"
|
||||
|
||||
safe-buffer@5.2.1, safe-buffer@~5.2.0:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||
|
||||
safer-buffer@~2.1.0:
|
||||
"safer-buffer@>= 2.1.2 < 3", safer-buffer@~2.1.0:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
semver@^5.7.1:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
||||
|
||||
semver@~7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
|
||||
integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
|
||||
|
||||
send@0.18.0:
|
||||
version "0.18.0"
|
||||
resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be"
|
||||
integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==
|
||||
dependencies:
|
||||
debug "2.6.9"
|
||||
depd "2.0.0"
|
||||
destroy "1.2.0"
|
||||
encodeurl "~1.0.2"
|
||||
escape-html "~1.0.3"
|
||||
etag "~1.8.1"
|
||||
fresh "0.5.2"
|
||||
http-errors "2.0.0"
|
||||
mime "1.6.0"
|
||||
ms "2.1.3"
|
||||
on-finished "2.4.1"
|
||||
range-parser "~1.2.1"
|
||||
statuses "2.0.1"
|
||||
|
||||
serve-static@1.15.0:
|
||||
version "1.15.0"
|
||||
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540"
|
||||
integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==
|
||||
dependencies:
|
||||
encodeurl "~1.0.2"
|
||||
escape-html "~1.0.3"
|
||||
parseurl "~1.3.3"
|
||||
send "0.18.0"
|
||||
|
||||
setprototypeof@1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
|
||||
integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
|
||||
|
||||
side-channel@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
|
||||
integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
|
||||
dependencies:
|
||||
call-bind "^1.0.0"
|
||||
get-intrinsic "^1.0.2"
|
||||
object-inspect "^1.9.0"
|
||||
|
||||
simple-update-notifier@^1.0.7:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz#67694c121de354af592b347cdba798463ed49c82"
|
||||
integrity sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==
|
||||
dependencies:
|
||||
semver "~7.0.0"
|
||||
|
||||
split-ca@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/split-ca/-/split-ca-1.0.1.tgz#6c83aff3692fa61256e0cd197e05e9de157691a6"
|
||||
|
|
@ -282,6 +1010,11 @@ ssh2@^1.11.0:
|
|||
cpu-features "~0.0.4"
|
||||
nan "^2.16.0"
|
||||
|
||||
statuses@2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
|
||||
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
|
||||
|
||||
string_decoder@^1.1.1:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
|
||||
|
|
@ -289,6 +1022,13 @@ string_decoder@^1.1.1:
|
|||
dependencies:
|
||||
safe-buffer "~5.2.0"
|
||||
|
||||
supports-color@^5.5.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
|
||||
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
|
||||
dependencies:
|
||||
has-flag "^3.0.0"
|
||||
|
||||
tar-fs@~2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.0.1.tgz#e44086c1c60d31a4f0cf893b1c4e155dabfae9e2"
|
||||
|
|
@ -310,6 +1050,32 @@ tar-stream@^2.0.0:
|
|||
inherits "^2.0.3"
|
||||
readable-stream "^3.1.1"
|
||||
|
||||
tmp@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14"
|
||||
integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==
|
||||
dependencies:
|
||||
rimraf "^3.0.0"
|
||||
|
||||
to-regex-range@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
|
||||
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
|
||||
dependencies:
|
||||
is-number "^7.0.0"
|
||||
|
||||
toidentifier@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
|
||||
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
|
||||
|
||||
touch@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b"
|
||||
integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==
|
||||
dependencies:
|
||||
nopt "~1.0.10"
|
||||
|
||||
ts-node@^10.9.1:
|
||||
version "10.9.1"
|
||||
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b"
|
||||
|
|
@ -334,21 +1100,54 @@ tweetnacl@^0.14.3:
|
|||
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
|
||||
integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==
|
||||
|
||||
type-is@~1.6.18:
|
||||
version "1.6.18"
|
||||
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
|
||||
integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
|
||||
dependencies:
|
||||
media-typer "0.3.0"
|
||||
mime-types "~2.1.24"
|
||||
|
||||
typescript@^4.9.5:
|
||||
version "4.9.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
|
||||
integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
|
||||
|
||||
undefsafe@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c"
|
||||
integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==
|
||||
|
||||
unpipe@1.0.0, unpipe@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
|
||||
integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
|
||||
|
||||
util-deprecate@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
|
||||
|
||||
utils-merge@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
||||
integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
|
||||
|
||||
v8-compile-cache-lib@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
|
||||
integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
|
||||
|
||||
vary@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
|
||||
|
||||
web-streams-polyfill@^3.0.3:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6"
|
||||
integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
|
|
|
|||
Loading…
Reference in New Issue