New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@lbu/server

Package Overview
Dependencies
Maintainers
1
Versions
98
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@lbu/server - npm Package Compare versions

Comparing version 0.0.8 to 0.0.9

8

package.json
{
"name": "@lbu/server",
"version": "0.0.8",
"version": "0.0.9",
"description": "Koa server and common middleware",

@@ -17,4 +17,4 @@ "main": "index.js",

"dependencies": {
"@lbu/insight": "^0.0.8",
"@lbu/stdlib": "^0.0.8",
"@lbu/insight": "^0.0.9",
"@lbu/stdlib": "^0.0.9",
"koa": "2.11.0",

@@ -38,3 +38,3 @@ "koa-body": "4.1.1",

},
"gitHead": "85feb582684f93714a7aad81f2a47883e72bd363"
"gitHead": "d847630e049071c7c2385eef8377ba976ddd0e2a"
}

@@ -12,30 +12,13 @@ # @lbu/server

## Versioning and first release
For internal testing we stay on v0.0.x. To reach v0.1.0 the following features
will be supported:
- Flexible code generation (validators, router, queries, openapi)
- Usable documentation
- Test coverage (either e2e or unit, but enough to be considered somewhat
stable)
- Used in a medium size project @ Lightbase
- Implement a [Realworld project](https://github.com/gothinkster/realworld)
## Features
- @lbu/cli: Project template, and simple script runner
- @lbu/code-gen: Flexible code generators. Supports generating router, validator
- @lbu/insight: Opinionated logger
- @lbu/server: Wrap around Koa and some useful middleware
- @lbu/stdlib: Growing library of various common utilities like uuid & a basic
templating system
- Minimal API project boilerplate
- Script runner, can watch & reload almost anything (via nodemon)
- Flexible code generators supporting routers, validators, api clients, mocks
and more in the future.
- Opinionated structured logging
- Common Koa middleware wrapped in a single function
- Various utilities like loading .env files, executing other processes and a
basic template system
## Roadmap
- [ ] @lbu/code-gen: OpenAPI importer
- [ ] @lbu/features: Feature flag implementation based on @lbu/store & support
for code-gen
- [ ] @lbu/code-gen: Postgres query generator
## Docs

@@ -42,0 +25,0 @@

@@ -20,3 +20,3 @@ import Koa from "koa";

*/
export const getApp = (opts = {}) => {
export function getApp(opts = {}) {
const app = new Koa();

@@ -41,2 +41,2 @@ app.proxy =

return app;
};
}

@@ -12,3 +12,3 @@ import { merge } from "@lbu/stdlib";

*/
export const createBodyParsers = (opts = {}) => {
export function createBodyParsers(opts = {}) {
const multiPartOpts = merge({}, opts);

@@ -21,3 +21,3 @@

memoizeMultipartBodyParser = koaBody(multiPartOpts);
};
}

@@ -29,3 +29,3 @@ /**

*/
export const getBodyParser = () => {
export function getBodyParser() {
if (memoizeBodyParser === undefined) {

@@ -38,3 +38,3 @@ throw new Error(

return memoizeBodyParser;
};
}

@@ -47,3 +47,3 @@ /**

*/
export const getMultipartBodyParser = () => {
export function getMultipartBodyParser() {
if (memoizeMultipartBodyParser === undefined) {

@@ -56,2 +56,2 @@ throw new Error(

return memoizeMultipartBodyParser;
};
}

@@ -35,3 +35,4 @@ /*

* @typedef {Object} CorsOptions
* @property {string|function(ctx)} [origin] `Access-Control-Allow-Origin`, default is request Origin header
* @property {string|function(ctx)} [origin] `Access-Control-Allow-Origin`, default is
* request Origin header
* @property {string[]} [exposeHeaders] `Access-Control-Expose-Headers`

@@ -53,6 +54,6 @@ * @property {string|number} [maxAge] `Access-Control-Max-Age` in seconds

*/
export const cors = (options = {}) => {
export function cors(options = {}) {
const opts = Object.assign({}, defaultOptions, options);
let originFn = ctx => options.origin || ctx.get("Origin") || "*";
let originFn = (ctx) => options.origin || ctx.get("Origin") || "*";
if (typeof options.origin === "function") {

@@ -132,2 +133,2 @@ originFn = options.origin;

};
};
}

@@ -122,3 +122,3 @@ import { isNil } from "@lbu/stdlib";

*/
export const errorHandler = ({ onAppError, onError, leakError }) => {
export function errorHandler({ onAppError, onError, leakError }) {
onAppError = onAppError || defaultOnAppError;

@@ -137,6 +137,6 @@ onError = onError || defaultOnError;

let err = error;
let log = ctx.log.info;
let log = ctx.log.info.bind(ctx.log);
if (!(error instanceof AppError)) {
log = ctx.log.error;
log = ctx.log.error.bind(ctx.log);
err = new AppError("error.server.internal", 500, {}, error);

@@ -171,2 +171,2 @@ }

};
};
}

@@ -7,3 +7,3 @@ import { cors } from "./cors.js";

*/
export const defaultHeaders = (opts = {}) => {
export function defaultHeaders(opts = {}) {
// Excerpt from default helmet headers

@@ -26,2 +26,2 @@ // When serving static files, some extra headers should be added

};
};
}
/**
* Middleware that immediately returns on ANY /_health
*/
export const healthHandler = () => (ctx, next) => {
if (ctx.path === "/_health") {
ctx.body = "";
} else {
return next();
}
};
export function healthHandler() {
return (ctx, next) => {
if (ctx.path === "/_health") {
ctx.body = "";
} else {
return next();
}
};
}

@@ -6,23 +6,64 @@ import { newLogger } from "@lbu/insight";

/**
* Wait for the ctx.body stream to finish before resolving
* @param ctx
* @returns {Promise<void>}
* Log basic request and response information
*/
const bodyCloseOrFinish = async ctx => {
return new Promise(resolve => {
const onFinish = done.bind(null, "finish");
const onClose = done.bind(null, "close");
export function logMiddleware() {
return async (ctx, next) => {
const startTime = process.hrtime.bigint();
ctx.body.once("finish", onFinish);
ctx.body.once("close", onClose);
let requestId = ctx.get("X-Request-Id");
if (isNil(requestId) || requestId.length === 0) {
requestId = uuid();
}
ctx.set("X-Request-Id", requestId);
function done() {
ctx.body.removeListener("finish", onFinish);
ctx.body.removeListener("close", onClose);
resolve();
ctx.log = newLogger({
depth: 5,
ctx: {
type: "HTTP",
requestId,
},
});
await next();
let counter;
if (!isNil(ctx.response.length)) {
logInfo(ctx, startTime, ctx.response.length);
return;
} else if (ctx.body && ctx.body.readable) {
const body = ctx.body;
counter = new StreamLength();
ctx.body = body.pipe(counter).on("error", ctx.onerror);
await bodyCloseOrFinish(ctx);
}
});
};
logInfo(ctx, startTime, isNil(counter) ? 0 : counter.length);
};
}
/**
* Basic http log counters
* @param store
* @return {function(...[*]=)}
*/
export function logParser(store) {
store.requestCount = 0;
store.totalDuration = 0;
store.totalResponseLength = 0;
store.methodSummary = {};
store.statusCodeSummary = {};
return (obj) => {
if (!obj.type || obj.type !== "HTTP") {
return;
}
if (!obj.message || !obj.message.request || !obj.message.response) {
return;
}
handleRequestLog(store, obj);
};
}
/**
* Get the size of data that goes through a stream

@@ -49,3 +90,3 @@ */

*/
const logInfo = (ctx, startTime, length) => {
function logInfo(ctx, startTime, length) {
const duration = Math.round(

@@ -67,78 +108,39 @@ Number(process.hrtime.bigint() - startTime) / 1000000,

});
};
}
/**
* Log basic request and response information
*/
export const logMiddleware = () => async (ctx, next) => {
const startTime = process.hrtime.bigint();
function handleRequestLog(store, obj) {
store.requestCount++;
store.totalDuration += Number(obj.message.response.duration);
store.totalResponseLength += obj.message.response.length;
let requestId = ctx.get("X-Request-Id");
if (isNil(requestId) || requestId.length === 0) {
requestId = uuid();
if (!store.methodSummary[obj.message.request.method]) {
store.methodSummary[obj.message.request.method] = 0;
}
ctx.set("X-Request-Id", requestId);
store.methodSummary[obj.message.request.method]++;
ctx.log = newLogger({
depth: 5,
ctx: {
type: "HTTP",
requestId,
},
});
await next();
let counter;
if (!isNil(ctx.response.length)) {
logInfo(ctx, startTime, ctx.response.length);
return;
} else if (ctx.body && ctx.body.readable) {
const body = ctx.body;
counter = new StreamLength();
ctx.body = body.pipe(counter).on("error", ctx.onerror);
await bodyCloseOrFinish(ctx);
if (!store.statusCodeSummary[obj.message.response.status]) {
store.statusCodeSummary[obj.message.response.status] = 0;
}
store.statusCodeSummary[obj.message.response.status]++;
}
logInfo(ctx, startTime, isNil(counter) ? 0 : counter.length);
};
/**
* Basic http log counters
* @param store
* @return {function(...[*]=)}
* Wait for the ctx.body stream to finish before resolving
* @param ctx
* @returns {Promise<void>}
*/
export const logParser = store => {
store.requestCount = 0;
store.totalDuration = 0;
store.totalResponseLength = 0;
store.methodSummary = {};
store.statusCodeSummary = {};
async function bodyCloseOrFinish(ctx) {
return new Promise((resolve) => {
const onFinish = done.bind(null, "finish");
const onClose = done.bind(null, "close");
return obj => {
if (!obj.type || obj.type !== "HTTP") {
return;
}
if (!obj.message || !obj.message.request || !obj.message.response) {
return;
}
ctx.body.once("finish", onFinish);
ctx.body.once("close", onClose);
handleRequestLog(obj);
};
function handleRequestLog(obj) {
store.requestCount++;
store.totalDuration += Number(obj.message.response.duration);
store.totalResponseLength += obj.message.response.length;
if (!store.methodSummary[obj.message.request.method]) {
store.methodSummary[obj.message.request.method] = 0;
function done() {
ctx.body.removeListener("finish", onFinish);
ctx.body.removeListener("close", onClose);
resolve();
}
store.methodSummary[obj.message.request.method]++;
if (!store.statusCodeSummary[obj.message.response.status]) {
store.statusCodeSummary[obj.message.response.status] = 0;
}
store.statusCodeSummary[obj.message.response.status]++;
}
};
});
}

@@ -6,8 +6,10 @@ import { AppError } from "./error.js";

*/
export const notFoundHandler = () => async (ctx, next) => {
await next();
ctx.status = ctx.status || 404;
if (ctx.status === 404) {
throw AppError.notFound();
}
};
export function notFoundHandler() {
return async (ctx, next) => {
await next();
ctx.status = ctx.status || 404;
if (ctx.status === 404) {
throw AppError.notFound();
}
};
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc