impress
Advanced tools
Comparing version 3.0.0-alpha.13 to 3.0.0-alpha.14
@@ -184,2 +184,3 @@ 'use strict'; | ||
const portsClosed = new Promise((resolve) => { | ||
impress.console.info('Graceful shutdown in worker 0'); | ||
const timeout = setTimeout(() => { | ||
@@ -201,7 +202,9 @@ impress.console.error('Exit with graceful shutdown timeout'); | ||
process.removeAllListeners('warning'); | ||
process.on('warning', logError('Warning')); | ||
process.on('uncaughtException', logError('Uncaught exception')); | ||
process.on('warning', logError('Warning')); | ||
process.on('unhandledRejection', logError('Unhandled rejection')); | ||
process.on('SIGINT', stop); | ||
process.on('SIGTERM', stop); | ||
if (process.stdin.isTTY) { | ||
@@ -208,0 +211,0 @@ process.stdin.setRawMode(true); |
@@ -10,2 +10,3 @@ 'use strict'; | ||
const metautil = require('metautil'); | ||
const { Error } = metautil; | ||
const metavm = require('metavm'); | ||
@@ -16,2 +17,3 @@ const metawatch = require('metawatch'); | ||
const { Resources } = require('./resources.js'); | ||
const { Certificates } = require('./certificates.js'); | ||
const { Schemas } = require('./schemas.js'); | ||
@@ -21,9 +23,2 @@ const scheduler = require('./scheduler.js'); | ||
class Error extends global.Error { | ||
constructor(message, code) { | ||
super(message); | ||
this.code = code; | ||
} | ||
} | ||
const invoke = async ({ method, args, exclusive = false }) => { | ||
@@ -66,2 +61,3 @@ const { port1: port, port2 } = new MessageChannel(); | ||
this.static = new Resources('static', this); | ||
this.cert = new Certificates('cert', this, { ext: ['pem', 'domains'] }); | ||
this.resources = new Resources('resources', this); | ||
@@ -77,3 +73,2 @@ this.api = new Interfaces('api', this); | ||
this.Error = Error; | ||
this.cert = null; | ||
this.config = null; | ||
@@ -107,2 +102,3 @@ this.logger = null; | ||
this.resources.load(), | ||
this.cert.load(), | ||
(async () => { | ||
@@ -136,3 +132,3 @@ await this.lib.load(); | ||
if (this.server) await this.server.close(); | ||
await this.logger.close(); | ||
if (this.logger) await this.logger.close(); | ||
} | ||
@@ -218,2 +214,9 @@ | ||
}); | ||
this.watcher.on('before', async (changes) => { | ||
const certPath = path.join(this.path, 'cert'); | ||
const changed = changes.filter(([name]) => name.startsWith(certPath)); | ||
if (changed.length === 0) return; | ||
await this.cert.before(changes); | ||
}); | ||
} | ||
@@ -239,3 +242,3 @@ | ||
const data = this.static.get(filePath); | ||
if (data) { | ||
if (Buffer.isBuffer(data)) { | ||
transport.write(data, 200, fileExt); | ||
@@ -249,2 +252,11 @@ return; | ||
} | ||
const absPath = path.join(this.static.path, url); | ||
if (absPath.startsWith(this.static.path)) { | ||
const readable = fs.createReadStream(absPath); | ||
readable.on('error', () => { | ||
transport.error(404); | ||
}); | ||
transport.write(readable, 200, fileExt); | ||
return; | ||
} | ||
transport.error(404); | ||
@@ -251,0 +263,0 @@ } |
@@ -19,3 +19,3 @@ 'use strict'; | ||
const { name } = file; | ||
if (name.startsWith('.') && !name.endsWith('.js')) continue; | ||
if (name.startsWith('.eslint')) continue; | ||
const filePath = path.join(targetPath, name); | ||
@@ -26,3 +26,4 @@ if (file.isDirectory()) await this.load(filePath); | ||
} catch (error) { | ||
this.application.console.error(error.stack); | ||
const console = this.application.console || global.console; | ||
console.error(error.stack); | ||
} | ||
@@ -29,0 +30,0 @@ } |
@@ -11,9 +11,2 @@ 'use strict'; | ||
const getSignature = (method) => { | ||
const src = method.toString(); | ||
const signature = metautil.between(src, '({', '})'); | ||
if (signature === '') return []; | ||
return signature.split(',').map((s) => s.trim()); | ||
}; | ||
class Interfaces extends Cache { | ||
@@ -48,3 +41,3 @@ constructor(place, application) { | ||
} | ||
interfaceMethods[methodName] = getSignature(method); | ||
interfaceMethods[methodName] = metautil.getSignature(method); | ||
} | ||
@@ -51,0 +44,0 @@ |
@@ -9,7 +9,10 @@ 'use strict'; | ||
const WIN = process.platform === 'win32'; | ||
const MAX_FILE_SIZE = '10 mb'; | ||
class Resources extends Cache { | ||
constructor(place, application) { | ||
constructor(place, application, options = {}) { | ||
super(place, application); | ||
this.files = new Map(); | ||
this.ext = options.ext; | ||
this.maxFileSize = -1; | ||
} | ||
@@ -33,10 +36,19 @@ | ||
async change(filePath) { | ||
if (this.maxFileSize === -1) { | ||
const maxFileSize = this.application.config?.cache?.maxFileSize; | ||
this.maxFileSize = metautil.sizeToBytes(maxFileSize || MAX_FILE_SIZE); | ||
} | ||
const ext = metautil.fileExt(filePath); | ||
if (this.ext && !this.ext.includes(ext)) return; | ||
try { | ||
const data = await fsp.readFile(filePath); | ||
const { size } = await fsp.stat(filePath); | ||
const key = this.getKey(filePath); | ||
this.files.set(key, data); | ||
} catch (error) { | ||
if (error.code !== 'ENOENT') { | ||
this.application.console.error(error.stack); | ||
if (size > this.maxFileSize) { | ||
this.files.set(key, { size }); | ||
} else { | ||
const data = await fsp.readFile(filePath); | ||
this.files.set(key, data); | ||
} | ||
} catch { | ||
this.delete(filePath); | ||
} | ||
@@ -43,0 +55,0 @@ } |
@@ -11,3 +11,5 @@ 'use strict'; | ||
const proto = url.startsWith('https') ? https : http; | ||
const headers = { 'Content-Type': 'application/json' }; | ||
const mimeType = 'application/json'; | ||
const len = body ? Buffer.byteLength(body) : 0; | ||
const headers = { 'Content-Type': mimeType, 'Content-Length': len }; | ||
const req = proto.request(url, { method, headers }, (res) => { | ||
@@ -14,0 +16,0 @@ const code = res.statusCode; |
'use strict'; | ||
const path = require('node:path'); | ||
const fsp = require('node:fs').promises; | ||
const { parentPort, threadId, workerData } = require('node:worker_threads'); | ||
@@ -15,6 +14,4 @@ const { Config } = require('metaconfiguration'); | ||
const logError = (type) => async (error) => { | ||
const msg = error.stack || error.message || 'no stack trace'; | ||
console.error(type + ': ' + msg); | ||
if (application.finalization) return; | ||
if (application.initialization) { | ||
if (error.name === 'ExperimentalWarning') return; | ||
console.info(`Initialization failed in worker ${threadId}`); | ||
@@ -24,6 +21,9 @@ await application.shutdown(); | ||
} | ||
const msg = error.stack || error.message || 'no stack trace'; | ||
console.error(type + ': ' + msg); | ||
}; | ||
process.removeAllListeners('warning'); | ||
process.on('warning', logError('warning')); | ||
process.on('uncaughtException', logError('uncaughtException')); | ||
process.on('warning', logError('warning')); | ||
process.on('unhandledRejection', logError('unhandledRejection')); | ||
@@ -51,22 +51,2 @@ | ||
if (config.server.protocol === 'https') { | ||
const certPath = path.join(application.path, 'cert'); | ||
try { | ||
const key = await fsp.readFile(path.join(certPath, 'key.pem')); | ||
const cert = await fsp.readFile(path.join(certPath, 'cert.pem')); | ||
application.cert = { key, cert }; | ||
} catch { | ||
if (threadId === 1) console.error('Can not load TLS certificates'); | ||
process.exit(0); | ||
} | ||
} | ||
await application.init(); | ||
const { kind, port } = workerData; | ||
if (kind === 'server' || kind === 'balancer') { | ||
const options = { ...config.server, port, kind }; | ||
application.server = new Server(application, options); | ||
} | ||
const stop = async () => { | ||
@@ -101,2 +81,17 @@ if (application.finalization) return; | ||
await application.init(); | ||
const { kind, port } = workerData; | ||
if (kind === 'server' || kind === 'balancer') { | ||
const options = { ...config.server, port, kind }; | ||
if (config.server.protocol === 'https') { | ||
options.SNICallback = (servername, callback) => { | ||
const domain = application.cert.get(servername); | ||
if (!domain) callback(new Error(`No certificate for ${servername}`)); | ||
else callback(null, domain.creds); | ||
}; | ||
} | ||
application.server = new Server(application, options); | ||
} | ||
parentPort.on('message', async (msg) => { | ||
@@ -103,0 +98,0 @@ const handler = handlers[msg.name]; |
{ | ||
"name": "impress", | ||
"version": "3.0.0-alpha.13", | ||
"version": "3.0.0-alpha.14", | ||
"author": "Timur Shemsedinov <timur.shemsedinov@gmail.com>", | ||
@@ -65,14 +65,14 @@ "description": "Enterprise application server for Node.js", | ||
"dependencies": { | ||
"metacom": "^3.0.0-alpha.10", | ||
"metaconfiguration": "^2.1.10", | ||
"metalog": "^3.1.9", | ||
"metaschema": "^2.1.3", | ||
"metautil": "^3.7.1", | ||
"metacom": "^3.0.0-alpha.12", | ||
"metaconfiguration": "^2.1.11", | ||
"metalog": "^3.1.11", | ||
"metaschema": "^2.1.4", | ||
"metautil": "^3.8.0", | ||
"metavm": "^1.2.4", | ||
"metawatch": "^1.0.7" | ||
"metawatch": "^1.1.1" | ||
}, | ||
"devDependencies": { | ||
"@types/node": "^18.15.2", | ||
"@types/node": "^20.2.5", | ||
"@types/ws": "^8.5.4", | ||
"eslint": "^8.36.0", | ||
"eslint": "^8.42.0", | ||
"eslint-config-metarhia": "^8.1.0", | ||
@@ -79,0 +79,0 @@ "eslint-config-prettier": "^8.7.0", |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
64131
32
1706
5
Updatedmetacom@^3.0.0-alpha.12
Updatedmetaconfiguration@^2.1.11
Updatedmetalog@^3.1.11
Updatedmetaschema@^2.1.4
Updatedmetautil@^3.8.0
Updatedmetawatch@^1.1.1