mirror of
https://github.com/standardnotes/server
synced 2026-05-12 06:57:20 -04:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2237e0f5df | |||
| 0df471585f | |||
| 95aac1a7bf | |||
| c078bc958d | |||
| 49c27924ea | |||
| c9dd8e7338 | |||
| 5ef90cc75b | |||
| 063c61d96c | |||
| 0cb5e36b20 | |||
| 319bab5b34 | |||
| 90a4f2111f | |||
| 3aba202970 | |||
| c8974b7fa2 | |||
| 3654a19586 | |||
| 5f0929c1aa | |||
| c0fa83bce6 | |||
| c201ee42a0 | |||
| e6a4cc3098 | |||
| 39f2fe2ba1 | |||
| 72ce190996 | |||
| 527dd1b61b | |||
| af8feaadfe | |||
| 3164f76662 | |||
| d6e531d4b6 |
@@ -4,6 +4,7 @@ DB_USERNAME=std_notes_user
|
|||||||
DB_PASSWORD=changeme123
|
DB_PASSWORD=changeme123
|
||||||
DB_DATABASE=standard_notes_db
|
DB_DATABASE=standard_notes_db
|
||||||
DB_PORT=3306
|
DB_PORT=3306
|
||||||
|
DB_SQLITE_DATABASE_PATH=standard_notes_db
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
REDIS_HOST=cache
|
REDIS_HOST=cache
|
||||||
AUTH_SERVER_ACCESS_TOKEN_AGE=4
|
AUTH_SERVER_ACCESS_TOKEN_AGE=4
|
||||||
|
|||||||
@@ -54,6 +54,11 @@ jobs:
|
|||||||
|
|
||||||
e2e-home-server:
|
e2e-home-server:
|
||||||
name: (Home Server) E2E Test Suite
|
name: (Home Server) E2E Test Suite
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
db_type: [mysql, sqlite]
|
||||||
|
cache_type: [redis, memory]
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
services:
|
services:
|
||||||
@@ -61,6 +66,19 @@ jobs:
|
|||||||
image: standardnotes/snjs:${{ inputs.snjs_image_tag }}
|
image: standardnotes/snjs:${{ inputs.snjs_image_tag }}
|
||||||
ports:
|
ports:
|
||||||
- 9001:9001
|
- 9001:9001
|
||||||
|
cache:
|
||||||
|
image: redis
|
||||||
|
ports:
|
||||||
|
- 6379:6379
|
||||||
|
db:
|
||||||
|
image: mysql
|
||||||
|
ports:
|
||||||
|
- 3306:3306
|
||||||
|
env:
|
||||||
|
MYSQL_ROOT_PASSWORD: root
|
||||||
|
MYSQL_DATABASE: standardnotes
|
||||||
|
MYSQL_USER: standardnotes
|
||||||
|
MYSQL_PASSWORD: standardnotes
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
@@ -90,6 +108,13 @@ jobs:
|
|||||||
echo "ACCESS_TOKEN_AGE=4" >> packages/home-server/.env
|
echo "ACCESS_TOKEN_AGE=4" >> packages/home-server/.env
|
||||||
echo "REFRESH_TOKEN_AGE=7" >> packages/home-server/.env
|
echo "REFRESH_TOKEN_AGE=7" >> packages/home-server/.env
|
||||||
echo "REVISIONS_FREQUENCY=5" >> packages/home-server/.env
|
echo "REVISIONS_FREQUENCY=5" >> packages/home-server/.env
|
||||||
|
echo "DB_HOST=db" >> packages/home-server/.env
|
||||||
|
echo "DB_PORT=3306" >> packages/home-server/.env
|
||||||
|
echo "DB_USERNAME=standardnotes" >> packages/home-server/.env
|
||||||
|
echo "DB_PASSWORD=standardnotes" >> packages/home-server/.env
|
||||||
|
echo "DB_TYPE=${{ matrix.db_type }}" >> packages/home-server/.env
|
||||||
|
echo "REDIS_URL=redis://cache" >> packages/home-server/.env
|
||||||
|
echo "CACHE_TYPE=${{ matrix.cache_type }}" >> packages/home-server/.env
|
||||||
|
|
||||||
- name: Run Server
|
- name: Run Server
|
||||||
run: nohup yarn workspace @standardnotes/home-server start &
|
run: nohup yarn workspace @standardnotes/home-server start &
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
MODE=microservice # microservice | home-server
|
||||||
LOG_LEVEL=debug
|
LOG_LEVEL=debug
|
||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
VERSION=development
|
VERSION=development
|
||||||
|
|||||||
@@ -3,6 +3,24 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.64.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.64.1...@standardnotes/api-gateway@1.64.2) (2023-06-22)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **home-server:** add debug logs about container initalizations ([0df4715](https://github.com/standardnotes/api-gateway/commit/0df471585fd5b4626ec2972f3b9a3e33b2830e65))
|
||||||
|
|
||||||
|
## [1.64.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.64.0...@standardnotes/api-gateway@1.64.1) (2023-06-09)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** direct call service proxy to return 400 responses instead of throwing errors ([e6a4cc3](https://github.com/standardnotes/api-gateway/commit/e6a4cc3098bdf84fc9d48ed0d9098ebb52afb0e7))
|
||||||
|
|
||||||
|
# [1.64.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.63.2...@standardnotes/api-gateway@1.64.0) (2023-06-05)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **home-server:** allow running the home server with a mysql and redis configuration ([#622](https://github.com/standardnotes/api-gateway/issues/622)) ([d6e531d](https://github.com/standardnotes/api-gateway/commit/d6e531d4b6c1c80a894f6d7ec93632595268dd64))
|
||||||
|
|
||||||
## [1.63.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.63.1...@standardnotes/api-gateway@1.63.2) (2023-06-02)
|
## [1.63.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.63.1...@standardnotes/api-gateway@1.63.2) (2023-06-02)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/api-gateway",
|
"name": "@standardnotes/api-gateway",
|
||||||
"version": "1.63.2",
|
"version": "1.64.2",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ export class ContainerConfigLoader {
|
|||||||
|
|
||||||
const container = new Container()
|
const container = new Container()
|
||||||
|
|
||||||
const isConfiguredForHomeServer = env.get('CACHE_TYPE') === 'memory'
|
const isConfiguredForHomeServer = env.get('MODE', true) === 'home-server'
|
||||||
|
const isConfiguredForInMemoryCache = env.get('CACHE_TYPE', true) === 'memory'
|
||||||
|
|
||||||
const winstonFormatters = [winston.format.splat(), winston.format.json()]
|
const winstonFormatters = [winston.format.splat(), winston.format.json()]
|
||||||
if (env.get('NEW_RELIC_ENABLED', true) === 'true') {
|
if (env.get('NEW_RELIC_ENABLED', true) === 'true') {
|
||||||
@@ -45,19 +46,20 @@ export class ContainerConfigLoader {
|
|||||||
winstonFormatters.push(newrelicWinstonFormatter())
|
winstonFormatters.push(newrelicWinstonFormatter())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let logger: winston.Logger
|
||||||
if (configuration?.logger) {
|
if (configuration?.logger) {
|
||||||
container.bind<winston.Logger>(TYPES.Logger).toConstantValue(configuration.logger as winston.Logger)
|
logger = configuration.logger as winston.Logger
|
||||||
} else {
|
} else {
|
||||||
const logger = winston.createLogger({
|
logger = winston.createLogger({
|
||||||
level: env.get('LOG_LEVEL', true) || 'info',
|
level: env.get('LOG_LEVEL', true) || 'info',
|
||||||
format: winston.format.combine(...winstonFormatters),
|
format: winston.format.combine(...winstonFormatters),
|
||||||
transports: [new winston.transports.Console({ level: env.get('LOG_LEVEL', true) || 'info' })],
|
transports: [new winston.transports.Console({ level: env.get('LOG_LEVEL', true) || 'info' })],
|
||||||
defaultMeta: { service: 'api-gateway' },
|
defaultMeta: { service: 'api-gateway' },
|
||||||
})
|
})
|
||||||
container.bind<winston.Logger>(TYPES.Logger).toConstantValue(logger)
|
|
||||||
}
|
}
|
||||||
|
container.bind<winston.Logger>(TYPES.Logger).toConstantValue(logger)
|
||||||
|
|
||||||
if (!isConfiguredForHomeServer) {
|
if (!isConfiguredForInMemoryCache) {
|
||||||
const redisUrl = env.get('REDIS_URL')
|
const redisUrl = env.get('REDIS_URL')
|
||||||
const isRedisInClusterMode = redisUrl.indexOf(',') > 0
|
const isRedisInClusterMode = redisUrl.indexOf(',') > 0
|
||||||
let redis
|
let redis
|
||||||
@@ -124,6 +126,8 @@ export class ContainerConfigLoader {
|
|||||||
.bind<EndpointResolverInterface>(TYPES.EndpointResolver)
|
.bind<EndpointResolverInterface>(TYPES.EndpointResolver)
|
||||||
.toConstantValue(new EndpointResolver(isConfiguredForHomeServer))
|
.toConstantValue(new EndpointResolver(isConfiguredForHomeServer))
|
||||||
|
|
||||||
|
logger.debug('Configuration complete')
|
||||||
|
|
||||||
return container
|
return container
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Request, Response } from 'express'
|
import { Request, Response } from 'express'
|
||||||
|
import { ServiceContainerInterface, ServiceIdentifier } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
import { ServiceProxyInterface } from '../Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../Http/ServiceProxyInterface'
|
||||||
import { ServiceContainerInterface, ServiceIdentifier } from '@standardnotes/domain-core'
|
|
||||||
|
|
||||||
export class DirectCallServiceProxy implements ServiceProxyInterface {
|
export class DirectCallServiceProxy implements ServiceProxyInterface {
|
||||||
constructor(private serviceContainer: ServiceContainerInterface, private filesServerUrl: string) {}
|
constructor(private serviceContainer: ServiceContainerInterface, private filesServerUrl: string) {}
|
||||||
@@ -34,8 +34,12 @@ export class DirectCallServiceProxy implements ServiceProxyInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async callEmailServer(_request: Request, _response: Response, _endpointOrMethodIdentifier: string): Promise<void> {
|
async callEmailServer(_request: Request, response: Response, _endpointOrMethodIdentifier: string): Promise<void> {
|
||||||
throw new Error('Email server is not available.')
|
response.status(400).send({
|
||||||
|
error: {
|
||||||
|
message: 'Email server is not available.',
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async callAuthServer(request: never, response: never, endpointOrMethodIdentifier: string): Promise<void> {
|
async callAuthServer(request: never, response: never, endpointOrMethodIdentifier: string): Promise<void> {
|
||||||
@@ -54,10 +58,14 @@ export class DirectCallServiceProxy implements ServiceProxyInterface {
|
|||||||
|
|
||||||
async callAuthServerWithLegacyFormat(
|
async callAuthServerWithLegacyFormat(
|
||||||
_request: Request,
|
_request: Request,
|
||||||
_response: Response,
|
response: Response,
|
||||||
_endpointOrMethodIdentifier: string,
|
_endpointOrMethodIdentifier: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
throw new Error('Legacy auth endpoints are no longer available.')
|
response.status(400).send({
|
||||||
|
error: {
|
||||||
|
message: 'Legacy auth endpoints are no longer available.',
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async callRevisionsServer(request: never, response: never, endpointOrMethodIdentifier: string): Promise<void> {
|
async callRevisionsServer(request: never, response: never, endpointOrMethodIdentifier: string): Promise<void> {
|
||||||
@@ -92,22 +100,30 @@ export class DirectCallServiceProxy implements ServiceProxyInterface {
|
|||||||
|
|
||||||
async callLegacySyncingServer(
|
async callLegacySyncingServer(
|
||||||
_request: Request,
|
_request: Request,
|
||||||
_response: Response,
|
response: Response,
|
||||||
_endpointOrMethodIdentifier: string,
|
_endpointOrMethodIdentifier: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
throw new Error('Legacy syncing server endpoints are no longer available.')
|
response.status(400).send({
|
||||||
|
error: {
|
||||||
|
message: 'Legacy syncing server endpoints are no longer available.',
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async callPaymentsServer(_request: Request, _response: Response, _endpointOrMethodIdentifier: string): Promise<void> {
|
async callPaymentsServer(_request: Request, response: Response, _endpointOrMethodIdentifier: string): Promise<void> {
|
||||||
throw new Error('Payments server is not available.')
|
response.status(400).send({
|
||||||
|
error: {
|
||||||
|
message: 'Payments server is not available.',
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async callWebSocketServer(
|
async callWebSocketServer(_request: Request, response: Response, _endpointOrMethodIdentifier: string): Promise<void> {
|
||||||
_request: Request,
|
response.status(400).send({
|
||||||
_response: Response,
|
error: {
|
||||||
_endpointOrMethodIdentifier: string,
|
message: 'Websockets server is not available.',
|
||||||
): Promise<void> {
|
},
|
||||||
throw new Error('Websockets server is not available.')
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private sendDecoratedResponse(
|
private sendDecoratedResponse(
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
MODE=microservice # microservice | home-server
|
||||||
LOG_LEVEL=debug
|
LOG_LEVEL=debug
|
||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
VERSION=development
|
VERSION=development
|
||||||
@@ -20,8 +21,10 @@ DB_USERNAME=auth
|
|||||||
DB_PASSWORD=changeme123
|
DB_PASSWORD=changeme123
|
||||||
DB_DATABASE=auth
|
DB_DATABASE=auth
|
||||||
DB_DEBUG_LEVEL=all # "all" | "query" | "schema" | "error" | "warn" | "info" | "log" | "migration"
|
DB_DEBUG_LEVEL=all # "all" | "query" | "schema" | "error" | "warn" | "info" | "log" | "migration"
|
||||||
|
DB_TYPE=mysql
|
||||||
|
|
||||||
REDIS_URL=redis://cache
|
REDIS_URL=redis://cache
|
||||||
|
CACHE_TYPE=redis
|
||||||
|
|
||||||
DISABLE_USER_REGISTRATION=false
|
DISABLE_USER_REGISTRATION=false
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,42 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.119.3](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.119.2...@standardnotes/auth-server@1.119.3) (2023-06-22)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **home-server:** add debug logs about container initalizations ([0df4715](https://github.com/standardnotes/server/commit/0df471585fd5b4626ec2972f3b9a3e33b2830e65))
|
||||||
|
|
||||||
|
## [1.119.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.119.1...@standardnotes/auth-server@1.119.2) (2023-06-14)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **home-server:** env var determining the sqlite database location ([#626](https://github.com/standardnotes/server/issues/626)) ([0cb5e36](https://github.com/standardnotes/server/commit/0cb5e36b20d9b095ea0edbcd877387e6c0069856))
|
||||||
|
|
||||||
|
## [1.119.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.119.0...@standardnotes/auth-server@1.119.1) (2023-06-09)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **home-server:** add default value for valet token ttl ([c201ee4](https://github.com/standardnotes/server/commit/c201ee42a00d9e5402afea2f2c5848a362c1529e))
|
||||||
|
|
||||||
|
# [1.119.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.118.0...@standardnotes/auth-server@1.119.0) (2023-06-09)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **home-server:** add activating premium features ([#624](https://github.com/standardnotes/server/issues/624)) ([72ce190](https://github.com/standardnotes/server/commit/72ce1909960fbd2ec6a47b8dbdfbe53a4f10e776))
|
||||||
|
|
||||||
|
# [1.118.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.117.0...@standardnotes/auth-server@1.118.0) (2023-06-07)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* configurable path for uploads and db ([#623](https://github.com/standardnotes/server/issues/623)) ([af8feaa](https://github.com/standardnotes/server/commit/af8feaadfe2dd58baab4cca217d6307b4a221326))
|
||||||
|
|
||||||
|
# [1.117.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.116.2...@standardnotes/auth-server@1.117.0) (2023-06-05)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **home-server:** allow running the home server with a mysql and redis configuration ([#622](https://github.com/standardnotes/server/issues/622)) ([d6e531d](https://github.com/standardnotes/server/commit/d6e531d4b6c1c80a894f6d7ec93632595268dd64))
|
||||||
|
|
||||||
## [1.116.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.116.1...@standardnotes/auth-server@1.116.2) (2023-06-02)
|
## [1.116.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.116.1...@standardnotes/auth-server@1.116.2) (2023-06-02)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/auth-server",
|
"name": "@standardnotes/auth-server",
|
||||||
"version": "1.116.2",
|
"version": "1.119.3",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { Result, ServiceInterface } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
|
export interface AuthServiceInterface extends ServiceInterface {
|
||||||
|
activatePremiumFeatures(username: string): Promise<Result<string>>
|
||||||
|
}
|
||||||
@@ -251,6 +251,7 @@ import { HomeServerValetTokenController } from '../Infra/InversifyExpressUtils/H
|
|||||||
import { HomeServerWebSocketsController } from '../Infra/InversifyExpressUtils/HomeServer/HomeServerWebSocketsController'
|
import { HomeServerWebSocketsController } from '../Infra/InversifyExpressUtils/HomeServer/HomeServerWebSocketsController'
|
||||||
import { HomeServerSessionsController } from '../Infra/InversifyExpressUtils/HomeServer/HomeServerSessionsController'
|
import { HomeServerSessionsController } from '../Infra/InversifyExpressUtils/HomeServer/HomeServerSessionsController'
|
||||||
import { Transform } from 'stream'
|
import { Transform } from 'stream'
|
||||||
|
import { ActivatePremiumFeatures } from '../Domain/UseCase/ActivatePremiumFeatures/ActivatePremiumFeatures'
|
||||||
|
|
||||||
export class ContainerConfigLoader {
|
export class ContainerConfigLoader {
|
||||||
async load(configuration?: {
|
async load(configuration?: {
|
||||||
@@ -267,12 +268,37 @@ export class ContainerConfigLoader {
|
|||||||
|
|
||||||
const container = new Container()
|
const container = new Container()
|
||||||
|
|
||||||
|
const winstonFormatters = [winston.format.splat(), winston.format.json()]
|
||||||
|
if (env.get('NEW_RELIC_ENABLED', true) === 'true') {
|
||||||
|
await import('newrelic')
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
const newrelicFormatter = require('@newrelic/winston-enricher')
|
||||||
|
const newrelicWinstonFormatter = newrelicFormatter(winston)
|
||||||
|
winstonFormatters.push(newrelicWinstonFormatter())
|
||||||
|
}
|
||||||
|
|
||||||
|
let logger: winston.Logger
|
||||||
|
if (configuration?.logger) {
|
||||||
|
logger = configuration.logger as winston.Logger
|
||||||
|
} else {
|
||||||
|
logger = winston.createLogger({
|
||||||
|
level: env.get('LOG_LEVEL', true) || 'info',
|
||||||
|
format: winston.format.combine(...winstonFormatters),
|
||||||
|
transports: [new winston.transports.Console({ level: env.get('LOG_LEVEL', true) || 'info' })],
|
||||||
|
defaultMeta: { service: 'auth' },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
container.bind<winston.Logger>(TYPES.Auth_Logger).toConstantValue(logger)
|
||||||
|
|
||||||
const appDataSource = new AppDataSource(env)
|
const appDataSource = new AppDataSource(env)
|
||||||
await appDataSource.initialize()
|
await appDataSource.initialize()
|
||||||
|
|
||||||
const isConfiguredForHomeServer = env.get('DB_TYPE') === 'sqlite'
|
logger.debug('Database initialized')
|
||||||
|
|
||||||
if (!isConfiguredForHomeServer) {
|
const isConfiguredForHomeServer = env.get('MODE', true) === 'home-server'
|
||||||
|
const isConfiguredForInMemoryCache = env.get('CACHE_TYPE', true) === 'memory'
|
||||||
|
|
||||||
|
if (!isConfiguredForInMemoryCache) {
|
||||||
const redisUrl = env.get('REDIS_URL')
|
const redisUrl = env.get('REDIS_URL')
|
||||||
const isRedisInClusterMode = redisUrl.indexOf(',') > 0
|
const isRedisInClusterMode = redisUrl.indexOf(',') > 0
|
||||||
let redis
|
let redis
|
||||||
@@ -285,27 +311,6 @@ export class ContainerConfigLoader {
|
|||||||
container.bind(TYPES.Auth_Redis).toConstantValue(redis)
|
container.bind(TYPES.Auth_Redis).toConstantValue(redis)
|
||||||
}
|
}
|
||||||
|
|
||||||
const winstonFormatters = [winston.format.splat(), winston.format.json()]
|
|
||||||
if (env.get('NEW_RELIC_ENABLED', true) === 'true') {
|
|
||||||
await import('newrelic')
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
||||||
const newrelicFormatter = require('@newrelic/winston-enricher')
|
|
||||||
const newrelicWinstonFormatter = newrelicFormatter(winston)
|
|
||||||
winstonFormatters.push(newrelicWinstonFormatter())
|
|
||||||
}
|
|
||||||
|
|
||||||
if (configuration?.logger) {
|
|
||||||
container.bind<winston.Logger>(TYPES.Auth_Logger).toConstantValue(configuration.logger as winston.Logger)
|
|
||||||
} else {
|
|
||||||
const logger = winston.createLogger({
|
|
||||||
level: env.get('LOG_LEVEL', true) || 'info',
|
|
||||||
format: winston.format.combine(...winstonFormatters),
|
|
||||||
transports: [new winston.transports.Console({ level: env.get('LOG_LEVEL', true) || 'info' })],
|
|
||||||
defaultMeta: { service: 'auth' },
|
|
||||||
})
|
|
||||||
container.bind<winston.Logger>(TYPES.Auth_Logger).toConstantValue(logger)
|
|
||||||
}
|
|
||||||
|
|
||||||
container.bind<TimerInterface>(TYPES.Auth_Timer).toConstantValue(new Timer())
|
container.bind<TimerInterface>(TYPES.Auth_Timer).toConstantValue(new Timer())
|
||||||
|
|
||||||
if (!isConfiguredForHomeServer) {
|
if (!isConfiguredForHomeServer) {
|
||||||
@@ -488,7 +493,9 @@ export class ContainerConfigLoader {
|
|||||||
.bind(TYPES.Auth_AUTH_JWT_TTL)
|
.bind(TYPES.Auth_AUTH_JWT_TTL)
|
||||||
.toConstantValue(env.get('AUTH_JWT_TTL', true) ? +env.get('AUTH_JWT_TTL') : 60_000)
|
.toConstantValue(env.get('AUTH_JWT_TTL', true) ? +env.get('AUTH_JWT_TTL') : 60_000)
|
||||||
container.bind(TYPES.Auth_VALET_TOKEN_SECRET).toConstantValue(env.get('VALET_TOKEN_SECRET', true))
|
container.bind(TYPES.Auth_VALET_TOKEN_SECRET).toConstantValue(env.get('VALET_TOKEN_SECRET', true))
|
||||||
container.bind(TYPES.Auth_VALET_TOKEN_TTL).toConstantValue(+env.get('VALET_TOKEN_TTL', true))
|
container
|
||||||
|
.bind(TYPES.Auth_VALET_TOKEN_TTL)
|
||||||
|
.toConstantValue(env.get('VALET_TOKEN_TTL', true) ? +env.get('VALET_TOKEN_TTL', true) : 7200)
|
||||||
container
|
container
|
||||||
.bind(TYPES.Auth_WEB_SOCKET_CONNECTION_TOKEN_SECRET)
|
.bind(TYPES.Auth_WEB_SOCKET_CONNECTION_TOKEN_SECRET)
|
||||||
.toConstantValue(env.get('WEB_SOCKET_CONNECTION_TOKEN_SECRET', true))
|
.toConstantValue(env.get('WEB_SOCKET_CONNECTION_TOKEN_SECRET', true))
|
||||||
@@ -550,7 +557,16 @@ export class ContainerConfigLoader {
|
|||||||
.bind(TYPES.Auth_READONLY_USERS)
|
.bind(TYPES.Auth_READONLY_USERS)
|
||||||
.toConstantValue(env.get('READONLY_USERS', true) ? env.get('READONLY_USERS', true).split(',') : [])
|
.toConstantValue(env.get('READONLY_USERS', true) ? env.get('READONLY_USERS', true).split(',') : [])
|
||||||
|
|
||||||
if (isConfiguredForHomeServer) {
|
if (isConfiguredForInMemoryCache) {
|
||||||
|
container
|
||||||
|
.bind<PKCERepositoryInterface>(TYPES.Auth_PKCERepository)
|
||||||
|
.toConstantValue(
|
||||||
|
new TypeORMPKCERepository(
|
||||||
|
container.get(TYPES.Auth_CacheEntryRepository),
|
||||||
|
container.get(TYPES.Auth_Logger),
|
||||||
|
container.get(TYPES.Auth_Timer),
|
||||||
|
),
|
||||||
|
)
|
||||||
container
|
container
|
||||||
.bind<LockRepositoryInterface>(TYPES.Auth_LockRepository)
|
.bind<LockRepositoryInterface>(TYPES.Auth_LockRepository)
|
||||||
.toConstantValue(
|
.toConstantValue(
|
||||||
@@ -578,15 +594,6 @@ export class ContainerConfigLoader {
|
|||||||
container.get(TYPES.Auth_Timer),
|
container.get(TYPES.Auth_Timer),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
container
|
|
||||||
.bind<PKCERepositoryInterface>(TYPES.Auth_PKCERepository)
|
|
||||||
.toConstantValue(
|
|
||||||
new TypeORMPKCERepository(
|
|
||||||
container.get(TYPES.Auth_CacheEntryRepository),
|
|
||||||
container.get(TYPES.Auth_Logger),
|
|
||||||
container.get(TYPES.Auth_Timer),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
container
|
container
|
||||||
.bind<SubscriptionTokenRepositoryInterface>(TYPES.Auth_SubscriptionTokenRepository)
|
.bind<SubscriptionTokenRepositoryInterface>(TYPES.Auth_SubscriptionTokenRepository)
|
||||||
.toConstantValue(
|
.toConstantValue(
|
||||||
@@ -780,6 +787,16 @@ export class ContainerConfigLoader {
|
|||||||
container.get(TYPES.Auth_CryptoNode),
|
container.get(TYPES.Auth_CryptoNode),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
container
|
||||||
|
.bind<ActivatePremiumFeatures>(TYPES.Auth_ActivatePremiumFeatures)
|
||||||
|
.toConstantValue(
|
||||||
|
new ActivatePremiumFeatures(
|
||||||
|
container.get(TYPES.Auth_UserRepository),
|
||||||
|
container.get(TYPES.Auth_UserSubscriptionRepository),
|
||||||
|
container.get(TYPES.Auth_RoleService),
|
||||||
|
container.get(TYPES.Auth_Timer),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
container
|
container
|
||||||
.bind<CleanupSessionTraces>(TYPES.Auth_CleanupSessionTraces)
|
.bind<CleanupSessionTraces>(TYPES.Auth_CleanupSessionTraces)
|
||||||
@@ -1187,6 +1204,8 @@ export class ContainerConfigLoader {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.debug('Configuration complete')
|
||||||
|
|
||||||
return container
|
return container
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ export class AppDataSource {
|
|||||||
const sqliteDataSourceOptions: SqliteConnectionOptions = {
|
const sqliteDataSourceOptions: SqliteConnectionOptions = {
|
||||||
...commonDataSourceOptions,
|
...commonDataSourceOptions,
|
||||||
type: 'sqlite',
|
type: 'sqlite',
|
||||||
database: `data/${this.env.get('DB_DATABASE')}.sqlite`,
|
database: this.env.get('DB_SQLITE_DATABASE_PATH'),
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dataSource = new DataSource(sqliteDataSourceOptions)
|
this.dataSource = new DataSource(sqliteDataSourceOptions)
|
||||||
|
|||||||
@@ -1,15 +1,21 @@
|
|||||||
import {
|
import {
|
||||||
ControllerContainerInterface,
|
ControllerContainerInterface,
|
||||||
|
Result,
|
||||||
ServiceConfiguration,
|
ServiceConfiguration,
|
||||||
ServiceContainerInterface,
|
ServiceContainerInterface,
|
||||||
ServiceIdentifier,
|
ServiceIdentifier,
|
||||||
ServiceInterface,
|
|
||||||
} from '@standardnotes/domain-core'
|
} from '@standardnotes/domain-core'
|
||||||
|
|
||||||
import { ContainerConfigLoader } from './Container'
|
import { ContainerConfigLoader } from './Container'
|
||||||
import { DirectCallDomainEventPublisher } from '@standardnotes/domain-events-infra'
|
import { DirectCallDomainEventPublisher } from '@standardnotes/domain-events-infra'
|
||||||
|
import TYPES from './Types'
|
||||||
|
import { Container } from 'inversify'
|
||||||
|
import { ActivatePremiumFeatures } from '../Domain/UseCase/ActivatePremiumFeatures/ActivatePremiumFeatures'
|
||||||
|
import { AuthServiceInterface } from './AuthServiceInterface'
|
||||||
|
|
||||||
|
export class Service implements AuthServiceInterface {
|
||||||
|
private container: Container | undefined
|
||||||
|
|
||||||
export class Service implements ServiceInterface {
|
|
||||||
constructor(
|
constructor(
|
||||||
private serviceContainer: ServiceContainerInterface,
|
private serviceContainer: ServiceContainerInterface,
|
||||||
private controllerContainer: ControllerContainerInterface,
|
private controllerContainer: ControllerContainerInterface,
|
||||||
@@ -18,6 +24,16 @@ export class Service implements ServiceInterface {
|
|||||||
this.serviceContainer.register(this.getId(), this)
|
this.serviceContainer.register(this.getId(), this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async activatePremiumFeatures(username: string): Promise<Result<string>> {
|
||||||
|
if (!this.container) {
|
||||||
|
return Result.fail('Container not initialized')
|
||||||
|
}
|
||||||
|
|
||||||
|
const activatePremiumFeatures = this.container.get(TYPES.Auth_ActivatePremiumFeatures) as ActivatePremiumFeatures
|
||||||
|
|
||||||
|
return activatePremiumFeatures.execute({ username })
|
||||||
|
}
|
||||||
|
|
||||||
async handleRequest(request: never, response: never, endpointOrMethodIdentifier: string): Promise<unknown> {
|
async handleRequest(request: never, response: never, endpointOrMethodIdentifier: string): Promise<unknown> {
|
||||||
const method = this.controllerContainer.get(endpointOrMethodIdentifier)
|
const method = this.controllerContainer.get(endpointOrMethodIdentifier)
|
||||||
|
|
||||||
@@ -31,12 +47,16 @@ export class Service implements ServiceInterface {
|
|||||||
async getContainer(configuration?: ServiceConfiguration): Promise<unknown> {
|
async getContainer(configuration?: ServiceConfiguration): Promise<unknown> {
|
||||||
const config = new ContainerConfigLoader()
|
const config = new ContainerConfigLoader()
|
||||||
|
|
||||||
return config.load({
|
const container = await config.load({
|
||||||
controllerConatiner: this.controllerContainer,
|
controllerConatiner: this.controllerContainer,
|
||||||
directCallDomainEventPublisher: this.directCallDomainEventPublisher,
|
directCallDomainEventPublisher: this.directCallDomainEventPublisher,
|
||||||
logger: configuration?.logger,
|
logger: configuration?.logger,
|
||||||
environmentOverrides: configuration?.environmentOverrides,
|
environmentOverrides: configuration?.environmentOverrides,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.container = container
|
||||||
|
|
||||||
|
return container
|
||||||
}
|
}
|
||||||
|
|
||||||
getId(): ServiceIdentifier {
|
getId(): ServiceIdentifier {
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ const TYPES = {
|
|||||||
Auth_ListAuthenticators: Symbol.for('Auth_ListAuthenticators'),
|
Auth_ListAuthenticators: Symbol.for('Auth_ListAuthenticators'),
|
||||||
Auth_DeleteAuthenticator: Symbol.for('Auth_DeleteAuthenticator'),
|
Auth_DeleteAuthenticator: Symbol.for('Auth_DeleteAuthenticator'),
|
||||||
Auth_GenerateRecoveryCodes: Symbol.for('Auth_GenerateRecoveryCodes'),
|
Auth_GenerateRecoveryCodes: Symbol.for('Auth_GenerateRecoveryCodes'),
|
||||||
|
Auth_ActivatePremiumFeatures: Symbol.for('Auth_ActivatePremiumFeatures'),
|
||||||
Auth_SignInWithRecoveryCodes: Symbol.for('Auth_SignInWithRecoveryCodes'),
|
Auth_SignInWithRecoveryCodes: Symbol.for('Auth_SignInWithRecoveryCodes'),
|
||||||
Auth_GetUserKeyParamsRecovery: Symbol.for('Auth_GetUserKeyParamsRecovery'),
|
Auth_GetUserKeyParamsRecovery: Symbol.for('Auth_GetUserKeyParamsRecovery'),
|
||||||
// Handlers
|
// Handlers
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
|
export * from './AuthServiceInterface'
|
||||||
export * from './Service'
|
export * from './Service'
|
||||||
|
|||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
import { TimerInterface } from '@standardnotes/time'
|
||||||
|
import { RoleServiceInterface } from '../../Role/RoleServiceInterface'
|
||||||
|
import { UserSubscriptionRepositoryInterface } from '../../Subscription/UserSubscriptionRepositoryInterface'
|
||||||
|
import { UserRepositoryInterface } from '../../User/UserRepositoryInterface'
|
||||||
|
|
||||||
|
import { ActivatePremiumFeatures } from './ActivatePremiumFeatures'
|
||||||
|
import { User } from '../../User/User'
|
||||||
|
|
||||||
|
describe('ActivatePremiumFeatures', () => {
|
||||||
|
let userRepository: UserRepositoryInterface
|
||||||
|
let userSubscriptionRepository: UserSubscriptionRepositoryInterface
|
||||||
|
let roleService: RoleServiceInterface
|
||||||
|
let timer: TimerInterface
|
||||||
|
let user: User
|
||||||
|
|
||||||
|
const createUseCase = () =>
|
||||||
|
new ActivatePremiumFeatures(userRepository, userSubscriptionRepository, roleService, timer)
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
user = {} as jest.Mocked<User>
|
||||||
|
|
||||||
|
userRepository = {} as jest.Mocked<UserRepositoryInterface>
|
||||||
|
userRepository.findOneByUsernameOrEmail = jest.fn().mockResolvedValue(user)
|
||||||
|
|
||||||
|
userSubscriptionRepository = {} as jest.Mocked<UserSubscriptionRepositoryInterface>
|
||||||
|
userSubscriptionRepository.save = jest.fn()
|
||||||
|
|
||||||
|
roleService = {} as jest.Mocked<RoleServiceInterface>
|
||||||
|
roleService.addUserRole = jest.fn()
|
||||||
|
|
||||||
|
timer = {} as jest.Mocked<TimerInterface>
|
||||||
|
timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(123456789)
|
||||||
|
timer.convertDateToMicroseconds = jest.fn().mockReturnValue(123456789)
|
||||||
|
timer.getUTCDateNDaysAhead = jest.fn().mockReturnValue(new Date('2024-01-01T00:00:00.000Z'))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return error when username is invalid', async () => {
|
||||||
|
const useCase = createUseCase()
|
||||||
|
|
||||||
|
const result = await useCase.execute({ username: '' })
|
||||||
|
|
||||||
|
expect(result.isFailed()).toBe(true)
|
||||||
|
expect(result.getError()).toBe('Username cannot be empty')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return error when user is not found', async () => {
|
||||||
|
userRepository.findOneByUsernameOrEmail = jest.fn().mockResolvedValue(null)
|
||||||
|
|
||||||
|
const useCase = createUseCase()
|
||||||
|
|
||||||
|
const result = await useCase.execute({ username: 'test@test.te' })
|
||||||
|
|
||||||
|
expect(result.isFailed()).toBe(true)
|
||||||
|
expect(result.getError()).toBe('User not found with username: test@test.te')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should save a subscription and add role to user', async () => {
|
||||||
|
const useCase = createUseCase()
|
||||||
|
|
||||||
|
const result = await useCase.execute({ username: 'test@test.te' })
|
||||||
|
|
||||||
|
expect(result.isFailed()).toBe(false)
|
||||||
|
|
||||||
|
expect(userSubscriptionRepository.save).toHaveBeenCalled()
|
||||||
|
expect(roleService.addUserRole).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import { Result, SubscriptionPlanName, UseCaseInterface, Username } from '@standardnotes/domain-core'
|
||||||
|
import { TimerInterface } from '@standardnotes/time'
|
||||||
|
|
||||||
|
import { RoleServiceInterface } from '../../Role/RoleServiceInterface'
|
||||||
|
import { UserSubscriptionRepositoryInterface } from '../../Subscription/UserSubscriptionRepositoryInterface'
|
||||||
|
import { UserRepositoryInterface } from '../../User/UserRepositoryInterface'
|
||||||
|
import { UserSubscription } from '../../Subscription/UserSubscription'
|
||||||
|
import { UserSubscriptionType } from '../../Subscription/UserSubscriptionType'
|
||||||
|
import { ActivatePremiumFeaturesDTO } from './ActivatePremiumFeaturesDTO'
|
||||||
|
|
||||||
|
export class ActivatePremiumFeatures implements UseCaseInterface<string> {
|
||||||
|
constructor(
|
||||||
|
private userRepository: UserRepositoryInterface,
|
||||||
|
private userSubscriptionRepository: UserSubscriptionRepositoryInterface,
|
||||||
|
private roleService: RoleServiceInterface,
|
||||||
|
private timer: TimerInterface,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async execute(dto: ActivatePremiumFeaturesDTO): Promise<Result<string>> {
|
||||||
|
const usernameOrError = Username.create(dto.username)
|
||||||
|
if (usernameOrError.isFailed()) {
|
||||||
|
return Result.fail(usernameOrError.getError())
|
||||||
|
}
|
||||||
|
const username = usernameOrError.getValue()
|
||||||
|
|
||||||
|
const user = await this.userRepository.findOneByUsernameOrEmail(username)
|
||||||
|
if (user === null) {
|
||||||
|
return Result.fail(`User not found with username: ${username.value}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const timestamp = this.timer.getTimestampInMicroseconds()
|
||||||
|
|
||||||
|
const subscription = new UserSubscription()
|
||||||
|
subscription.planName = SubscriptionPlanName.NAMES.ProPlan
|
||||||
|
subscription.user = Promise.resolve(user)
|
||||||
|
subscription.createdAt = timestamp
|
||||||
|
subscription.updatedAt = timestamp
|
||||||
|
subscription.endsAt = this.timer.convertDateToMicroseconds(this.timer.getUTCDateNDaysAhead(365))
|
||||||
|
subscription.cancelled = false
|
||||||
|
subscription.subscriptionId = 1
|
||||||
|
subscription.subscriptionType = UserSubscriptionType.Regular
|
||||||
|
|
||||||
|
await this.userSubscriptionRepository.save(subscription)
|
||||||
|
|
||||||
|
await this.roleService.addUserRole(user, SubscriptionPlanName.NAMES.ProPlan)
|
||||||
|
|
||||||
|
return Result.ok('Premium features activated.')
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export interface ActivatePremiumFeaturesDTO {
|
||||||
|
username: string
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
MODE=microservice # microservice | home-server
|
||||||
LOG_LEVEL=debug
|
LOG_LEVEL=debug
|
||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
VERSION=development
|
VERSION=development
|
||||||
|
|||||||
@@ -3,6 +3,30 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.18.3](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.18.2...@standardnotes/files-server@1.18.3) (2023-06-22)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **home-server:** add debug logs about container initalizations ([0df4715](https://github.com/standardnotes/files/commit/0df471585fd5b4626ec2972f3b9a3e33b2830e65))
|
||||||
|
|
||||||
|
## [1.18.2](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.18.1...@standardnotes/files-server@1.18.2) (2023-06-12)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **home-server:** accept application/octet-stream requests for files ([#625](https://github.com/standardnotes/files/issues/625)) ([c8974b7](https://github.com/standardnotes/files/commit/c8974b7fa229ff4f1e026e1ebff50d1081cc5f8b))
|
||||||
|
|
||||||
|
## [1.18.1](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.18.0...@standardnotes/files-server@1.18.1) (2023-06-09)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **files:** add debug logs for checking chunks upon finishing upload session ([5f0929c](https://github.com/standardnotes/files/commit/5f0929c1aa7b83661fb102bad34644db69ddf7eb))
|
||||||
|
|
||||||
|
# [1.18.0](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.17.1...@standardnotes/files-server@1.18.0) (2023-06-05)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **home-server:** allow running the home server with a mysql and redis configuration ([#622](https://github.com/standardnotes/files/issues/622)) ([d6e531d](https://github.com/standardnotes/files/commit/d6e531d4b6c1c80a894f6d7ec93632595268dd64))
|
||||||
|
|
||||||
## [1.17.1](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.17.0...@standardnotes/files-server@1.17.1) (2023-06-02)
|
## [1.17.1](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.17.0...@standardnotes/files-server@1.17.1) (2023-06-02)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/files-server",
|
"name": "@standardnotes/files-server",
|
||||||
"version": "1.17.1",
|
"version": "1.18.3",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -67,30 +67,24 @@ export class ContainerConfigLoader {
|
|||||||
await import('newrelic')
|
await import('newrelic')
|
||||||
}
|
}
|
||||||
|
|
||||||
const isConfiguredForHomeServer = env.get('CACHE_TYPE') === 'memory'
|
const isConfiguredForHomeServer = env.get('MODE', true) === 'home-server'
|
||||||
|
const isConfiguredForInMemoryCache = env.get('CACHE_TYPE', true) === 'memory'
|
||||||
|
|
||||||
|
let logger: winston.Logger
|
||||||
if (configuration?.logger) {
|
if (configuration?.logger) {
|
||||||
container.bind<winston.Logger>(TYPES.Files_Logger).toConstantValue(configuration.logger as winston.Logger)
|
logger = configuration.logger as winston.Logger
|
||||||
} else {
|
} else {
|
||||||
container.bind<winston.Logger>(TYPES.Files_Logger).toConstantValue(this.createLogger({ env }))
|
logger = this.createLogger({ env })
|
||||||
}
|
}
|
||||||
|
container.bind<winston.Logger>(TYPES.Files_Logger).toConstantValue(logger)
|
||||||
|
|
||||||
container.bind<TimerInterface>(TYPES.Files_Timer).toConstantValue(new Timer())
|
container.bind<TimerInterface>(TYPES.Files_Timer).toConstantValue(new Timer())
|
||||||
|
|
||||||
if (isConfiguredForHomeServer) {
|
if (isConfiguredForInMemoryCache) {
|
||||||
container
|
container
|
||||||
.bind<UploadRepositoryInterface>(TYPES.Files_UploadRepository)
|
.bind<UploadRepositoryInterface>(TYPES.Files_UploadRepository)
|
||||||
.toConstantValue(new InMemoryUploadRepository(container.get(TYPES.Files_Timer)))
|
.toConstantValue(new InMemoryUploadRepository(container.get(TYPES.Files_Timer)))
|
||||||
|
|
||||||
container
|
|
||||||
.bind<DomainEventPublisherInterface>(TYPES.Files_DomainEventPublisher)
|
|
||||||
.toConstantValue(directCallDomainEventPublisher)
|
|
||||||
} else {
|
} else {
|
||||||
container.bind(TYPES.Files_S3_BUCKET_NAME).toConstantValue(env.get('S3_BUCKET_NAME', true))
|
|
||||||
container.bind(TYPES.Files_S3_AWS_REGION).toConstantValue(env.get('S3_AWS_REGION', true))
|
|
||||||
container.bind(TYPES.Files_SNS_TOPIC_ARN).toConstantValue(env.get('SNS_TOPIC_ARN'))
|
|
||||||
container.bind(TYPES.Files_SNS_AWS_REGION).toConstantValue(env.get('SNS_AWS_REGION', true))
|
|
||||||
container.bind(TYPES.Files_SQS_QUEUE_URL).toConstantValue(env.get('SQS_QUEUE_URL'))
|
|
||||||
container.bind(TYPES.Files_REDIS_URL).toConstantValue(env.get('REDIS_URL'))
|
container.bind(TYPES.Files_REDIS_URL).toConstantValue(env.get('REDIS_URL'))
|
||||||
|
|
||||||
const redisUrl = container.get(TYPES.Files_REDIS_URL) as string
|
const redisUrl = container.get(TYPES.Files_REDIS_URL) as string
|
||||||
@@ -104,6 +98,20 @@ export class ContainerConfigLoader {
|
|||||||
|
|
||||||
container.bind(TYPES.Files_Redis).toConstantValue(redis)
|
container.bind(TYPES.Files_Redis).toConstantValue(redis)
|
||||||
|
|
||||||
|
container.bind<UploadRepositoryInterface>(TYPES.Files_UploadRepository).to(RedisUploadRepository)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isConfiguredForHomeServer) {
|
||||||
|
container
|
||||||
|
.bind<DomainEventPublisherInterface>(TYPES.Files_DomainEventPublisher)
|
||||||
|
.toConstantValue(directCallDomainEventPublisher)
|
||||||
|
} else {
|
||||||
|
container.bind(TYPES.Files_S3_BUCKET_NAME).toConstantValue(env.get('S3_BUCKET_NAME', true))
|
||||||
|
container.bind(TYPES.Files_S3_AWS_REGION).toConstantValue(env.get('S3_AWS_REGION', true))
|
||||||
|
container.bind(TYPES.Files_SNS_TOPIC_ARN).toConstantValue(env.get('SNS_TOPIC_ARN'))
|
||||||
|
container.bind(TYPES.Files_SNS_AWS_REGION).toConstantValue(env.get('SNS_AWS_REGION', true))
|
||||||
|
container.bind(TYPES.Files_SQS_QUEUE_URL).toConstantValue(env.get('SQS_QUEUE_URL'))
|
||||||
|
|
||||||
if (env.get('SNS_TOPIC_ARN', true)) {
|
if (env.get('SNS_TOPIC_ARN', true)) {
|
||||||
const snsConfig: SNSClientConfig = {
|
const snsConfig: SNSClientConfig = {
|
||||||
apiVersion: 'latest',
|
apiVersion: 'latest',
|
||||||
@@ -137,8 +145,6 @@ export class ContainerConfigLoader {
|
|||||||
container.bind<SQSClient>(TYPES.Files_SQS).toConstantValue(new SQSClient(sqsConfig))
|
container.bind<SQSClient>(TYPES.Files_SQS).toConstantValue(new SQSClient(sqsConfig))
|
||||||
}
|
}
|
||||||
|
|
||||||
container.bind<UploadRepositoryInterface>(TYPES.Files_UploadRepository).to(RedisUploadRepository)
|
|
||||||
|
|
||||||
container
|
container
|
||||||
.bind<DomainEventPublisherInterface>(TYPES.Files_DomainEventPublisher)
|
.bind<DomainEventPublisherInterface>(TYPES.Files_DomainEventPublisher)
|
||||||
.toConstantValue(
|
.toConstantValue(
|
||||||
@@ -156,7 +162,7 @@ export class ContainerConfigLoader {
|
|||||||
.bind(TYPES.Files_FILE_UPLOAD_PATH)
|
.bind(TYPES.Files_FILE_UPLOAD_PATH)
|
||||||
.toConstantValue(env.get('FILE_UPLOAD_PATH', true) ?? `${__dirname}/../../uploads`)
|
.toConstantValue(env.get('FILE_UPLOAD_PATH', true) ?? `${__dirname}/../../uploads`)
|
||||||
|
|
||||||
if (env.get('S3_AWS_REGION', true) || env.get('S3_ENDPOINT', true)) {
|
if (!isConfiguredForHomeServer && (env.get('S3_AWS_REGION', true) || env.get('S3_ENDPOINT', true))) {
|
||||||
const s3Opts: S3ClientConfig = {
|
const s3Opts: S3ClientConfig = {
|
||||||
apiVersion: 'latest',
|
apiVersion: 'latest',
|
||||||
}
|
}
|
||||||
@@ -245,6 +251,8 @@ export class ContainerConfigLoader {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.debug('Configuration complete')
|
||||||
|
|
||||||
return container
|
return container
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,24 @@ describe('UploadFileChunk', () => {
|
|||||||
logger.warn = jest.fn()
|
logger.warn = jest.fn()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should not upload a data chunk with 0 bytes', async () => {
|
||||||
|
expect(
|
||||||
|
await createUseCase().execute({
|
||||||
|
chunkId: 2,
|
||||||
|
data: new Uint8Array([]),
|
||||||
|
resourceRemoteIdentifier: '2-3-4',
|
||||||
|
resourceUnencryptedFileSize: 123,
|
||||||
|
userUuid: '1-2-3',
|
||||||
|
}),
|
||||||
|
).toEqual({
|
||||||
|
success: false,
|
||||||
|
message: 'Empty file chunk',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(fileUploader.uploadFileChunk).not.toHaveBeenCalled()
|
||||||
|
expect(uploadRepository.storeUploadChunkResult).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
it('should not upload a data chunk to a non existing file upload session', async () => {
|
it('should not upload a data chunk to a non existing file upload session', async () => {
|
||||||
uploadRepository.retrieveUploadSessionId = jest.fn().mockReturnValue(undefined)
|
uploadRepository.retrieveUploadSessionId = jest.fn().mockReturnValue(undefined)
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,17 @@ export class UploadFileChunk implements UseCaseInterface {
|
|||||||
|
|
||||||
async execute(dto: UploadFileChunkDTO): Promise<UploadFileChunkResponse> {
|
async execute(dto: UploadFileChunkDTO): Promise<UploadFileChunkResponse> {
|
||||||
try {
|
try {
|
||||||
|
if (!dto.data.byteLength || dto.data.byteLength === 0) {
|
||||||
|
this.logger.debug(
|
||||||
|
`Skipping upload file chunk ${dto.chunkId} with 0 bytes for resource: ${dto.resourceRemoteIdentifier}`,
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: 'Empty file chunk',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`Starting upload file chunk ${dto.chunkId} with ${dto.data.byteLength} bytes for resource: ${dto.resourceRemoteIdentifier}`,
|
`Starting upload file chunk ${dto.chunkId} with ${dto.data.byteLength} bytes for resource: ${dto.resourceRemoteIdentifier}`,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -39,7 +39,9 @@ export class FSFileUploader implements FileUploaderInterface {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.debug(`FS storing file chunk ${dto.chunkId} in memory for ${dto.uploadId}`)
|
this.logger.debug(
|
||||||
|
`FS storing file chunk ${dto.chunkId} in memory for ${dto.uploadId}: ${dto.data}, ${dto.data.byteLength}`,
|
||||||
|
)
|
||||||
|
|
||||||
fileChunks.set(dto.chunkId, dto.data)
|
fileChunks.set(dto.chunkId, dto.data)
|
||||||
|
|
||||||
@@ -60,7 +62,14 @@ export class FSFileUploader implements FileUploaderInterface {
|
|||||||
|
|
||||||
const orderedKeys = [...fileChunks.keys()].sort((a, b) => a - b)
|
const orderedKeys = [...fileChunks.keys()].sort((a, b) => a - b)
|
||||||
for (const orderedKey of orderedKeys) {
|
for (const orderedKey of orderedKeys) {
|
||||||
await promises.appendFile(`${this.fileUploadPath}/${filePath}`, fileChunks.get(orderedKey) as Uint8Array)
|
const chunk = fileChunks.get(orderedKey)
|
||||||
|
if (!chunk || chunk.byteLength === 0) {
|
||||||
|
throw new Error(`Could not find chunk ${orderedKey} for upload ${uploadId}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.debug(`FS writing chunk ${orderedKey} for ${uploadId}: ${chunk.toString()} ${chunk.byteLength}}`)
|
||||||
|
|
||||||
|
await promises.appendFile(`${this.fileUploadPath}/${filePath}`, chunk)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.inMemoryChunks.delete(uploadId)
|
this.inMemoryChunks.delete(uploadId)
|
||||||
|
|||||||
@@ -3,6 +3,69 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.11.8](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.11.7...@standardnotes/home-server@1.11.8) (2023-06-22)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **home-server:** add debug logs about container initalizations ([0df4715](https://github.com/standardnotes/server/commit/0df471585fd5b4626ec2972f3b9a3e33b2830e65))
|
||||||
|
|
||||||
|
## [1.11.7](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.11.6...@standardnotes/home-server@1.11.7) (2023-06-22)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **home-server:** add default log level to overrides ([c078bc9](https://github.com/standardnotes/server/commit/c078bc958d96e856f6e607406d5d817d422572fb))
|
||||||
|
* **home-server:** add log leve information to starting the home server information ([49c2792](https://github.com/standardnotes/server/commit/49c27924eafa50c164854946053fd95e6429df9e))
|
||||||
|
|
||||||
|
## [1.11.6](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.11.5...@standardnotes/home-server@1.11.6) (2023-06-16)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **home-server:** unref the server instance when stopping the home server ([5ef90cc](https://github.com/standardnotes/server/commit/5ef90cc75b44133bf8065ce16f36d5b347c68122))
|
||||||
|
|
||||||
|
## [1.11.5](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.11.4...@standardnotes/home-server@1.11.5) (2023-06-14)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **home-server:** env var determining the sqlite database location ([#626](https://github.com/standardnotes/server/issues/626)) ([0cb5e36](https://github.com/standardnotes/server/commit/0cb5e36b20d9b095ea0edbcd877387e6c0069856))
|
||||||
|
|
||||||
|
## [1.11.4](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.11.3...@standardnotes/home-server@1.11.4) (2023-06-13)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **home-server:** encapsulate starting the server with a result return ([90a4f21](https://github.com/standardnotes/server/commit/90a4f2111f9e050e5fb500261c3e43eacc5622e4))
|
||||||
|
|
||||||
|
## [1.11.3](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.11.2...@standardnotes/home-server@1.11.3) (2023-06-12)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **home-server:** accept application/octet-stream requests for files ([#625](https://github.com/standardnotes/server/issues/625)) ([c8974b7](https://github.com/standardnotes/server/commit/c8974b7fa229ff4f1e026e1ebff50d1081cc5f8b))
|
||||||
|
|
||||||
|
## [1.11.2](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.11.1...@standardnotes/home-server@1.11.2) (2023-06-09)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/home-server
|
||||||
|
|
||||||
|
## [1.11.1](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.11.0...@standardnotes/home-server@1.11.1) (2023-06-09)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/home-server
|
||||||
|
|
||||||
|
# [1.11.0](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.10.0...@standardnotes/home-server@1.11.0) (2023-06-09)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **home-server:** add activating premium features ([#624](https://github.com/standardnotes/server/issues/624)) ([72ce190](https://github.com/standardnotes/server/commit/72ce1909960fbd2ec6a47b8dbdfbe53a4f10e776))
|
||||||
|
|
||||||
|
# [1.10.0](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.9.0...@standardnotes/home-server@1.10.0) (2023-06-07)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* configurable path for uploads and db ([#623](https://github.com/standardnotes/server/issues/623)) ([af8feaa](https://github.com/standardnotes/server/commit/af8feaadfe2dd58baab4cca217d6307b4a221326))
|
||||||
|
|
||||||
|
# [1.9.0](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.8.5...@standardnotes/home-server@1.9.0) (2023-06-05)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **home-server:** allow running the home server with a mysql and redis configuration ([#622](https://github.com/standardnotes/server/issues/622)) ([d6e531d](https://github.com/standardnotes/server/commit/d6e531d4b6c1c80a894f6d7ec93632595268dd64))
|
||||||
|
|
||||||
## [1.8.5](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.8.4...@standardnotes/home-server@1.8.5) (2023-06-02)
|
## [1.8.5](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.8.4...@standardnotes/home-server@1.8.5) (2023-06-02)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { HomeServer } from '../src/Server/HomeServer'
|
|||||||
|
|
||||||
const homeServer = new HomeServer()
|
const homeServer = new HomeServer()
|
||||||
|
|
||||||
Promise.resolve(homeServer.start())
|
Promise.resolve(homeServer.start({ dataDirectoryPath: `${__dirname}/../data` }))
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const logStream = homeServer.logs()
|
const logStream = homeServer.logs()
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/home-server",
|
"name": "@standardnotes/home-server",
|
||||||
"version": "1.8.5",
|
"version": "1.11.8",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import 'reflect-metadata'
|
import 'reflect-metadata'
|
||||||
|
|
||||||
import { ControllerContainer, ServiceContainer } from '@standardnotes/domain-core'
|
import { ControllerContainer, Result, ServiceContainer } from '@standardnotes/domain-core'
|
||||||
import { Service as ApiGatewayService } from '@standardnotes/api-gateway'
|
import { Service as ApiGatewayService } from '@standardnotes/api-gateway'
|
||||||
import { Service as FilesService } from '@standardnotes/files-server'
|
import { Service as FilesService } from '@standardnotes/files-server'
|
||||||
import { DirectCallDomainEventPublisher } from '@standardnotes/domain-events-infra'
|
import { DirectCallDomainEventPublisher } from '@standardnotes/domain-events-infra'
|
||||||
import { Service as AuthService } from '@standardnotes/auth-server'
|
import { Service as AuthService, AuthServiceInterface } from '@standardnotes/auth-server'
|
||||||
import { Service as SyncingService } from '@standardnotes/syncing-server'
|
import { Service as SyncingService } from '@standardnotes/syncing-server'
|
||||||
import { Service as RevisionsService } from '@standardnotes/revisions-server'
|
import { Service as RevisionsService } from '@standardnotes/revisions-server'
|
||||||
import { Container } from 'inversify'
|
import { Container } from 'inversify'
|
||||||
@@ -12,7 +12,7 @@ import { InversifyExpressServer } from 'inversify-express-utils'
|
|||||||
import helmet from 'helmet'
|
import helmet from 'helmet'
|
||||||
import * as cors from 'cors'
|
import * as cors from 'cors'
|
||||||
import * as http from 'http'
|
import * as http from 'http'
|
||||||
import { text, json, Request, Response, NextFunction } from 'express'
|
import { text, json, Request, Response, NextFunction, raw } from 'express'
|
||||||
import * as winston from 'winston'
|
import * as winston from 'winston'
|
||||||
import { PassThrough } from 'stream'
|
import { PassThrough } from 'stream'
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
@@ -24,121 +24,155 @@ import { HomeServerConfiguration } from './HomeServerConfiguration'
|
|||||||
|
|
||||||
export class HomeServer implements HomeServerInterface {
|
export class HomeServer implements HomeServerInterface {
|
||||||
private serverInstance: http.Server | undefined
|
private serverInstance: http.Server | undefined
|
||||||
|
private authService: AuthServiceInterface | undefined
|
||||||
private logStream: PassThrough = new PassThrough()
|
private logStream: PassThrough = new PassThrough()
|
||||||
|
|
||||||
async start(configuration?: HomeServerConfiguration): Promise<void> {
|
async start(configuration: HomeServerConfiguration): Promise<Result<string>> {
|
||||||
const controllerContainer = new ControllerContainer()
|
try {
|
||||||
const serviceContainer = new ServiceContainer()
|
const controllerContainer = new ControllerContainer()
|
||||||
const directCallDomainEventPublisher = new DirectCallDomainEventPublisher()
|
const serviceContainer = new ServiceContainer()
|
||||||
|
const directCallDomainEventPublisher = new DirectCallDomainEventPublisher()
|
||||||
|
|
||||||
const environmentOverrides = {
|
const environmentOverrides = {
|
||||||
...configuration?.environment,
|
DB_TYPE: 'sqlite',
|
||||||
NEW_RELIC_ENABLED: 'false',
|
CACHE_TYPE: 'memory',
|
||||||
NEW_RELIC_APP_NAME: 'Home Server',
|
DB_SQLITE_DATABASE_PATH: `${configuration.dataDirectoryPath}/database/home_server.sqlite`,
|
||||||
CACHE_TYPE: 'memory',
|
FILE_UPLOAD_PATH: `${configuration.dataDirectoryPath}/uploads`,
|
||||||
DB_TYPE: 'sqlite',
|
...configuration.environment,
|
||||||
DB_DATABASE: 'home_server',
|
MODE: 'home-server',
|
||||||
}
|
NEW_RELIC_ENABLED: 'false',
|
||||||
|
NEW_RELIC_APP_NAME: 'Home Server',
|
||||||
|
}
|
||||||
|
|
||||||
const env: Env = new Env(environmentOverrides)
|
const env: Env = new Env(environmentOverrides)
|
||||||
env.load()
|
env.load()
|
||||||
|
|
||||||
this.configureLoggers(env)
|
this.configureLoggers(env)
|
||||||
|
|
||||||
const apiGatewayService = new ApiGatewayService(serviceContainer)
|
const apiGatewayService = new ApiGatewayService(serviceContainer)
|
||||||
const authService = new AuthService(serviceContainer, controllerContainer, directCallDomainEventPublisher)
|
const authService = new AuthService(serviceContainer, controllerContainer, directCallDomainEventPublisher)
|
||||||
const syncingService = new SyncingService(serviceContainer, controllerContainer, directCallDomainEventPublisher)
|
this.authService = authService
|
||||||
const revisionsService = new RevisionsService(serviceContainer, controllerContainer, directCallDomainEventPublisher)
|
const syncingService = new SyncingService(serviceContainer, controllerContainer, directCallDomainEventPublisher)
|
||||||
const filesService = new FilesService(serviceContainer, directCallDomainEventPublisher)
|
const revisionsService = new RevisionsService(
|
||||||
|
serviceContainer,
|
||||||
|
controllerContainer,
|
||||||
|
directCallDomainEventPublisher,
|
||||||
|
)
|
||||||
|
const filesService = new FilesService(serviceContainer, directCallDomainEventPublisher)
|
||||||
|
|
||||||
const container = Container.merge(
|
const container = Container.merge(
|
||||||
(await apiGatewayService.getContainer({
|
(await apiGatewayService.getContainer({
|
||||||
logger: winston.loggers.get('api-gateway'),
|
logger: winston.loggers.get('api-gateway'),
|
||||||
environmentOverrides,
|
environmentOverrides,
|
||||||
})) as Container,
|
})) as Container,
|
||||||
(await authService.getContainer({
|
(await authService.getContainer({
|
||||||
logger: winston.loggers.get('auth-server'),
|
logger: winston.loggers.get('auth-server'),
|
||||||
environmentOverrides,
|
environmentOverrides,
|
||||||
})) as Container,
|
})) as Container,
|
||||||
(await syncingService.getContainer({
|
(await syncingService.getContainer({
|
||||||
logger: winston.loggers.get('syncing-server'),
|
logger: winston.loggers.get('syncing-server'),
|
||||||
environmentOverrides,
|
environmentOverrides,
|
||||||
})) as Container,
|
})) as Container,
|
||||||
(await revisionsService.getContainer({
|
(await revisionsService.getContainer({
|
||||||
logger: winston.loggers.get('revisions-server'),
|
logger: winston.loggers.get('revisions-server'),
|
||||||
environmentOverrides,
|
environmentOverrides,
|
||||||
})) as Container,
|
})) as Container,
|
||||||
(await filesService.getContainer({
|
(await filesService.getContainer({
|
||||||
logger: winston.loggers.get('files-server'),
|
logger: winston.loggers.get('files-server'),
|
||||||
environmentOverrides,
|
environmentOverrides,
|
||||||
})) as Container,
|
})) as Container,
|
||||||
)
|
)
|
||||||
|
|
||||||
const server = new InversifyExpressServer(container)
|
const server = new InversifyExpressServer(container)
|
||||||
|
|
||||||
server.setConfig((app) => {
|
server.setConfig((app) => {
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
app.use(helmet({
|
app.use(helmet({
|
||||||
contentSecurityPolicy: {
|
contentSecurityPolicy: {
|
||||||
directives: {
|
directives: {
|
||||||
defaultSrc: ["https: 'self'"],
|
defaultSrc: ["https: 'self'"],
|
||||||
baseUri: ["'self'"],
|
baseUri: ["'self'"],
|
||||||
childSrc: ["*", "blob:"],
|
childSrc: ["*", "blob:"],
|
||||||
connectSrc: ["*"],
|
connectSrc: ["*"],
|
||||||
fontSrc: ["*", "'self'"],
|
fontSrc: ["*", "'self'"],
|
||||||
formAction: ["'self'"],
|
formAction: ["'self'"],
|
||||||
frameAncestors: ["*", "*.standardnotes.org", "*.standardnotes.com"],
|
frameAncestors: ["*", "*.standardnotes.org", "*.standardnotes.com"],
|
||||||
frameSrc: ["*", "blob:"],
|
frameSrc: ["*", "blob:"],
|
||||||
imgSrc: ["'self'", "*", "data:"],
|
imgSrc: ["'self'", "*", "data:"],
|
||||||
manifestSrc: ["'self'"],
|
manifestSrc: ["'self'"],
|
||||||
mediaSrc: ["'self'"],
|
mediaSrc: ["'self'"],
|
||||||
objectSrc: ["'self'"],
|
objectSrc: ["'self'"],
|
||||||
scriptSrc: ["'self'"],
|
scriptSrc: ["'self'"],
|
||||||
styleSrc: ["'self'"]
|
styleSrc: ["'self'"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}))
|
||||||
}))
|
/* eslint-enable */
|
||||||
/* eslint-enable */
|
app.use(json({ limit: '50mb' }))
|
||||||
app.use(json({ limit: '50mb' }))
|
app.use(raw({ limit: '50mb', type: 'application/octet-stream' }))
|
||||||
app.use(
|
app.use(
|
||||||
text({
|
text({
|
||||||
type: ['text/plain', 'application/x-www-form-urlencoded', 'application/x-www-form-urlencoded; charset=utf-8'],
|
type: [
|
||||||
}),
|
'text/plain',
|
||||||
)
|
'application/x-www-form-urlencoded',
|
||||||
app.use(cors())
|
'application/x-www-form-urlencoded; charset=utf-8',
|
||||||
app.use(
|
],
|
||||||
robots({
|
}),
|
||||||
UserAgent: '*',
|
)
|
||||||
Disallow: '/',
|
app.use(
|
||||||
}),
|
cors({
|
||||||
)
|
exposedHeaders: ['Content-Range', 'Accept-Ranges'],
|
||||||
})
|
}),
|
||||||
|
)
|
||||||
|
app.use(
|
||||||
|
robots({
|
||||||
|
UserAgent: '*',
|
||||||
|
Disallow: '/',
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
const logger: winston.Logger = winston.loggers.get('home-server')
|
const logger: winston.Logger = winston.loggers.get('home-server')
|
||||||
|
|
||||||
server.setErrorConfig((app) => {
|
server.setErrorConfig((app) => {
|
||||||
app.use((error: Record<string, unknown>, _request: Request, response: Response, _next: NextFunction) => {
|
app.use((error: Record<string, unknown>, _request: Request, response: Response, _next: NextFunction) => {
|
||||||
logger.error(error.stack)
|
logger.error(error.stack)
|
||||||
|
|
||||||
response.status(500).send({
|
response.status(500).send({
|
||||||
error: {
|
error: {
|
||||||
message:
|
message:
|
||||||
"Unfortunately, we couldn't handle your request. Please try again or contact our support if the error persists.",
|
"Unfortunately, we couldn't handle your request. Please try again or contact our support if the error persists.",
|
||||||
},
|
},
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
const port = env.get('PORT', true) ? +env.get('PORT', true) : 3000
|
const port = env.get('PORT', true) ? +env.get('PORT', true) : 3000
|
||||||
|
|
||||||
this.serverInstance = server.build().listen(port)
|
this.serverInstance = server.build().listen(port)
|
||||||
|
|
||||||
logger.info(`Server started on port ${port}`)
|
logger.info(`Server started on port ${port}. Log level: ${env.get('LOG_LEVEL', true)}.`)
|
||||||
|
|
||||||
|
return Result.ok('Server started.')
|
||||||
|
} catch (error) {
|
||||||
|
return Result.fail((error as Error).message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async stop(): Promise<void> {
|
async stop(): Promise<Result<string>> {
|
||||||
if (this.serverInstance) {
|
try {
|
||||||
|
if (!this.serverInstance) {
|
||||||
|
return Result.fail('Home server is not running.')
|
||||||
|
}
|
||||||
|
|
||||||
this.serverInstance.close()
|
this.serverInstance.close()
|
||||||
|
this.serverInstance.unref()
|
||||||
|
|
||||||
|
this.serverInstance = undefined
|
||||||
|
|
||||||
|
return Result.ok('Server stopped.')
|
||||||
|
} catch (error) {
|
||||||
|
return Result.fail((error as Error).message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,6 +184,14 @@ export class HomeServer implements HomeServerInterface {
|
|||||||
return this.serverInstance.address() !== null
|
return this.serverInstance.address() !== null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async activatePremiumFeatures(username: string): Promise<Result<string>> {
|
||||||
|
if (!this.isRunning() || !this.authService) {
|
||||||
|
return Result.fail('Home server is not running.')
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.authService.activatePremiumFeatures(username)
|
||||||
|
}
|
||||||
|
|
||||||
logs(): NodeJS.ReadableStream {
|
logs(): NodeJS.ReadableStream {
|
||||||
return this.logStream
|
return this.logStream
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
export interface HomeServerConfiguration {
|
export interface HomeServerConfiguration {
|
||||||
environment: { [name: string]: string }
|
dataDirectoryPath: string
|
||||||
|
environment?: { [name: string]: string }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
import { Result } from '@standardnotes/domain-core'
|
||||||
import { HomeServerConfiguration } from './HomeServerConfiguration'
|
import { HomeServerConfiguration } from './HomeServerConfiguration'
|
||||||
|
|
||||||
export interface HomeServerInterface {
|
export interface HomeServerInterface {
|
||||||
start(configuration?: HomeServerConfiguration): Promise<void>
|
start(configuration?: HomeServerConfiguration): Promise<Result<string>>
|
||||||
stop(): Promise<void>
|
activatePremiumFeatures(username: string): Promise<Result<string>>
|
||||||
|
stop(): Promise<Result<string>>
|
||||||
isRunning(): Promise<boolean>
|
isRunning(): Promise<boolean>
|
||||||
logs(): NodeJS.ReadableStream
|
logs(): NodeJS.ReadableStream
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
MODE=microservice # microservice | home-server
|
||||||
LOG_LEVEL=info
|
LOG_LEVEL=info
|
||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
VERSION=development
|
VERSION=development
|
||||||
@@ -14,8 +15,10 @@ DB_PASSWORD=revisionspassword
|
|||||||
DB_DATABASE=revisions
|
DB_DATABASE=revisions
|
||||||
DB_DEBUG_LEVEL=all # "all" | "query" | "schema" | "error" | "warn" | "info" | "log" | "migration"
|
DB_DEBUG_LEVEL=all # "all" | "query" | "schema" | "error" | "warn" | "info" | "log" | "migration"
|
||||||
DB_MIGRATIONS_PATH=dist/migrations/*.js
|
DB_MIGRATIONS_PATH=dist/migrations/*.js
|
||||||
|
DB_TYPE=mysql
|
||||||
|
|
||||||
REDIS_URL=redis://cache
|
REDIS_URL=redis://cache
|
||||||
|
CACHE_TYPE=redis
|
||||||
|
|
||||||
SQS_QUEUE_URL=
|
SQS_QUEUE_URL=
|
||||||
SQS_AWS_REGION=
|
SQS_AWS_REGION=
|
||||||
|
|||||||
@@ -3,6 +3,30 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.23.2](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.23.1...@standardnotes/revisions-server@1.23.2) (2023-06-22)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **home-server:** add debug logs about container initalizations ([0df4715](https://github.com/standardnotes/server/commit/0df471585fd5b4626ec2972f3b9a3e33b2830e65))
|
||||||
|
|
||||||
|
## [1.23.1](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.23.0...@standardnotes/revisions-server@1.23.1) (2023-06-14)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **home-server:** env var determining the sqlite database location ([#626](https://github.com/standardnotes/server/issues/626)) ([0cb5e36](https://github.com/standardnotes/server/commit/0cb5e36b20d9b095ea0edbcd877387e6c0069856))
|
||||||
|
|
||||||
|
# [1.23.0](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.22.0...@standardnotes/revisions-server@1.23.0) (2023-06-07)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* configurable path for uploads and db ([#623](https://github.com/standardnotes/server/issues/623)) ([af8feaa](https://github.com/standardnotes/server/commit/af8feaadfe2dd58baab4cca217d6307b4a221326))
|
||||||
|
|
||||||
|
# [1.22.0](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.21.3...@standardnotes/revisions-server@1.22.0) (2023-06-05)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **home-server:** allow running the home server with a mysql and redis configuration ([#622](https://github.com/standardnotes/server/issues/622)) ([d6e531d](https://github.com/standardnotes/server/commit/d6e531d4b6c1c80a894f6d7ec93632595268dd64))
|
||||||
|
|
||||||
## [1.21.3](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.21.2...@standardnotes/revisions-server@1.21.3) (2023-06-02)
|
## [1.21.3](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.21.2...@standardnotes/revisions-server@1.21.3) (2023-06-02)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/revisions-server",
|
"name": "@standardnotes/revisions-server",
|
||||||
"version": "1.21.3",
|
"version": "1.23.2",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -61,19 +61,15 @@ export class ContainerConfigLoader {
|
|||||||
const env: Env = new Env(configuration?.environmentOverrides)
|
const env: Env = new Env(configuration?.environmentOverrides)
|
||||||
env.load()
|
env.load()
|
||||||
|
|
||||||
const isConfiguredForHomeServer = env.get('DB_TYPE') === 'sqlite'
|
const isConfiguredForHomeServer = env.get('MODE', true) === 'home-server'
|
||||||
|
|
||||||
const container = new Container({
|
const container = new Container({
|
||||||
defaultScope: 'Singleton',
|
defaultScope: 'Singleton',
|
||||||
})
|
})
|
||||||
|
|
||||||
const appDataSource = new AppDataSource(env)
|
let logger: winston.Logger
|
||||||
await appDataSource.initialize()
|
|
||||||
|
|
||||||
container.bind<Env>(TYPES.Revisions_Env).toConstantValue(env)
|
|
||||||
|
|
||||||
if (configuration?.logger) {
|
if (configuration?.logger) {
|
||||||
container.bind<winston.Logger>(TYPES.Revisions_Logger).toConstantValue(configuration.logger as winston.Logger)
|
logger = configuration.logger as winston.Logger
|
||||||
} else {
|
} else {
|
||||||
const winstonFormatters = [winston.format.splat(), winston.format.json()]
|
const winstonFormatters = [winston.format.splat(), winston.format.json()]
|
||||||
if (env.get('NEW_RELIC_ENABLED', true) === 'true') {
|
if (env.get('NEW_RELIC_ENABLED', true) === 'true') {
|
||||||
@@ -84,15 +80,21 @@ export class ContainerConfigLoader {
|
|||||||
winstonFormatters.push(newrelicWinstonFormatter())
|
winstonFormatters.push(newrelicWinstonFormatter())
|
||||||
}
|
}
|
||||||
|
|
||||||
const logger = winston.createLogger({
|
logger = winston.createLogger({
|
||||||
level: env.get('LOG_LEVEL', true) || 'info',
|
level: env.get('LOG_LEVEL', true) || 'info',
|
||||||
format: winston.format.combine(...winstonFormatters),
|
format: winston.format.combine(...winstonFormatters),
|
||||||
transports: [new winston.transports.Console({ level: env.get('LOG_LEVEL', true) || 'info' })],
|
transports: [new winston.transports.Console({ level: env.get('LOG_LEVEL', true) || 'info' })],
|
||||||
defaultMeta: { service: 'revisions' },
|
defaultMeta: { service: 'revisions' },
|
||||||
})
|
})
|
||||||
|
|
||||||
container.bind<winston.Logger>(TYPES.Revisions_Logger).toConstantValue(logger)
|
|
||||||
}
|
}
|
||||||
|
container.bind<winston.Logger>(TYPES.Revisions_Logger).toConstantValue(logger)
|
||||||
|
|
||||||
|
const appDataSource = new AppDataSource(env)
|
||||||
|
await appDataSource.initialize()
|
||||||
|
|
||||||
|
logger.debug('Database initialized')
|
||||||
|
|
||||||
|
container.bind<Env>(TYPES.Revisions_Env).toConstantValue(env)
|
||||||
|
|
||||||
container.bind(TYPES.Revisions_NEW_RELIC_ENABLED).toConstantValue(env.get('NEW_RELIC_ENABLED', true))
|
container.bind(TYPES.Revisions_NEW_RELIC_ENABLED).toConstantValue(env.get('NEW_RELIC_ENABLED', true))
|
||||||
container.bind(TYPES.Revisions_VERSION).toConstantValue(env.get('VERSION', true) ?? 'development')
|
container.bind(TYPES.Revisions_VERSION).toConstantValue(env.get('VERSION', true) ?? 'development')
|
||||||
@@ -350,6 +352,8 @@ export class ContainerConfigLoader {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.debug('Configuration complete')
|
||||||
|
|
||||||
return container
|
return container
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ export class AppDataSource {
|
|||||||
const sqliteDataSourceOptions: SqliteConnectionOptions = {
|
const sqliteDataSourceOptions: SqliteConnectionOptions = {
|
||||||
...commonDataSourceOptions,
|
...commonDataSourceOptions,
|
||||||
type: 'sqlite',
|
type: 'sqlite',
|
||||||
database: `data/${this.env.get('DB_DATABASE')}.sqlite`,
|
database: this.env.get('DB_SQLITE_DATABASE_PATH'),
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dataSource = new DataSource(sqliteDataSourceOptions)
|
this.dataSource = new DataSource(sqliteDataSourceOptions)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
MODE=microservice # microservice | home-server
|
||||||
LOG_LEVEL=info
|
LOG_LEVEL=info
|
||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
VERSION=development
|
VERSION=development
|
||||||
@@ -14,8 +15,10 @@ DB_PASSWORD=changeme123
|
|||||||
DB_DATABASE=standard_notes_db
|
DB_DATABASE=standard_notes_db
|
||||||
DB_DEBUG_LEVEL=all # "all" | "query" | "schema" | "error" | "warn" | "info" | "log" | "migration"
|
DB_DEBUG_LEVEL=all # "all" | "query" | "schema" | "error" | "warn" | "info" | "log" | "migration"
|
||||||
DB_MIGRATIONS_PATH=dist/migrations/*.js
|
DB_MIGRATIONS_PATH=dist/migrations/*.js
|
||||||
|
DB_TYPE=mysql
|
||||||
|
|
||||||
REDIS_URL=redis://cache
|
REDIS_URL=redis://cache
|
||||||
|
CACHE_TYPE=redis
|
||||||
|
|
||||||
SNS_TOPIC_ARN=
|
SNS_TOPIC_ARN=
|
||||||
SNS_AWS_REGION=
|
SNS_AWS_REGION=
|
||||||
|
|||||||
@@ -3,6 +3,30 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.44.2](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.44.1...@standardnotes/syncing-server@1.44.2) (2023-06-22)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **home-server:** add debug logs about container initalizations ([0df4715](https://github.com/standardnotes/syncing-server-js/commit/0df471585fd5b4626ec2972f3b9a3e33b2830e65))
|
||||||
|
|
||||||
|
## [1.44.1](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.44.0...@standardnotes/syncing-server@1.44.1) (2023-06-14)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **home-server:** env var determining the sqlite database location ([#626](https://github.com/standardnotes/syncing-server-js/issues/626)) ([0cb5e36](https://github.com/standardnotes/syncing-server-js/commit/0cb5e36b20d9b095ea0edbcd877387e6c0069856))
|
||||||
|
|
||||||
|
# [1.44.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.43.0...@standardnotes/syncing-server@1.44.0) (2023-06-07)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* configurable path for uploads and db ([#623](https://github.com/standardnotes/syncing-server-js/issues/623)) ([af8feaa](https://github.com/standardnotes/syncing-server-js/commit/af8feaadfe2dd58baab4cca217d6307b4a221326))
|
||||||
|
|
||||||
|
# [1.43.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.42.2...@standardnotes/syncing-server@1.43.0) (2023-06-05)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **home-server:** allow running the home server with a mysql and redis configuration ([#622](https://github.com/standardnotes/syncing-server-js/issues/622)) ([d6e531d](https://github.com/standardnotes/syncing-server-js/commit/d6e531d4b6c1c80a894f6d7ec93632595268dd64))
|
||||||
|
|
||||||
## [1.42.2](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.42.1...@standardnotes/syncing-server@1.42.2) (2023-06-02)
|
## [1.42.2](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.42.1...@standardnotes/syncing-server@1.42.2) (2023-06-02)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/syncing-server",
|
"name": "@standardnotes/syncing-server",
|
||||||
"version": "1.42.2",
|
"version": "1.44.2",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -95,15 +95,9 @@ export class ContainerConfigLoader {
|
|||||||
defaultScope: 'Singleton',
|
defaultScope: 'Singleton',
|
||||||
})
|
})
|
||||||
|
|
||||||
const appDataSource = new AppDataSource(env)
|
let logger: winston.Logger
|
||||||
await appDataSource.initialize()
|
|
||||||
|
|
||||||
const isConfiguredForHomeServer = env.get('DB_TYPE') === 'sqlite'
|
|
||||||
|
|
||||||
container.bind<Env>(TYPES.Sync_Env).toConstantValue(env)
|
|
||||||
|
|
||||||
if (configuration?.logger) {
|
if (configuration?.logger) {
|
||||||
container.bind<winston.Logger>(TYPES.Sync_Logger).toConstantValue(configuration.logger as winston.Logger)
|
logger = configuration.logger as winston.Logger
|
||||||
} else {
|
} else {
|
||||||
const winstonFormatters = [winston.format.splat(), winston.format.json()]
|
const winstonFormatters = [winston.format.splat(), winston.format.json()]
|
||||||
if (env.get('NEW_RELIC_ENABLED', true) === 'true') {
|
if (env.get('NEW_RELIC_ENABLED', true) === 'true') {
|
||||||
@@ -114,15 +108,23 @@ export class ContainerConfigLoader {
|
|||||||
winstonFormatters.push(newrelicWinstonFormatter())
|
winstonFormatters.push(newrelicWinstonFormatter())
|
||||||
}
|
}
|
||||||
|
|
||||||
const logger = winston.createLogger({
|
logger = winston.createLogger({
|
||||||
level: env.get('LOG_LEVEL', true) || 'info',
|
level: env.get('LOG_LEVEL', true) || 'info',
|
||||||
format: winston.format.combine(...winstonFormatters),
|
format: winston.format.combine(...winstonFormatters),
|
||||||
transports: [new winston.transports.Console({ level: env.get('LOG_LEVEL', true) || 'info' })],
|
transports: [new winston.transports.Console({ level: env.get('LOG_LEVEL', true) || 'info' })],
|
||||||
defaultMeta: { service: 'syncing-server' },
|
defaultMeta: { service: 'syncing-server' },
|
||||||
})
|
})
|
||||||
|
|
||||||
container.bind<winston.Logger>(TYPES.Sync_Logger).toConstantValue(logger)
|
|
||||||
}
|
}
|
||||||
|
container.bind<winston.Logger>(TYPES.Sync_Logger).toConstantValue(logger)
|
||||||
|
|
||||||
|
const appDataSource = new AppDataSource(env)
|
||||||
|
await appDataSource.initialize()
|
||||||
|
|
||||||
|
logger.debug('Database initialized')
|
||||||
|
|
||||||
|
const isConfiguredForHomeServer = env.get('MODE', true) === 'home-server'
|
||||||
|
|
||||||
|
container.bind<Env>(TYPES.Sync_Env).toConstantValue(env)
|
||||||
|
|
||||||
if (isConfiguredForHomeServer) {
|
if (isConfiguredForHomeServer) {
|
||||||
container
|
container
|
||||||
@@ -517,6 +519,8 @@ export class ContainerConfigLoader {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.debug('Configuration complete')
|
||||||
|
|
||||||
return container
|
return container
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ export class AppDataSource {
|
|||||||
const sqliteDataSourceOptions: SqliteConnectionOptions = {
|
const sqliteDataSourceOptions: SqliteConnectionOptions = {
|
||||||
...commonDataSourceOptions,
|
...commonDataSourceOptions,
|
||||||
type: 'sqlite',
|
type: 'sqlite',
|
||||||
database: `data/${this.env.get('DB_DATABASE')}.sqlite`,
|
database: this.env.get('DB_SQLITE_DATABASE_PATH'),
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dataSource = new DataSource(sqliteDataSourceOptions)
|
this.dataSource = new DataSource(sqliteDataSourceOptions)
|
||||||
|
|||||||
Reference in New Issue
Block a user