Compare commits
25 commits
Author | SHA1 | Date | |
---|---|---|---|
97081d46c4 | |||
60f83b334e | |||
340ac869ce | |||
b2b6ba4921 | |||
3274a06e34 | |||
e9850bfc56 | |||
529c42cccf | |||
2a00227486 | |||
5252edbf70 | |||
74c15b4f42 | |||
d482b9baf6 | |||
cde216523e | |||
8aeb815b5a | |||
3c602268e3 | |||
9177fb4d77 | |||
e3f1fafad9 | |||
32bf923c1a | |||
d3a0e8067e | |||
105d5007cf | |||
bafa486668 | |||
80a2b34d43 | |||
a5e1e38e74 | |||
0486e9e37b | |||
09722d8678 | |||
cd22e38660 |
12
.eslintrc.js
12
.eslintrc.js
|
@ -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'
|
||||
}
|
||||
};
|
||||
|
|
94
.github/workflows/build.yml
vendored
94
.github/workflows/build.yml
vendored
|
@ -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
93
.github/workflows/docker.yml
vendored
Normal 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 }}
|
|
@ -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({
|
||||
|
|
69
app-sync.js
69
app-sync.js
|
@ -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
4
app.js
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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 = []
|
||||
|
|
|
@ -16,4 +16,7 @@ try {
|
|||
};
|
||||
}
|
||||
|
||||
// The env variable always takes precedence
|
||||
config.userFiles = process.env.ACTUAL_USER_FILES || config.userFiles;
|
||||
|
||||
module.exports = config;
|
||||
|
|
|
@ -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('!');
|
||||
|
|
13
package.json
13
package.json
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -17,11 +17,11 @@ function sequential(fn) {
|
|||
sequenceState.running = fn(...args);
|
||||
|
||||
sequenceState.running.then(
|
||||
val => {
|
||||
(val) => {
|
||||
pump();
|
||||
resolve(val);
|
||||
},
|
||||
err => {
|
||||
(err) => {
|
||||
pump();
|
||||
reject(err);
|
||||
}
|
||||
|
|
|
@ -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' });
|
||||
}
|
||||
|
|
|
@ -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
12
util/paths.js
Normal 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
257
yarn.lock
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue