Compare commits

...

25 commits

Author SHA1 Message Date
James Long 97081d46c4 Fix reference to Timestamp; version 22.12.09 2022-12-08 17:38:26 -05:00
James Long 60f83b334e 22.12.08 2022-12-08 16:00:20 -05:00
James Long 340ac869ce Bump API to working version 2022-12-08 16:00:01 -05:00
Trevor Farlow b2b6ba4921 Docker workflow: Drop major.minor tagging 2022-12-08 14:53:48 -05:00
James Long 3274a06e34 Bump to 22.12.03 2022-12-08 12:11:21 -05:00
James Long e9850bfc56 Bump @actual-app/web and @actual-app/api 2022-12-08 11:30:07 -05:00
James Long 529c42cccf Version 22.10.25 of actual-server 2022-10-25 12:19:40 -04:00
Rich In SQL 2a00227486 Update Actual to 22.10.25 2022-10-25 11:28:16 -04:00
Trevor Farlow 5252edbf70
Merge pull request #82 from trevdor/patch-1
Build docker image on push to master or tag
2022-10-19 21:32:16 -06:00
Trevor Farlow 74c15b4f42
fixup! Build docker image on push to master or tag 2022-10-13 00:19:59 -06:00
Trevor Farlow d482b9baf6
Build docker image on push to master or tag 2022-10-13 00:17:12 -06:00
James Long cde216523e Store user files as blobs instead of unzipping them 2022-10-05 21:47:14 -04:00
James Long 8aeb815b5a Respect configuration for user-files 2022-09-15 10:19:22 -04:00
James Long 3c602268e3 Log sync method in response 2022-09-14 23:43:12 -04:00
James Long 9177fb4d77 Fix lint 2022-09-14 23:43:12 -04:00
James Long e3f1fafad9 Switch syncing to simple sync method 2022-09-14 23:43:12 -04:00
Arthur E. Jones 32bf923c1a build: add node GC argument to fly template
Fly deployments on the free tier have ~256mb of memory available. Users
with large transaction histories were encountering out of memory errors
when attempting to export their data. This commit adds a node argument
to (more or less) run the garbage collector at a smaller memory usage,
helping keep users on flyio within their available limit.
2022-08-31 23:51:05 -04:00
Arthur E. Jones d3a0e8067e build: add tini subreaper arg to fly template
Fly deployments with the previous template setting are running without
tini's subreaper capabilities. This change enables tini as a subreaper
in that environment.
2022-08-31 23:50:26 -04:00
Arthur E. Jones 105d5007cf fix: zip only necessary files in budget download
While investigating #54 it was noted that the previous implementation
zips the entire budget folder in the download endpoint. Once received on
the client side, only the most recent db and metadata are actually used.
This means up to 10 backups are being zipped in memory and transferred
to the client (in addition to the two necessary files) despite none of
that data being used. While this inefficiency isn't a major concern in
some environments, it may be problematic in memory constrained
environments.

This change transfers only the files that are actually utilized.

issue #54
2022-08-31 23:49:52 -04:00
Tom French bafa486668 style: ignore unused variables which begin with an underscore 2022-08-29 23:11:51 -04:00
Tom French 80a2b34d43 style: apply prettier fixes 2022-08-29 23:11:51 -04:00
Tom French a5e1e38e74 fix: activate prettier rules 2022-08-29 23:11:51 -04:00
Tom French 0486e9e37b ci: check that the server builds correctly on PRs/master 2022-08-29 23:11:02 -04:00
Tom French 09722d8678 ci: rename github workflow file from build to docker 2022-08-29 23:11:02 -04:00
Rich In SQL cd22e38660 Express version update
Update: Updated express version, this resolves #69
2022-08-09 10:41:29 -04:00
18 changed files with 311 additions and 319 deletions

View file

@ -7,8 +7,16 @@ module.exports = {
},
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint', 'prettier'],
extends: ['eslint:recommended', "plugin:@typescript-eslint/recommended"],
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
rules: {
"@typescript-eslint/no-var-requires": "off"
'prettier/prettier': 'error',
'@typescript-eslint/no-unused-vars': [
'warn',
{
argsIgnorePattern: '^_'
}
],
'@typescript-eslint/no-var-requires': 'off'
}
};

View file

@ -1,85 +1,29 @@
name: Build Docker Image
name: Build
# Docker Images are only built when a new tag is created
on:
push:
tags:
- 'v*.*.*'
branches:
- master
pull_request:
branches: '*'
jobs:
build:
name: Build Docker image
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Docker meta
id: meta
uses: docker/metadata-action@v4
- uses: actions/checkout@v2
- name: Install node
uses: actions/setup-node@v1
with:
# Push to both Docker Hub and Github Container Registry
images: |
jlongster/actual-server
ghcr.io/actualbudget/actual-server
# Creates the following tags:
# - actual-server:latest
# - actual-server:1.3
# - actual-server:1.3.7
# - actual-server:sha-90dd603
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
- name: Docker meta for Alpine image
id: alpine-meta
uses: docker/metadata-action@v4
node-version: 16
- name: Cache
uses: actions/cache@v2
id: cache
with:
images: |
jlongster/actual-server
ghcr.io/actualbudget/actual-server
tags: |
type=ref,event=branch
type=ref,event=pr
type=raw,value=latest,suffix=-alpine
type=semver,pattern={{version}},suffix=-alpine
type=semver,pattern={{major}}.{{minor}},suffix=-alpine
type=sha,suffix=-alpine
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push standard image
uses: docker/build-push-action@v2
with:
context: .
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
- name: Build and push Alpine image
uses: docker/build-push-action@v2
with:
context: .
push: true
file: Dockerfile.alpine
platforms: linux/amd64,linux/arm64
tags: ${{ steps.alpine-meta.outputs.tags }}
path: '**/node_modules'
key: yarn-v1-${{ hashFiles('**/yarn.lock') }}
- name: Install
run: yarn --immutable
if: steps.cache.outputs.cache-hit != 'true'
- name: Build
run: yarn build

93
.github/workflows/docker.yml vendored Normal file
View file

@ -0,0 +1,93 @@
name: Build Docker Image
# Docker Images are built for every push to master or when a new tag is created
on:
push:
branches:
- master
tags:
- 'v*.*.*'
paths-ignore:
- README.md
- LICENSE.txt
env:
IMAGES: |
jlongster/actual-server
ghcr.io/actualbudget/actual-server
# Creates the following tags:
# - actual-server:latest (see docker/metadata-action flavor inputs, below)
# - actual-server:edge (for master)
# - actual-server:1.3
# - actual-server:1.3.7
# - actual-server:sha-90dd603
TAGS: |
type=edge,value=edge
type=semver,pattern={{version}}
type=sha
jobs:
build:
name: Build Docker image
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Docker meta
id: meta
uses: docker/metadata-action@v4
with:
# Push to both Docker Hub and Github Container Registry
images: ${{ env.IMAGES }}
# Automatically update :latest for our semver tags
flavor: |
latest=auto
tags: ${{ env.TAGS }}
- name: Docker meta for Alpine image
id: alpine-meta
uses: docker/metadata-action@v4
with:
images: ${{ env.IMAGES }}
# Automatically update :latest for our semver tags and suffix all tags
flavor: |
latest=auto
suffix=-alpine,onlatest=true
tags: $${{ env.TAGS }}
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push standard image
uses: docker/build-push-action@v2
with:
context: .
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
- name: Build and push Alpine image
uses: docker/build-push-action@v2
with:
context: .
push: true
file: Dockerfile.alpine
platforms: linux/amd64,linux/arm64
tags: ${{ steps.alpine-meta.outputs.tags }}

View file

@ -190,7 +190,7 @@ app.post(
'Content-Type': 'application/json',
'User-Agent': 'Actual Budget'
}
}).then(res => res.json());
}).then((res) => res.json());
await req.runQuery(
'INSERT INTO access_tokens (item_id, user_id, access_token) VALUES ($1, $2, $3)',
@ -233,7 +233,7 @@ app.post(
'Content-Type': 'application/json',
'User-Agent': 'Actual Budget'
}
}).then(res => res.json());
}).then((res) => res.json());
if (resData.removed !== true) {
console.log('[Error] Item not removed: ' + access_token.slice(0, 3));
@ -286,7 +286,7 @@ app.post(
'Content-Type': 'application/json',
'User-Agent': 'Actual Budget'
}
}).then(res => res.json());
}).then((res) => res.json());
res.send(
JSON.stringify({
@ -342,7 +342,7 @@ app.post(
'Content-Type': 'application/json',
'User-Agent': 'Actual Budget'
}
}).then(res => res.json());
}).then((res) => res.json());
res.send(
JSON.stringify({

View file

@ -1,14 +1,13 @@
let fs = require('fs/promises');
let { Buffer } = require('buffer');
let { join } = require('path');
let express = require('express');
let uuid = require('uuid');
let AdmZip = require('adm-zip');
let { validateUser } = require('./util/validate-user');
let errorMiddleware = require('./util/error-middleware');
let config = require('./load-config');
let { getAccountDb } = require('./account-db');
let { getPathForUserFile, getPathForGroupFile } = require('./util/paths');
let fullSync = require('./sync-full');
let simpleSync = require('./sync-simple');
let actual = require('@actual-app/api');
let SyncPb = actual.internal.SyncProtoBuf;
@ -16,17 +15,8 @@ let SyncPb = actual.internal.SyncProtoBuf;
const app = express();
app.use(errorMiddleware);
async function init() {
let fileDir = join(process.env.ACTUAL_USER_FILES || config.userFiles);
console.log('Initializing Actual with user file dir:', fileDir);
await actual.init({
config: {
dataDir: fileDir
}
});
}
// eslint-disable-next-line
async function init() {}
// This is a version representing the internal format of sync
// messages. When this changes, all sync files need to be reset. We
@ -121,24 +111,15 @@ app.post('/sync', async (req, res) => {
return false;
}
// TODO: We also provide a "simple" sync method which currently isn't
// used. This method just stores the messages locally and doesn't
// load the whole app at all. If we want to support end-to-end
// encryption, this method is required because we can't read the
// messages. Using it looks like this:
//
// let simpleSync = require('./sync-simple');
// let {trie, newMessages } = simpleSync.sync(messages, since, file_id);
let { trie, newMessages } = await fullSync.sync(messages, since, file_id);
let { trie, newMessages } = simpleSync.sync(messages, since, group_id);
// encode it back...
let responsePb = new SyncPb.SyncResponse();
responsePb.setMerkle(JSON.stringify(trie));
newMessages.forEach(msg => responsePb.addMessages(msg));
newMessages.forEach((msg) => responsePb.addMessages(msg));
res.set('Content-Type', 'application/actual-sync');
res.set('X-ACTUAL-SYNC-METHOD', 'simple');
res.send(Buffer.from(responsePb.serializeBinary()));
});
@ -185,7 +166,7 @@ app.post('/user-create-key', (req, res) => {
res.send(JSON.stringify({ status: 'ok' }));
});
app.post('/reset-user-file', (req, res) => {
app.post('/reset-user-file', async (req, res) => {
let user = validateUser(req, res);
if (!user) {
return;
@ -205,10 +186,11 @@ app.post('/reset-user-file', (req, res) => {
accountDb.mutate('UPDATE files SET group_id = NULL WHERE id = ?', [fileId]);
if (group_id) {
// TODO: Instead of doing this, just delete the db file named
// after the group
// db.mutate('DELETE FROM messages_binary WHERE group_id = ?', [group_id]);
// db.mutate('DELETE FROM messages_merkles WHERE group_id = ?', [group_id]);
try {
await fs.unlink(getPathForGroupFile(group_id));
} catch (e) {
console.log(`Unable to delete sync data for group "${group_id}"`);
}
}
res.send(JSON.stringify({ status: 'ok' }));
@ -265,21 +247,11 @@ app.post('/upload-user-file', async (req, res) => {
}
}
// TODO: If we want to support end-to-end encryption, we'd write the
// raw file down because it's an encrypted blob. This isn't
// supported yet in the self-hosted version because it's unclear if
// it's still needed, given that you own your server
//
// await fs.writeFile(join(config.userFiles, `${fileId}.blob`), req.body);
let zip = new AdmZip(req.body);
try {
zip.extractAllTo(join(config.userFiles, fileId), true);
await fs.writeFile(getPathForUserFile(fileId), req.body);
} catch (err) {
console.log('Error writing file', err);
res.send(JSON.stringify({ status: 'error' }));
return;
}
let rows = accountDb.all('SELECT id FROM files WHERE id = ?', [fileId]);
@ -306,6 +278,7 @@ app.post('/upload-user-file', async (req, res) => {
'UPDATE files SET sync_version = ?, encrypt_meta = ?, name = ? WHERE id = ?',
[syncFormatVersion, encryptMeta, name, fileId]
);
res.send(JSON.stringify({ status: 'ok', groupId }));
}
});
@ -328,14 +301,14 @@ app.get('/download-user-file', async (req, res) => {
return;
}
let zip = new AdmZip();
let buffer;
try {
zip.addLocalFolder(join(config.userFiles, fileId), '/');
buffer = await fs.readFile(getPathForUserFile(fileId));
} catch (e) {
res.status(500).send('Error reading files');
console.log(`Error: file does not exist: ${getPathForUserFile(fileId)}`);
res.status(500).send('File does not exist on server');
return;
}
let buffer = zip.toBuffer();
res.setHeader('Content-Disposition', `attachment;filename=${fileId}`);
res.send(buffer);
@ -376,7 +349,7 @@ app.get('/list-user-files', (req, res) => {
res.send(
JSON.stringify({
status: 'ok',
data: rows.map(row => ({
data: rows.map((row) => ({
deleted: row.deleted,
fileId: row.id,
groupId: row.group_id,

4
app.js
View file

@ -10,7 +10,7 @@ const syncApp = require('./app-sync');
const app = express();
process.on('unhandledRejection', reason => {
process.on('unhandledRejection', (reason) => {
console.log('Rejection:', reason);
});
@ -59,7 +59,7 @@ async function run() {
app.listen(config.port, config.hostname);
}
run().catch(err => {
run().catch((err) => {
console.log('Error starting app:', err);
process.exit(1);
});

View file

@ -6,10 +6,12 @@ processes = []
[env]
PORT = "5006"
TINI_SUBREAPER = 1
[experimental]
allowed_public_ports = []
auto_rollback = true
cmd = ["node", "--max-old-space-size=180", "app.js"]
[[services]]
http_checks = []

View file

@ -16,4 +16,7 @@ try {
};
}
// The env variable always takes precedence
config.userFiles = process.env.ACTUAL_USER_FILES || config.userFiles;
module.exports = config;

View file

@ -37,7 +37,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
true
);
db.transaction(() => {
budget.map(monthBudget => {
budget.map((monthBudget) => {
let match = monthBudget.name.match(
/^(budget-report|budget)(\d+)!budget-(.+)$/
);
@ -84,7 +84,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
true
);
db.transaction(() => {
buffers.map(buffer => {
buffers.map((buffer) => {
let match = buffer.name.match(/^budget(\d+)!buffered$/);
if (match) {
let month = match[1].slice(0, 4) + '-' + match[1].slice(4);
@ -108,7 +108,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
true
);
let parseNote = str => {
let parseNote = (str) => {
try {
let value = JSON.parse(str);
return value && value !== '' ? value : null;
@ -118,7 +118,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
};
db.transaction(() => {
notes.forEach(note => {
notes.forEach((note) => {
let parsed = parseNote(getValue(note));
if (parsed) {
let [, id] = note.name.split('!');

View file

@ -1,6 +1,6 @@
{
"name": "actual-sync",
"version": "1.0.1",
"version": "22.12.09",
"license": "MIT",
"description": "actual syncing server",
"main": "index.js",
@ -12,27 +12,26 @@
"verify": "yarn -s lint && yarn types"
},
"dependencies": {
"@actual-app/api": "4.1.0",
"@actual-app/web": "4.1.0",
"adm-zip": "^0.5.9",
"@actual-app/api": "4.1.5",
"@actual-app/web": "22.12.3",
"bcrypt": "^5.0.1",
"better-sqlite3": "^7.5.0",
"body-parser": "^1.18.3",
"cors": "^2.8.5",
"express": "^4.16.3",
"express": "4.17",
"express-actuator": "^1.8.1",
"express-response-size": "^0.0.3",
"node-fetch": "^2.2.0",
"uuid": "^3.3.2"
},
"devDependencies": {
"@types/better-sqlite3": "^7.5.0",
"@types/node": "^17.0.31",
"@typescript-eslint/eslint-plugin": "^5.23.0",
"@typescript-eslint/parser": "^5.23.0",
"eslint": "^8.15.0",
"eslint-plugin-prettier": "^4.0.0",
"prettier": "^2.6.2",
"@types/better-sqlite3": "^7.5.0",
"@types/node": "^17.0.31",
"typescript": "^4.6.4"
}
}

View file

@ -1,10 +1,9 @@
CREATE TABLE messages_binary
(timestamp TEXT,
(timestamp TEXT PRIMARY KEY,
is_encrypted BOOLEAN,
content bytea,
PRIMARY KEY(timestamp, group_id));
content bytea);
CREATE TABLE messages_merkles
(id TEXT PRIMAREY KEY,
(id INTEGER PRIMARY KEY,
merkle TEXT);

View file

@ -15,7 +15,7 @@ const sync = sequential(async function syncAPI(messages, since, fileId) {
await actual.internal.send('load-budget', { id: fileId });
}
messages = messages.map(envPb => {
messages = messages.map((envPb) => {
let timestamp = envPb.getTimestamp();
let msg = SyncPb.Message.deserializeBinary(envPb.getContent());
return {
@ -27,11 +27,14 @@ const sync = sequential(async function syncAPI(messages, since, fileId) {
};
});
const newMessages = await actual.internal.syncAndReceiveMessages(messages, since);
const newMessages = await actual.internal.syncAndReceiveMessages(
messages,
since
);
return {
trie: actual.internal.timestamp.getClock().merkle,
newMessages: newMessages.map(msg => {
newMessages: newMessages.map((msg) => {
const envelopePb = new SyncPb.MessageEnvelope();
const messagePb = new SyncPb.Message();

View file

@ -1,13 +1,15 @@
let { existsSync, readFileSync } = require('fs');
let { join } = require('path');
let { openDatabase } = require('./db');
let { getPathForGroupFile } = require('./util/paths');
let actual = require('@actual-app/api');
let merkle = actual.internal.merkle;
let SyncPb = actual.internal.SyncProtoBuf;
let Timestamp = actual.internal.timestamp.Timestamp;
function getGroupDb(groupId) {
let path = join(__dirname, `user-files/${groupId}.sqlite`);
let path = getPathForGroupFile(groupId);
let needsInit = !existsSync(path);
let db = openDatabase(path);
@ -56,8 +58,8 @@ function addMessages(db, messages) {
return returnValue;
}
function getMerkle(db, group_id) {
let rows = db.all('SELECT * FROM messages_merkles', [group_id]);
function getMerkle(db) {
let rows = db.all('SELECT * FROM messages_merkles');
if (rows.length > 0) {
return JSON.parse(rows[0].merkle);
@ -68,18 +70,29 @@ function getMerkle(db, group_id) {
}
}
function sync(messages, since, fileId) {
let db = getGroupDb(fileId);
function sync(messages, since, groupId) {
let db = getGroupDb(groupId);
let newMessages = db.all(
`SELECT * FROM messages_binary
WHERE timestamp > ?
ORDER BY timestamp`,
[since],
[since]
);
let trie = addMessages(db, messages);
return { trie, newMessages };
db.close();
return {
trie,
newMessages: newMessages.map((msg) => {
const envelopePb = new SyncPb.MessageEnvelope();
envelopePb.setTimestamp(msg.timestamp);
envelopePb.setIsencrypted(msg.is_encrypted);
envelopePb.setContent(msg.content);
return envelopePb;
})
};
}
module.exports = { sync };

View file

@ -17,11 +17,11 @@ function sequential(fn) {
sequenceState.running = fn(...args);
sequenceState.running.then(
val => {
(val) => {
pump();
resolve(val);
},
err => {
(err) => {
pump();
reject(err);
}

View file

@ -1,4 +1,4 @@
async function middleware(err, req, res, next) {
async function middleware(err, req, res, _next) {
console.log('ERROR', err);
res.status(500).send({ status: 'error', reason: 'internal-error' });
}

View file

@ -1,11 +1,11 @@
function handleError(func) {
return (req, res) => {
func(req, res).catch(err => {
console.log('Error', req.originalUrl, err);
func(req, res).catch((err) => {
console.log('Error', req.originalUrl, err);
res.status(500);
res.send({ status: 'error', reason: 'internal-error' });
});
};
}
module.exports = { handleError }
module.exports = { handleError };

12
util/paths.js Normal file
View file

@ -0,0 +1,12 @@
let { join } = require('path');
let config = require('../load-config');
function getPathForUserFile(fileId) {
return join(config.userFiles, `file-${fileId}.blob`);
}
function getPathForGroupFile(groupId) {
return join(config.userFiles, `group-${groupId}.sqlite`);
}
module.exports = { getPathForUserFile, getPathForGroupFile };

257
yarn.lock
View file

@ -2,19 +2,19 @@
# yarn lockfile v1
"@actual-app/api@4.1.0":
version "4.1.0"
resolved "https://registry.yarnpkg.com/@actual-app/api/-/api-4.1.0.tgz#43580a56a370a12dae5668b8d56c540c1849c4c9"
integrity sha512-8tLuA6zDnN0NjD9wui5fB/cSe0hr/iYWOHGyW/ikJoGPrCu8N8zIITz2FhfplD2QDszgAsTRt48H2YtPmR9plg==
"@actual-app/api@4.1.5":
version "4.1.5"
resolved "https://registry.yarnpkg.com/@actual-app/api/-/api-4.1.5.tgz#727f7e2233dd29204d2b7e244a671b3b88d0683a"
integrity sha512-rI4xqaHt9UNxovSPo8tukjluuESlxscMXUkImyYV4gYzAETsSFET3k0708Zw0EZsXCVanqAtfv+v84SNEBqn0A==
dependencies:
better-sqlite3 "^7.5.0"
node-fetch "^1.6.3"
uuid "3.3.2"
"@actual-app/web@4.1.0":
version "4.1.0"
resolved "https://registry.yarnpkg.com/@actual-app/web/-/web-4.1.0.tgz#9a5c5d5fd3c6e5a1a34dcaf087fb1920a27f13eb"
integrity sha512-QgxrHBUoDXsUCRzQTD4PmDkTt27UUcPfFJMqXPHtk2lP0ey7iVsZIW7AUeYkEs1+ghmqVVqk+jw3OAD4XQzbRA==
"@actual-app/web@22.12.3":
version "22.12.3"
resolved "https://registry.yarnpkg.com/@actual-app/web/-/web-22.12.3.tgz#e171fcd2bc3cdeea5cd87d879cc28986e3685a0f"
integrity sha512-Ii6xbISEfDlLP8X+ZUYwyINuiJF1r8PHGy83OZl9lx6IbBj+d81Z8l2Qv5fhizmqHin8JytfZt0dR7rmpduVRg==
"@eslint/eslintrc@^1.2.3":
version "1.2.3"
@ -183,13 +183,6 @@ abbrev@1:
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
accepts@~1.3.5:
version "1.3.5"
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2"
dependencies:
mime-types "~2.1.18"
negotiator "0.6.1"
accepts@~1.3.8:
version "1.3.8"
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
@ -208,11 +201,6 @@ acorn@^8.7.1:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30"
integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
adm-zip@^0.5.9:
version "0.5.9"
resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.5.9.tgz#b33691028333821c0cf95c31374c5462f2905a83"
integrity sha512-s+3fXLkeeLjZ2kLjCBwQufpI5fuN+kIGBxu6530nVQZGVol0d7Y/M88/xw9HGGUcJjKf8LutN3VPRUBq6N7Ajg==
agent-base@6:
version "6.0.2"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
@ -334,20 +322,21 @@ bl@^4.0.3:
inherits "^2.0.4"
readable-stream "^3.4.0"
body-parser@1.18.2:
version "1.18.2"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454"
body-parser@1.19.2:
version "1.19.2"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.2.tgz#4714ccd9c157d44797b8b5607d72c0b89952f26e"
integrity sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==
dependencies:
bytes "3.0.0"
bytes "3.1.2"
content-type "~1.0.4"
debug "2.6.9"
depd "~1.1.1"
http-errors "~1.6.2"
iconv-lite "0.4.19"
depd "~1.1.2"
http-errors "1.8.1"
iconv-lite "0.4.24"
on-finished "~2.3.0"
qs "6.5.1"
raw-body "2.3.2"
type-is "~1.6.15"
qs "6.9.7"
raw-body "2.4.3"
type-is "~1.6.18"
body-parser@1.20.0:
version "1.20.0"
@ -477,10 +466,6 @@ console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
content-disposition@0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
content-disposition@0.5.4:
version "0.5.4"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
@ -496,9 +481,10 @@ cookie-signature@1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
cookie@0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
cookie@0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
cookie@0.5.0:
version "0.5.0"
@ -569,16 +555,12 @@ delegates@^1.0.0:
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
depd@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359"
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==
depd@~1.1.1, depd@~1.1.2:
depd@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
@ -794,38 +776,39 @@ express-response-size@^0.0.3:
dependencies:
on-headers "1.0.1"
express@^4.16.3:
version "4.16.3"
resolved "http://registry.npmjs.org/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53"
express@4.17:
version "4.17.3"
resolved "https://registry.yarnpkg.com/express/-/express-4.17.3.tgz#f6c7302194a4fb54271b73a1fe7a06478c8f85a1"
integrity sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==
dependencies:
accepts "~1.3.5"
accepts "~1.3.8"
array-flatten "1.1.1"
body-parser "1.18.2"
content-disposition "0.5.2"
body-parser "1.19.2"
content-disposition "0.5.4"
content-type "~1.0.4"
cookie "0.3.1"
cookie "0.4.2"
cookie-signature "1.0.6"
debug "2.6.9"
depd "~1.1.2"
encodeurl "~1.0.2"
escape-html "~1.0.3"
etag "~1.8.1"
finalhandler "1.1.1"
finalhandler "~1.1.2"
fresh "0.5.2"
merge-descriptors "1.0.1"
methods "~1.1.2"
on-finished "~2.3.0"
parseurl "~1.3.2"
parseurl "~1.3.3"
path-to-regexp "0.1.7"
proxy-addr "~2.0.3"
qs "6.5.1"
range-parser "~1.2.0"
safe-buffer "5.1.1"
send "0.16.2"
serve-static "1.13.2"
setprototypeof "1.1.0"
statuses "~1.4.0"
type-is "~1.6.16"
proxy-addr "~2.0.7"
qs "6.9.7"
range-parser "~1.2.1"
safe-buffer "5.2.1"
send "0.17.2"
serve-static "1.14.2"
setprototypeof "1.2.0"
statuses "~1.5.0"
type-is "~1.6.18"
utils-merge "1.0.1"
vary "~1.1.2"
@ -923,18 +906,6 @@ fill-range@^7.0.1:
dependencies:
to-regex-range "^5.0.1"
finalhandler@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105"
dependencies:
debug "2.6.9"
encodeurl "~1.0.2"
escape-html "~1.0.3"
on-finished "~2.3.0"
parseurl "~1.3.2"
statuses "~1.4.0"
unpipe "~1.0.0"
finalhandler@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32"
@ -948,6 +919,19 @@ finalhandler@1.2.0:
statuses "2.0.1"
unpipe "~1.0.0"
finalhandler@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
dependencies:
debug "2.6.9"
encodeurl "~1.0.2"
escape-html "~1.0.3"
on-finished "~2.3.0"
parseurl "~1.3.3"
statuses "~1.5.0"
unpipe "~1.0.0"
flat-cache@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
@ -966,10 +950,6 @@ forwarded@0.2.0:
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
forwarded@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
fresh@0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
@ -1111,16 +1091,7 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
http-errors@1.6.2:
version "1.6.2"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736"
dependencies:
depd "1.1.1"
inherits "2.0.3"
setprototypeof "1.0.3"
statuses ">= 1.3.1 < 2"
http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3:
http-errors@1.6.3, http-errors@~1.6.3:
version "1.6.3"
resolved "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
dependencies:
@ -1129,6 +1100,17 @@ http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3:
setprototypeof "1.1.0"
statuses ">= 1.4.0 < 2"
http-errors@1.8.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c"
integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==
dependencies:
depd "~1.1.2"
inherits "2.0.4"
setprototypeof "1.2.0"
statuses ">= 1.5.0 < 2"
toidentifier "1.0.1"
http-errors@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
@ -1148,10 +1130,6 @@ https-proxy-agent@^5.0.0:
agent-base "6"
debug "4"
iconv-lite@0.4.19:
version "0.4.19"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
iconv-lite@0.4.23:
version "0.4.23"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
@ -1225,10 +1203,6 @@ ini@~1.3.0:
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
ipaddr.js@1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e"
ipaddr.js@1.9.1:
version "1.9.1"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
@ -1373,10 +1347,6 @@ mime-types@~2.1.24, mime-types@~2.1.34:
dependencies:
mime-db "1.52.0"
mime@1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
mime@1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
@ -1460,10 +1430,6 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
negotiator@0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
negotiator@0.6.3:
version "0.6.3"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
@ -1585,10 +1551,6 @@ parent-module@^1.0.0:
dependencies:
callsites "^3.0.0"
parseurl@~1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3"
parseurl@~1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
@ -1666,13 +1628,6 @@ properties-reader@^2.2.0:
dependencies:
mkdirp "^1.0.4"
proxy-addr@~2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93"
dependencies:
forwarded "~0.1.2"
ipaddr.js "1.8.0"
proxy-addr@~2.0.7:
version "2.0.7"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
@ -1701,37 +1656,25 @@ qs@6.10.3:
dependencies:
side-channel "^1.0.4"
qs@6.5.1:
version "6.5.1"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
qs@6.5.2:
version "6.5.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
qs@6.9.7:
version "6.9.7"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.7.tgz#4610846871485e1e048f44ae3b94033f0e675afe"
integrity sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==
queue-microtask@^1.2.2:
version "1.2.3"
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
range-parser@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
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.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89"
dependencies:
bytes "3.0.0"
http-errors "1.6.2"
iconv-lite "0.4.19"
unpipe "1.0.0"
raw-body@2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3"
@ -1741,6 +1684,16 @@ raw-body@2.3.3:
iconv-lite "0.4.23"
unpipe "1.0.0"
raw-body@2.4.3:
version "2.4.3"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.3.tgz#8f80305d11c2a0a545c2d9d89d7a0286fcead43c"
integrity sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==
dependencies:
bytes "3.1.2"
http-errors "1.8.1"
iconv-lite "0.4.24"
unpipe "1.0.0"
raw-body@2.5.1:
version "2.5.1"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857"
@ -1812,10 +1765,6 @@ run-parallel@^1.1.9:
dependencies:
queue-microtask "^1.2.2"
safe-buffer@5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
@ -1842,9 +1791,10 @@ semver@^7.3.5:
dependencies:
lru-cache "^6.0.0"
send@0.16.2:
version "0.16.2"
resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1"
send@0.17.2:
version "0.17.2"
resolved "https://registry.yarnpkg.com/send/-/send-0.17.2.tgz#926622f76601c41808012c8bf1688fe3906f7820"
integrity sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==
dependencies:
debug "2.6.9"
depd "~1.1.2"
@ -1853,12 +1803,12 @@ send@0.16.2:
escape-html "~1.0.3"
etag "~1.8.1"
fresh "0.5.2"
http-errors "~1.6.2"
mime "1.4.1"
ms "2.0.0"
http-errors "1.8.1"
mime "1.6.0"
ms "2.1.3"
on-finished "~2.3.0"
range-parser "~1.2.0"
statuses "~1.4.0"
range-parser "~1.2.1"
statuses "~1.5.0"
send@0.18.0:
version "0.18.0"
@ -1879,14 +1829,15 @@ send@0.18.0:
range-parser "~1.2.1"
statuses "2.0.1"
serve-static@1.13.2:
version "1.13.2"
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1"
serve-static@1.14.2:
version "1.14.2"
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.2.tgz#722d6294b1d62626d41b43a013ece4598d292bfa"
integrity sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==
dependencies:
encodeurl "~1.0.2"
escape-html "~1.0.3"
parseurl "~1.3.2"
send "0.16.2"
parseurl "~1.3.3"
send "0.17.2"
serve-static@1.15.0:
version "1.15.0"
@ -1903,10 +1854,6 @@ set-blocking@^2.0.0, set-blocking@~2.0.0:
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
setprototypeof@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04"
setprototypeof@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
@ -1966,14 +1913,10 @@ statuses@2.0.1:
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
"statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2":
"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
statuses@~1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
string-width@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
@ -2138,7 +2081,7 @@ type-fest@^0.20.2:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
type-is@~1.6.15, type-is@~1.6.16:
type-is@~1.6.16:
version "1.6.16"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194"
dependencies: