@foal/core
Advanced tools
Comparing version 1.11.1 to 2.0.0-beta.0
export { Log, LogOptions } from './log.hook'; | ||
export { UserRequired } from './user-required.hook'; | ||
export { ValidateBody } from './validate-body.hook'; | ||
export { ValidateCookie } from './validate-cookie.hook'; | ||
export { ValidateCookies } from './validate-cookies.hook'; | ||
export { ValidateHeader } from './validate-header.hook'; | ||
export { ValidateHeaders } from './validate-headers.hook'; | ||
export { ValidatePathParam } from './validate-path-param.hook'; | ||
export { ValidateParams } from './validate-params.hook'; | ||
export { ValidateQueryParam } from './validate-query-param.hook'; | ||
export { ValidateQuery } from './validate-query.hook'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ValidateQueryParam = exports.ValidatePathParam = exports.ValidateHeader = exports.ValidateCookie = exports.ValidateBody = exports.UserRequired = exports.Log = void 0; | ||
var log_hook_1 = require("./log.hook"); | ||
exports.Log = log_hook_1.Log; | ||
Object.defineProperty(exports, "Log", { enumerable: true, get: function () { return log_hook_1.Log; } }); | ||
var user_required_hook_1 = require("./user-required.hook"); | ||
Object.defineProperty(exports, "UserRequired", { enumerable: true, get: function () { return user_required_hook_1.UserRequired; } }); | ||
var validate_body_hook_1 = require("./validate-body.hook"); | ||
exports.ValidateBody = validate_body_hook_1.ValidateBody; | ||
Object.defineProperty(exports, "ValidateBody", { enumerable: true, get: function () { return validate_body_hook_1.ValidateBody; } }); | ||
var validate_cookie_hook_1 = require("./validate-cookie.hook"); | ||
exports.ValidateCookie = validate_cookie_hook_1.ValidateCookie; | ||
var validate_cookies_hook_1 = require("./validate-cookies.hook"); | ||
exports.ValidateCookies = validate_cookies_hook_1.ValidateCookies; | ||
Object.defineProperty(exports, "ValidateCookie", { enumerable: true, get: function () { return validate_cookie_hook_1.ValidateCookie; } }); | ||
var validate_header_hook_1 = require("./validate-header.hook"); | ||
exports.ValidateHeader = validate_header_hook_1.ValidateHeader; | ||
var validate_headers_hook_1 = require("./validate-headers.hook"); | ||
exports.ValidateHeaders = validate_headers_hook_1.ValidateHeaders; | ||
Object.defineProperty(exports, "ValidateHeader", { enumerable: true, get: function () { return validate_header_hook_1.ValidateHeader; } }); | ||
var validate_path_param_hook_1 = require("./validate-path-param.hook"); | ||
exports.ValidatePathParam = validate_path_param_hook_1.ValidatePathParam; | ||
var validate_params_hook_1 = require("./validate-params.hook"); | ||
exports.ValidateParams = validate_params_hook_1.ValidateParams; | ||
Object.defineProperty(exports, "ValidatePathParam", { enumerable: true, get: function () { return validate_path_param_hook_1.ValidatePathParam; } }); | ||
var validate_query_param_hook_1 = require("./validate-query-param.hook"); | ||
exports.ValidateQueryParam = validate_query_param_hook_1.ValidateQueryParam; | ||
var validate_query_hook_1 = require("./validate-query.hook"); | ||
exports.ValidateQuery = validate_query_hook_1.ValidateQuery; | ||
Object.defineProperty(exports, "ValidateQueryParam", { enumerable: true, get: function () { return validate_query_param_hook_1.ValidateQueryParam; } }); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.isFunction = void 0; | ||
function isFunction(schema) { | ||
@@ -4,0 +5,0 @@ return typeof schema === 'function'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Log = void 0; | ||
const core_1 = require("../../core"); | ||
@@ -4,0 +5,0 @@ /** |
@@ -7,3 +7,3 @@ import { HookDecorator } from '../../core'; | ||
* @param {(object | ((controller: any) => object))} schema - Schema used to validate the body request. | ||
* @param {{ openapi?: boolean }} [options={}] - Options to add openapi metadata | ||
* @param {{ openapi?: boolean }} [options] - Options to add openapi metadata | ||
* @returns {HookDecorator} - The hook. | ||
@@ -10,0 +10,0 @@ */ |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ValidateBody = void 0; | ||
// FoalTS | ||
const core_1 = require("../../core"); | ||
const openapi_1 = require("../../openapi"); | ||
const utils_1 = require("../utils"); | ||
@@ -13,37 +13,30 @@ const is_function_util_1 = require("./is-function.util"); | ||
* @param {(object | ((controller: any) => object))} schema - Schema used to validate the body request. | ||
* @param {{ openapi?: boolean }} [options={}] - Options to add openapi metadata | ||
* @param {{ openapi?: boolean }} [options] - Options to add openapi metadata | ||
* @returns {HookDecorator} - The hook. | ||
*/ | ||
function ValidateBody(schema, options = {}) { | ||
const ajv = utils_1.getAjvInstance(); | ||
function validate(ctx) { | ||
const ajvSchema = is_function_util_1.isFunction(schema) ? schema(this) : schema; | ||
if (!ajv.validate(ajvSchema, ctx.request.body)) { | ||
return new core_1.HttpResponseBadRequest({ body: ajv.errors }); | ||
function ValidateBody(schema, options) { | ||
let validateSchema; | ||
function validate(ctx, services) { | ||
if (!validateSchema) { | ||
const ajvSchema = is_function_util_1.isFunction(schema) ? schema(this) : schema; | ||
const components = services.get(core_1.OpenApi).getComponents(this); | ||
validateSchema = utils_1.getAjvInstance().compile(Object.assign(Object.assign({}, ajvSchema), { components })); | ||
} | ||
if (!validateSchema(ctx.request.body)) { | ||
return new core_1.HttpResponseBadRequest({ body: validateSchema.errors }); | ||
} | ||
} | ||
return (target, propertyKey) => { | ||
core_1.Hook(validate)(target, propertyKey); | ||
if (options.openapi === false || | ||
(options.openapi === undefined && !core_1.Config.get2('settings.openapi.useHooks', 'boolean'))) { | ||
return; | ||
} | ||
function makeRequestBody(schema) { | ||
return { | ||
content: { | ||
'application/json': { schema } | ||
}, | ||
required: true | ||
}; | ||
} | ||
const requestBody = is_function_util_1.isFunction(schema) ? (c) => makeRequestBody(schema(c)) : makeRequestBody(schema); | ||
if (propertyKey) { | ||
openapi_1.ApiRequestBody(requestBody)(target, propertyKey); | ||
} | ||
else { | ||
openapi_1.ApiRequestBody(requestBody)(target); | ||
} | ||
openapi_1.ApiResponse(400, { description: 'Bad request.' })(target, propertyKey); | ||
}; | ||
const openapi = [ | ||
core_1.ApiRequestBody((c) => ({ | ||
content: { | ||
'application/json': { | ||
schema: is_function_util_1.isFunction(schema) ? schema(c) : schema | ||
} | ||
}, | ||
required: true | ||
})), | ||
core_1.ApiResponse(400, { description: 'Bad request.' }) | ||
]; | ||
return core_1.Hook(validate, openapi, options); | ||
} | ||
exports.ValidateBody = ValidateBody; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ValidateCookie = void 0; | ||
// FoalTS | ||
const core_1 = require("../../core"); | ||
const openapi_1 = require("../../openapi"); | ||
const utils_1 = require("../utils"); | ||
@@ -21,34 +21,33 @@ const is_function_util_1 = require("./is-function.util"); | ||
function ValidateCookie(name, schema = { type: 'string' }, options = {}) { | ||
const ajv = utils_1.getAjvInstance(); | ||
const required = options.required !== false; | ||
function validate(ctx) { | ||
const cookiesSchema = { | ||
properties: { | ||
[name]: is_function_util_1.isFunction(schema) ? schema(this) : schema | ||
}, | ||
required: required ? [name] : [], | ||
type: 'object', | ||
}; | ||
if (!ajv.validate(cookiesSchema, ctx.request.cookies)) { | ||
return new core_1.HttpResponseBadRequest({ cookies: ajv.errors }); | ||
var _a; | ||
// tslint:disable-next-line | ||
const required = (_a = options.required) !== null && _a !== void 0 ? _a : true; | ||
let validateSchema; | ||
function validate(ctx, services) { | ||
if (!validateSchema) { | ||
const ajvSchema = is_function_util_1.isFunction(schema) ? schema(this) : schema; | ||
const components = services.get(core_1.OpenApi).getComponents(this); | ||
validateSchema = utils_1.getAjvInstance().compile({ | ||
components, | ||
properties: { | ||
[name]: ajvSchema | ||
}, | ||
required: required ? [name] : [], | ||
type: 'object', | ||
}); | ||
} | ||
if (!validateSchema(ctx.request.cookies)) { | ||
return new core_1.HttpResponseBadRequest({ cookies: validateSchema.errors }); | ||
} | ||
} | ||
return (target, propertyKey) => { | ||
core_1.Hook(validate)(target, propertyKey); | ||
if (options.openapi === false || | ||
(options.openapi === undefined && !core_1.Config.get2('settings.openapi.useHooks', 'boolean'))) { | ||
return; | ||
} | ||
function makeParameter(schema) { | ||
const result = { in: 'cookie', name, schema }; | ||
if (required) { | ||
result.required = required; | ||
} | ||
return result; | ||
} | ||
const apiCookieParameter = is_function_util_1.isFunction(schema) ? (c) => makeParameter(schema(c)) : makeParameter(schema); | ||
openapi_1.ApiParameter(apiCookieParameter)(target, propertyKey); | ||
openapi_1.ApiResponse(400, { description: 'Bad request.' })(target, propertyKey); | ||
}; | ||
const param = { in: 'cookie', name }; | ||
if (required) { | ||
param.required = required; | ||
} | ||
const openapi = [ | ||
core_1.ApiParameter((c) => (Object.assign(Object.assign({}, param), { schema: is_function_util_1.isFunction(schema) ? schema(c) : schema }))), | ||
core_1.ApiResponse(400, { description: 'Bad request.' }) | ||
]; | ||
return core_1.Hook(validate, openapi, options); | ||
} | ||
exports.ValidateCookie = ValidateCookie; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
// FoalTS | ||
exports.ValidateHeader = void 0; | ||
const core_1 = require("../../core"); | ||
const openapi_1 = require("../../openapi"); | ||
const utils_1 = require("../utils"); | ||
@@ -21,35 +20,34 @@ const is_function_util_1 = require("./is-function.util"); | ||
function ValidateHeader(name, schema = { type: 'string' }, options = {}) { | ||
const ajv = utils_1.getAjvInstance(); | ||
const required = options.required !== false; | ||
var _a; | ||
// tslint:disable-next-line | ||
const required = (_a = options.required) !== null && _a !== void 0 ? _a : true; | ||
name = name.toLowerCase(); | ||
function validate(ctx) { | ||
const headersSchema = { | ||
properties: { | ||
[name]: is_function_util_1.isFunction(schema) ? schema(this) : schema | ||
}, | ||
required: required ? [name] : [], | ||
type: 'object', | ||
}; | ||
if (!ajv.validate(headersSchema, ctx.request.headers)) { | ||
return new core_1.HttpResponseBadRequest({ headers: ajv.errors }); | ||
let validateSchema; | ||
function validate(ctx, services) { | ||
if (!validateSchema) { | ||
const ajvSchema = is_function_util_1.isFunction(schema) ? schema(this) : schema; | ||
const components = services.get(core_1.OpenApi).getComponents(this); | ||
validateSchema = utils_1.getAjvInstance().compile({ | ||
components, | ||
properties: { | ||
[name]: ajvSchema | ||
}, | ||
required: required ? [name] : [], | ||
type: 'object', | ||
}); | ||
} | ||
if (!validateSchema(ctx.request.headers)) { | ||
return new core_1.HttpResponseBadRequest({ headers: validateSchema.errors }); | ||
} | ||
} | ||
return (target, propertyKey) => { | ||
core_1.Hook(validate)(target, propertyKey); | ||
if (options.openapi === false || | ||
(options.openapi === undefined && !core_1.Config.get2('settings.openapi.useHooks', 'boolean'))) { | ||
return; | ||
} | ||
function makeParameter(schema) { | ||
const result = { in: 'header', name, schema }; | ||
if (required) { | ||
result.required = required; | ||
} | ||
return result; | ||
} | ||
const apiHeaderParameter = is_function_util_1.isFunction(schema) ? (c) => makeParameter(schema(c)) : makeParameter(schema); | ||
openapi_1.ApiParameter(apiHeaderParameter)(target, propertyKey); | ||
openapi_1.ApiResponse(400, { description: 'Bad request.' })(target, propertyKey); | ||
}; | ||
const param = { in: 'header', name }; | ||
if (required) { | ||
param.required = required; | ||
} | ||
const openapi = [ | ||
core_1.ApiParameter((c) => (Object.assign(Object.assign({}, param), { schema: is_function_util_1.isFunction(schema) ? schema(c) : schema }))), | ||
core_1.ApiResponse(400, { description: 'Bad request.' }) | ||
]; | ||
return core_1.Hook(validate, openapi, options); | ||
} | ||
exports.ValidateHeader = ValidateHeader; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ValidatePathParam = void 0; | ||
// FoalTS | ||
const core_1 = require("../../core"); | ||
const openapi_1 = require("../../openapi"); | ||
const utils_1 = require("../utils"); | ||
@@ -20,29 +20,31 @@ const is_function_util_1 = require("./is-function.util"); | ||
function ValidatePathParam(name, schema, options = {}) { | ||
const ajv = utils_1.getAjvInstance(); | ||
function validate(ctx) { | ||
const paramsSchema = { | ||
properties: { | ||
[name]: is_function_util_1.isFunction(schema) ? schema(this) : schema | ||
}, | ||
required: [name], | ||
type: 'object', | ||
}; | ||
if (!ajv.validate(paramsSchema, ctx.request.params)) { | ||
return new core_1.HttpResponseBadRequest({ pathParams: ajv.errors }); | ||
let validateSchema; | ||
function validate(ctx, services) { | ||
if (!validateSchema) { | ||
const ajvSchema = is_function_util_1.isFunction(schema) ? schema(this) : schema; | ||
const components = services.get(core_1.OpenApi).getComponents(this); | ||
validateSchema = utils_1.getAjvInstance().compile({ | ||
components, | ||
properties: { | ||
[name]: ajvSchema | ||
}, | ||
required: [name], | ||
type: 'object', | ||
}); | ||
} | ||
if (!validateSchema(ctx.request.params)) { | ||
return new core_1.HttpResponseBadRequest({ pathParams: validateSchema.errors }); | ||
} | ||
} | ||
return (target, propertyKey) => { | ||
core_1.Hook(validate)(target, propertyKey); | ||
if (options.openapi === false || | ||
(options.openapi === undefined && !core_1.Config.get2('settings.openapi.useHooks', 'boolean'))) { | ||
return; | ||
} | ||
function makeParameter(schema) { | ||
return { in: 'path', name, required: true, schema }; | ||
} | ||
const apiPathParameter = is_function_util_1.isFunction(schema) ? (c) => makeParameter(schema(c)) : makeParameter(schema); | ||
openapi_1.ApiParameter(apiPathParameter)(target, propertyKey); | ||
openapi_1.ApiResponse(400, { description: 'Bad request.' })(target, propertyKey); | ||
}; | ||
const openapi = [ | ||
core_1.ApiParameter((c) => ({ | ||
in: 'path', | ||
name, | ||
required: true, | ||
schema: is_function_util_1.isFunction(schema) ? schema(c) : schema, | ||
})), | ||
core_1.ApiResponse(400, { description: 'Bad request.' }) | ||
]; | ||
return core_1.Hook(validate, openapi, options); | ||
} | ||
exports.ValidatePathParam = ValidatePathParam; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ValidateQueryParam = void 0; | ||
// FoalTS | ||
const core_1 = require("../../core"); | ||
const openapi_1 = require("../../openapi"); | ||
const utils_1 = require("../utils"); | ||
@@ -21,34 +21,33 @@ const is_function_util_1 = require("./is-function.util"); | ||
function ValidateQueryParam(name, schema = { type: 'string' }, options = {}) { | ||
const ajv = utils_1.getAjvInstance(); | ||
const required = options.required !== false; | ||
function validate(ctx) { | ||
const querySchema = { | ||
properties: { | ||
[name]: is_function_util_1.isFunction(schema) ? schema(this) : schema | ||
}, | ||
required: required ? [name] : [], | ||
type: 'object', | ||
}; | ||
if (!ajv.validate(querySchema, ctx.request.query)) { | ||
return new core_1.HttpResponseBadRequest({ query: ajv.errors }); | ||
var _a; | ||
// tslint:disable-next-line | ||
const required = (_a = options.required) !== null && _a !== void 0 ? _a : true; | ||
let validateSchema; | ||
function validate(ctx, services) { | ||
if (!validateSchema) { | ||
const ajvSchema = is_function_util_1.isFunction(schema) ? schema(this) : schema; | ||
const components = services.get(core_1.OpenApi).getComponents(this); | ||
validateSchema = utils_1.getAjvInstance().compile({ | ||
components, | ||
properties: { | ||
[name]: ajvSchema | ||
}, | ||
required: required ? [name] : [], | ||
type: 'object', | ||
}); | ||
} | ||
if (!validateSchema(ctx.request.query)) { | ||
return new core_1.HttpResponseBadRequest({ query: validateSchema.errors }); | ||
} | ||
} | ||
return (target, propertyKey) => { | ||
core_1.Hook(validate)(target, propertyKey); | ||
if (options.openapi === false || | ||
(options.openapi === undefined && !core_1.Config.get2('settings.openapi.useHooks', 'boolean'))) { | ||
return; | ||
} | ||
function makeParameter(schema) { | ||
const result = { in: 'query', name, schema }; | ||
if (required) { | ||
result.required = required; | ||
} | ||
return result; | ||
} | ||
const apiQueryParameter = is_function_util_1.isFunction(schema) ? (c) => makeParameter(schema(c)) : makeParameter(schema); | ||
openapi_1.ApiParameter(apiQueryParameter)(target, propertyKey); | ||
openapi_1.ApiResponse(400, { description: 'Bad request.' })(target, propertyKey); | ||
}; | ||
const param = { in: 'query', name }; | ||
if (required) { | ||
param.required = required; | ||
} | ||
const openapi = [ | ||
core_1.ApiParameter((c) => (Object.assign(Object.assign({}, param), { schema: is_function_util_1.isFunction(schema) ? schema(c) : schema }))), | ||
core_1.ApiResponse(400, { description: 'Bad request.' }) | ||
]; | ||
return core_1.Hook(validate, openapi, options); | ||
} | ||
exports.ValidateQueryParam = ValidateQueryParam; |
@@ -1,4 +0,3 @@ | ||
export * from './errors'; | ||
export * from './hooks'; | ||
export * from './tokens'; | ||
export * from './utils'; |
"use strict"; | ||
function __export(m) { | ||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; | ||
} | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
__export(require("./errors")); | ||
__export(require("./hooks")); | ||
__export(require("./tokens")); | ||
__export(require("./utils")); | ||
__exportStar(require("./hooks"), exports); | ||
__exportStar(require("./tokens"), exports); | ||
__exportStar(require("./utils"), exports); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.convertBase64ToBase64url = void 0; | ||
/** | ||
@@ -4,0 +5,0 @@ * Convert a base64-encode string into a base64url-encode string with no equals. |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.generateSignedToken = void 0; | ||
const generate_token_util_1 = require("./generate-token.util"); | ||
@@ -4,0 +5,0 @@ const sign_token_util_1 = require("./sign-token.util"); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.generateToken = void 0; | ||
// std | ||
@@ -4,0 +5,0 @@ const crypto_1 = require("crypto"); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.verifySignedToken = exports.signToken = exports.generateToken = exports.generateSignedToken = exports.convertBase64ToBase64url = void 0; | ||
var convert_base64_to_base64_url_util_1 = require("./convert-base64-to-base64-url.util"); | ||
exports.convertBase64ToBase64url = convert_base64_to_base64_url_util_1.convertBase64ToBase64url; | ||
Object.defineProperty(exports, "convertBase64ToBase64url", { enumerable: true, get: function () { return convert_base64_to_base64_url_util_1.convertBase64ToBase64url; } }); | ||
var generate_signed_token_util_1 = require("./generate-signed-token.util"); | ||
exports.generateSignedToken = generate_signed_token_util_1.generateSignedToken; | ||
Object.defineProperty(exports, "generateSignedToken", { enumerable: true, get: function () { return generate_signed_token_util_1.generateSignedToken; } }); | ||
var generate_token_util_1 = require("./generate-token.util"); | ||
exports.generateToken = generate_token_util_1.generateToken; | ||
Object.defineProperty(exports, "generateToken", { enumerable: true, get: function () { return generate_token_util_1.generateToken; } }); | ||
var sign_token_util_1 = require("./sign-token.util"); | ||
exports.signToken = sign_token_util_1.signToken; | ||
Object.defineProperty(exports, "signToken", { enumerable: true, get: function () { return sign_token_util_1.signToken; } }); | ||
var verify_signed_token_util_1 = require("./verify-signed-token.util"); | ||
exports.verifySignedToken = verify_signed_token_util_1.verifySignedToken; | ||
Object.defineProperty(exports, "verifySignedToken", { enumerable: true, get: function () { return verify_signed_token_util_1.verifySignedToken; } }); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.signToken = exports.sign = void 0; | ||
// std | ||
@@ -4,0 +5,0 @@ const crypto_1 = require("crypto"); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.verifySignedToken = void 0; | ||
// std | ||
@@ -4,0 +5,0 @@ const crypto_1 = require("crypto"); |
@@ -8,6 +8,7 @@ import 'reflect-metadata'; | ||
* @export | ||
* @template T | ||
* @param {string} path - The HTTP path. | ||
* @param {Class} controllerClass - The controller class. | ||
* @returns {Class} The controller class. | ||
* @param {Class<T>} controllerClass - The controller class. | ||
* @returns {Class<T>} The controller class. | ||
*/ | ||
export declare function controller(path: string, controllerClass: Class): Class; | ||
export declare function controller<T>(path: string, controllerClass: Class<T>): Class<T>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.controller = void 0; | ||
// 3p | ||
@@ -10,5 +11,6 @@ require("reflect-metadata"); | ||
* @export | ||
* @template T | ||
* @param {string} path - The HTTP path. | ||
* @param {Class} controllerClass - The controller class. | ||
* @returns {Class} The controller class. | ||
* @param {Class<T>} controllerClass - The controller class. | ||
* @returns {Class<T>} The controller class. | ||
*/ | ||
@@ -15,0 +17,0 @@ function controller(path, controllerClass) { |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.escapeProp = void 0; | ||
const escape_1 = require("./escape"); | ||
@@ -4,0 +5,0 @@ /** |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.escape = void 0; | ||
const escapeMap = { | ||
@@ -4,0 +5,0 @@ '"': '"', |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.getAjvInstance = exports._instanceWrapper = void 0; | ||
// 3p | ||
@@ -26,7 +27,7 @@ const Ajv = require("ajv"); | ||
exports._instanceWrapper.instance = new Ajv({ | ||
allErrors: core_1.Config.get2('settings.ajv.allErrors', 'boolean'), | ||
coerceTypes: core_1.Config.get2('settings.ajv.coerceTypes', 'boolean', true), | ||
nullable: core_1.Config.get2('settings.ajv.nullable', 'boolean'), | ||
removeAdditional: core_1.Config.get2('settings.ajv.removeAdditional', 'boolean|string', true), | ||
useDefaults: core_1.Config.get2('settings.ajv.useDefaults', 'boolean|string', true), | ||
allErrors: core_1.Config.get('settings.ajv.allErrors', 'boolean'), | ||
coerceTypes: core_1.Config.get('settings.ajv.coerceTypes', 'boolean', true), | ||
nullable: core_1.Config.get('settings.ajv.nullable', 'boolean'), | ||
removeAdditional: core_1.Config.get('settings.ajv.removeAdditional', 'boolean|string', true), | ||
useDefaults: core_1.Config.get('settings.ajv.useDefaults', 'boolean|string', true), | ||
}); | ||
@@ -33,0 +34,0 @@ } |
@@ -5,3 +5,3 @@ /** | ||
* Configured to use PBKDF2 + HMAC + SHA256. | ||
* The result is a 64 byte binary string (or hex if the legacy option is true). | ||
* The result is a 64 byte binary string. | ||
* | ||
@@ -14,7 +14,4 @@ * The random salt is 16 bytes long. | ||
* @param {string} plainTextPassword - The password to hash. | ||
* @param {{ legacy?: boolean }} [options={}] | ||
* @returns {Promise<string>} The derived key with the algorithm name, the number of iterations and the salt. | ||
*/ | ||
export declare function hashPassword(plainTextPassword: string, options?: { | ||
legacy?: boolean; | ||
}): Promise<string>; | ||
export declare function hashPassword(plainTextPassword: string): Promise<string>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.hashPassword = void 0; | ||
const crypto_1 = require("crypto"); | ||
const util_1 = require("util"); | ||
/** | ||
* Legacy function to hash passwords. Only kept for backward compatibility. | ||
* @param password | ||
*/ | ||
async function parsePassword(password) { | ||
const salt = (await util_1.promisify(crypto_1.randomBytes)(16)).toString('hex'); | ||
const iterations = 100000; | ||
const keylen = 64; | ||
const digest = 'sha256'; | ||
const derivedKey = await util_1.promisify(crypto_1.pbkdf2)(password, salt, iterations, keylen, digest); | ||
return `pbkdf2_${digest}$${iterations}$${salt}$${derivedKey.toString('hex')}`; | ||
} | ||
/** | ||
* Hash a password using the PBKDF2 algorithm. | ||
* | ||
* Configured to use PBKDF2 + HMAC + SHA256. | ||
* The result is a 64 byte binary string (or hex if the legacy option is true). | ||
* The result is a 64 byte binary string. | ||
* | ||
@@ -29,9 +18,5 @@ * The random salt is 16 bytes long. | ||
* @param {string} plainTextPassword - The password to hash. | ||
* @param {{ legacy?: boolean }} [options={}] | ||
* @returns {Promise<string>} The derived key with the algorithm name, the number of iterations and the salt. | ||
*/ | ||
async function hashPassword(plainTextPassword, options = {}) { | ||
if (options.legacy) { | ||
return parsePassword(plainTextPassword); | ||
} | ||
async function hashPassword(plainTextPassword) { | ||
const saltBuffer = await util_1.promisify(crypto_1.randomBytes)(16); | ||
@@ -38,0 +23,0 @@ const iterations = 150000; |
@@ -9,3 +9,2 @@ export { controller } from './controller.util'; | ||
export { render } from './render.util'; | ||
export { validate } from './validate.util'; | ||
export { verifyPassword } from './verify-password.util'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.verifyPassword = exports.render = exports.renderError = exports.isInFile = exports.hashPassword = exports.getAjvInstance = exports.escape = exports.escapeProp = exports.controller = void 0; | ||
var controller_util_1 = require("./controller.util"); | ||
exports.controller = controller_util_1.controller; | ||
Object.defineProperty(exports, "controller", { enumerable: true, get: function () { return controller_util_1.controller; } }); | ||
var escape_prop_1 = require("./escape-prop"); | ||
exports.escapeProp = escape_prop_1.escapeProp; | ||
Object.defineProperty(exports, "escapeProp", { enumerable: true, get: function () { return escape_prop_1.escapeProp; } }); | ||
var escape_1 = require("./escape"); | ||
exports.escape = escape_1.escape; | ||
Object.defineProperty(exports, "escape", { enumerable: true, get: function () { return escape_1.escape; } }); | ||
var get_ajv_instance_1 = require("./get-ajv-instance"); | ||
exports.getAjvInstance = get_ajv_instance_1.getAjvInstance; | ||
Object.defineProperty(exports, "getAjvInstance", { enumerable: true, get: function () { return get_ajv_instance_1.getAjvInstance; } }); | ||
var hash_password_util_1 = require("./hash-password.util"); | ||
exports.hashPassword = hash_password_util_1.hashPassword; | ||
Object.defineProperty(exports, "hashPassword", { enumerable: true, get: function () { return hash_password_util_1.hashPassword; } }); | ||
var is_in_file_util_1 = require("./is-in-file.util"); | ||
exports.isInFile = is_in_file_util_1.isInFile; | ||
Object.defineProperty(exports, "isInFile", { enumerable: true, get: function () { return is_in_file_util_1.isInFile; } }); | ||
var render_error_util_1 = require("./render-error.util"); | ||
exports.renderError = render_error_util_1.renderError; | ||
Object.defineProperty(exports, "renderError", { enumerable: true, get: function () { return render_error_util_1.renderError; } }); | ||
var render_util_1 = require("./render.util"); | ||
exports.render = render_util_1.render; | ||
var validate_util_1 = require("./validate.util"); | ||
exports.validate = validate_util_1.validate; | ||
Object.defineProperty(exports, "render", { enumerable: true, get: function () { return render_util_1.render; } }); | ||
var verify_password_util_1 = require("./verify-password.util"); | ||
exports.verifyPassword = verify_password_util_1.verifyPassword; | ||
Object.defineProperty(exports, "verifyPassword", { enumerable: true, get: function () { return verify_password_util_1.verifyPassword; } }); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.isInFile = void 0; | ||
// std | ||
@@ -4,0 +5,0 @@ const fs_1 = require("fs"); |
import { Context, HttpResponseInternalServerError } from '../../core'; | ||
/** | ||
* Render the default HTML page when an error is thrown or rejected in the application. | ||
* Renders the default HTML page when an error is thrown or rejected in the application. | ||
* | ||
@@ -10,5 +10,5 @@ * The page is different depending on if the configuration key `settings.debug` is | ||
* @param {Error} error - The error thrown or rejected. | ||
* @param {Context} ctx - The Context. object. | ||
* @param {Context} ctx - The Context object. | ||
* @returns {Promise<HttpResponseInternalServerError>} The HTTP response. | ||
*/ | ||
export declare function renderError(error: Error, ctx: Context): Promise<HttpResponseInternalServerError>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.renderError = void 0; | ||
// std | ||
@@ -10,6 +11,4 @@ const fs_1 = require("fs"); | ||
const render_util_1 = require("./render.util"); | ||
const page500 = '<html><head><title>INTERNAL SERVER ERROR</title></head><body>' | ||
+ '<h1>500 - INTERNAL SERVER ERROR</h1></body></html>'; | ||
/** | ||
* Render the default HTML page when an error is thrown or rejected in the application. | ||
* Renders the default HTML page when an error is thrown or rejected in the application. | ||
* | ||
@@ -21,16 +20,18 @@ * The page is different depending on if the configuration key `settings.debug` is | ||
* @param {Error} error - The error thrown or rejected. | ||
* @param {Context} ctx - The Context. object. | ||
* @param {Context} ctx - The Context object. | ||
* @returns {Promise<HttpResponseInternalServerError>} The HTTP response. | ||
*/ | ||
async function renderError(error, ctx) { | ||
const template = await util_1.promisify(fs_1.readFile)(path_1.join(__dirname, '500.debug.html'), 'utf8'); | ||
if (!core_1.Config.get2('settings.debug', 'boolean')) { | ||
return new core_1.HttpResponseInternalServerError(page500); | ||
let body = '<html><head><title>INTERNAL SERVER ERROR</title></head><body>' | ||
+ '<h1>500 - INTERNAL SERVER ERROR</h1></body></html>'; | ||
if (core_1.Config.get('settings.debug', 'boolean')) { | ||
const template = await util_1.promisify(fs_1.readFile)(path_1.join(__dirname, '500.debug.html'), 'utf8'); | ||
body = render_util_1.renderToString(template, { | ||
message: error.message, | ||
name: error.name, | ||
stack: error.stack | ||
}); | ||
} | ||
return new core_1.HttpResponseInternalServerError(render_util_1.renderToString(template, { | ||
message: error.message, | ||
name: error.name, | ||
stack: error.stack | ||
})); | ||
return new core_1.HttpResponseInternalServerError(body, { ctx, error }); | ||
} | ||
exports.renderError = renderError; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.render = exports.renderToString = void 0; | ||
// std | ||
@@ -42,5 +43,5 @@ const fs_1 = require("fs"); | ||
const template = await util_1.promisify(fs_1.readFile)(path, 'utf8'); | ||
const templateEngine = core_1.Config.get2('settings.templateEngine', 'string'); | ||
const templateEngine = core_1.Config.get('settings.templateEngine', 'string'); | ||
if (templateEngine) { | ||
const { renderToString, __express } = require(templateEngine); | ||
const { __express } = require(templateEngine); | ||
if (__express) { | ||
@@ -56,5 +57,2 @@ return new Promise((resolve, reject) => { | ||
} | ||
if (renderToString) { | ||
return new core_1.HttpResponseOK(renderToString(template, locals)); | ||
} | ||
throw new Error(`${templateEngine} is not a template engine compatible with FoalTS.`); | ||
@@ -61,0 +59,0 @@ } |
@@ -7,7 +7,4 @@ /** | ||
* @param {string} passwordHash - The password hash generated by the `hashPassword` function. | ||
* @param {{ legacy?: boolean }} [options={}] | ||
* @returns {Promise<boolean>} True if the hash and the password match. False otherwise. | ||
*/ | ||
export declare function verifyPassword(plainTextPassword: string, passwordHash: string, options?: { | ||
legacy?: boolean; | ||
}): Promise<boolean>; | ||
export declare function verifyPassword(plainTextPassword: string, passwordHash: string): Promise<boolean>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.verifyPassword = void 0; | ||
const assert_1 = require("assert"); | ||
@@ -12,7 +13,5 @@ const crypto_1 = require("crypto"); | ||
* @param {string} passwordHash - The password hash generated by the `hashPassword` function. | ||
* @param {{ legacy?: boolean }} [options={}] | ||
* @returns {Promise<boolean>} True if the hash and the password match. False otherwise. | ||
*/ | ||
async function verifyPassword(plainTextPassword, passwordHash, options = {}) { | ||
const legacy = options.legacy || false; | ||
async function verifyPassword(plainTextPassword, passwordHash) { | ||
const [algorithm, iterations, salt, derivedKey] = passwordHash.split('$'); | ||
@@ -24,8 +23,8 @@ assert_1.strictEqual(algorithm, 'pbkdf2_sha256', 'Invalid algorithm.'); | ||
assert_1.strictEqual(isNaN(parseInt(iterations, 10)), false, 'Invalid password format.'); | ||
const saltBuffer = Buffer.from(salt, legacy ? 'hex' : 'base64'); | ||
const derivedKeyBuffer = Buffer.from(derivedKey, legacy ? 'hex' : 'base64'); | ||
const saltBuffer = Buffer.from(salt, 'base64'); | ||
const derivedKeyBuffer = Buffer.from(derivedKey, 'base64'); | ||
const digest = 'sha256'; // TODO: depends on the algorthim var | ||
const password = await util_1.promisify(crypto_1.pbkdf2)(plainTextPassword, legacy ? saltBuffer.toString('hex') : saltBuffer, parseInt(iterations, 10), derivedKeyBuffer.length, digest); | ||
const password = await util_1.promisify(crypto_1.pbkdf2)(plainTextPassword, saltBuffer, parseInt(iterations, 10), derivedKeyBuffer.length, digest); | ||
return crypto_1.timingSafeEqual(password, derivedKeyBuffer); | ||
} | ||
exports.verifyPassword = verifyPassword; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ConfigNotFoundError = void 0; | ||
const utils_1 = require("./utils"); | ||
class ConfigNotFoundError extends Error { | ||
constructor(key, msg) { | ||
super(`No value found for the configuration key "${key}".\n\n` | ||
+ (msg ? `${msg}\n\n` : '') | ||
+ 'To pass a value, you can use:\n' | ||
+ `- the environment variable ${utils_1.dotToUnderscore(key)},\n` | ||
+ `- the ".env" file with the variable ${utils_1.dotToUnderscore(key)},\n` | ||
+ `- the JSON file "config/${process.env.NODE_ENV || 'development'}.json" with the path "${key}",\n` | ||
+ `- the YAML file "config/${process.env.NODE_ENV || 'development'}.yml" with the path "${key}",\n` | ||
+ `- the JSON file "config/default.json" with the path "${key}", or\n` | ||
+ `- the YAML file "config/default.yml" with the path "${key}".`); | ||
super(); | ||
this.key = key; | ||
this.msg = msg; | ||
this.name = 'ConfigNotFoundError'; | ||
const keywords = key.split('.'); | ||
function generateContent(type) { | ||
const lines = []; | ||
if (type === 'JS') { | ||
lines.push(' const { Env } = require(\'@foal/core\');'); | ||
lines.push(''); | ||
} | ||
if (type !== 'YAML') { | ||
lines.push(' {'); | ||
} | ||
keywords.forEach((keyword, index) => { | ||
if (type === 'JSON') { | ||
keyword = `"${keyword}"`; | ||
} | ||
const spaces = ' '.repeat(index + (type === 'YAML' ? 1 : 2)); | ||
if (index === keywords.length - 1) { | ||
lines.push(spaces + keyword + ': <your_value>'); | ||
if (type === 'YAML') { | ||
lines.push(spaces + '# OR with an environment variable: '); | ||
} | ||
else { | ||
lines.push(spaces + '// OR with an environment variable: '); | ||
} | ||
let envValue = ''; | ||
switch (type) { | ||
case 'JS': | ||
envValue = 'Env.get(\'<YOUR_ENVIRONMENT_VARIABLE>\')'; | ||
break; | ||
case 'JSON': | ||
envValue = '"env(<YOUR_ENVIRONMENT_VARIABLE>)"'; | ||
break; | ||
case 'YAML': | ||
envValue = 'env(<YOUR_ENVIRONMENT_VARIABLE>)'; | ||
break; | ||
} | ||
lines.push(spaces + keyword + ': ' + envValue); | ||
} | ||
else { | ||
if (type === 'YAML') { | ||
lines.push(spaces + keyword + ':'); | ||
} | ||
else { | ||
lines.push(spaces + keyword + ': {'); | ||
} | ||
} | ||
}); | ||
if (type !== 'YAML') { | ||
keywords.forEach((_, index) => { | ||
if (index === keywords.length - 1) { | ||
return; | ||
} | ||
const spaces = ' '.repeat(keywords.length - index); | ||
lines.push(spaces + '}'); | ||
}); | ||
lines.push(' }'); | ||
} | ||
return lines; | ||
} | ||
this.message = '\n\n' | ||
+ utils_1.makeBox('JSON file (config/default.json, config/test.json, ...)', generateContent('JSON')) | ||
+ '\n' | ||
+ utils_1.makeBox('YAML file (config/default.yml, config/test.yml, ...)', generateContent('YAML')) | ||
+ '\n' | ||
+ utils_1.makeBox('JS file (config/default.js, config/test.js, ...)', generateContent('JS')) | ||
+ '\n' | ||
+ `No value found for the configuration key "${key}".\n` | ||
+ (msg === undefined ? '' : `\n${msg}\n`) | ||
+ '\n' | ||
+ `To pass a value, use one of the examples above.\n`; | ||
} | ||
} | ||
exports.ConfigNotFoundError = ConfigNotFoundError; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ConfigTypeError = void 0; | ||
const utils_1 = require("./utils"); | ||
class ConfigTypeError extends Error { | ||
constructor(key, expected, actual) { | ||
super(`The value of the configuration key "${key}" has an invalid type.\n` | ||
+ '\n' | ||
+ `Expected a "${expected}", but got a "${actual}".`); | ||
super(); | ||
this.key = key; | ||
@@ -12,4 +12,30 @@ this.expected = expected; | ||
this.name = 'ConfigTypeError'; | ||
const keywords = key.split('.'); | ||
const lines = []; | ||
lines.push(' {'); | ||
keywords.forEach((keyword, index) => { | ||
const spaces = ' '.repeat(index + 1); | ||
if (index === keywords.length - 1) { | ||
lines.push('->' + spaces + keyword + ': *************'); | ||
} | ||
else { | ||
lines.push(' ' + spaces + keyword + ': {'); | ||
} | ||
}); | ||
keywords.forEach((_, index) => { | ||
if (index === keywords.length - 1) { | ||
return; | ||
} | ||
const spaces = ' '.repeat(keywords.length - index); | ||
lines.push(spaces + '}'); | ||
}); | ||
lines.push(' }'); | ||
this.message = '\n\n' | ||
+ utils_1.makeBox('Configuration file', lines) | ||
+ '\n' | ||
+ `The value of the configuration key "${key}" has an invalid type.\n` | ||
+ '\n' | ||
+ `Expected a "${expected}", but got a "${actual}".\n`; | ||
} | ||
} | ||
exports.ConfigTypeError = ConfigTypeError; |
@@ -13,28 +13,2 @@ declare type ValueStringType = 'string' | 'number' | 'boolean' | 'boolean|string' | 'number|string' | 'any'; | ||
/** | ||
* Access environment variables and configuration files. | ||
* | ||
* For example, if it is called with the string `settings.session.secret`, | ||
* the method will go through these steps: | ||
* | ||
* 1. If the environment variable `SETTINGS_SESSION_SECRET` exists, then return its value. | ||
* 2. If `.env` exists and has a line `SETTINGS_SESSION_SECRET=`, then return its value. | ||
* 3. If `config/${NODE_ENV}.json` exists and the property `config['settings']['session']['secret']` | ||
* does too, then return its value. | ||
* 4. Same with `config/${NODE_ENV}.yml`. | ||
* 5. If `config/default.json` exists and the property `config['settings']['session']['secret']` | ||
* does too, then return its value. | ||
* 6. Same with `config/default.yml`. | ||
* | ||
* If none value is found, then the method returns the default value provided as second argument | ||
* to the function. If none was given, it returns undefined. | ||
* | ||
* @static | ||
* @template T - TypeScript type of the returned value. Default is `any`. | ||
* @param {string} key - Name of the config key using dots and camel case. | ||
* @param {T} [defaultValue] - Default value to return if no configuration is found with that key. | ||
* @returns {T} The configuration value. | ||
* @memberof Config | ||
*/ | ||
static get<T = any>(key: string, defaultValue?: T): T; | ||
/** | ||
* Read the configuration value associated with the given key. Optionaly check its type. | ||
@@ -50,4 +24,4 @@ * | ||
*/ | ||
static get2<T extends ValueStringType>(key: string, type: T, defaultValue: ValueType<T>): ValueType<T>; | ||
static get2<T extends ValueStringType>(key: string, type?: T): ValueType<T> | undefined; | ||
static get<T extends ValueStringType>(key: string, type: T, defaultValue: ValueType<T>): ValueType<T>; | ||
static get<T extends ValueStringType>(key: string, type?: T): ValueType<T> | undefined; | ||
/** | ||
@@ -74,37 +48,14 @@ * Read the configuration value associated with the given key. Optionaly check its type. | ||
static clearCache(): void; | ||
static set(key: string, value: string | number | boolean): void; | ||
static remove(key: string): void; | ||
private static yaml; | ||
private static cache; | ||
private static config; | ||
private static testConfig; | ||
private static readJSON; | ||
private static readYAML; | ||
private static readJS; | ||
private static readConfigValue; | ||
private static readDotEnvValue; | ||
private static readJSONValue; | ||
private static readYAMLValue; | ||
private static mergeDeep; | ||
private static getYAMLInstance; | ||
private static convertType; | ||
private static getValue; | ||
/** | ||
* Access environment variables and configuration files. | ||
* | ||
* For example, if it is called with the string `settings.session.secret`, | ||
* the method will go through these steps: | ||
* | ||
* 1. If the environment variable `SETTINGS_SESSION_SECRET` exists, then return its value. | ||
* 2. If `.env` exists and has a line `SETTINGS_SESSION_SECRET=`, then return its value. | ||
* 3. If `config/${NODE_ENV}.json` exists and the property `config['settings']['session']['secret']` | ||
* does too, then return its value. | ||
* 4. Same with `config/${NODE_ENV}.yml`. | ||
* 5. If `config/default.json` exists and the property `config['settings']['session']['secret']` | ||
* does too, then return its value. | ||
* 6. Same with `config/default.yml`. | ||
* | ||
* If none value is found, then the method returns the default value provided as second argument | ||
* to the function. If none was given, it returns undefined. | ||
* | ||
* @template T - TypeScript type of the returned value. Default is `any`. | ||
* @param {string} key - Name of the config key using dots and camel case. | ||
* @param {T} [defaultValue] - Default value to return if no configuration is found with that key. | ||
* @returns {T} The configuration value. | ||
* @memberof Config | ||
*/ | ||
get<T = any>(key: string, defaultValue?: T): T; | ||
} | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Config = void 0; | ||
// 3p | ||
const fs_1 = require("fs"); | ||
const path_1 = require("path"); | ||
// FoalTS | ||
const config_not_found_error_1 = require("./config-not-found.error"); | ||
const config_type_error_1 = require("./config-type.error"); | ||
const utils_1 = require("./utils"); | ||
const env_1 = require("./env"); | ||
/** | ||
@@ -18,38 +20,3 @@ * Static class to access environment variables and configuration files. | ||
class Config { | ||
/** | ||
* Access environment variables and configuration files. | ||
* | ||
* For example, if it is called with the string `settings.session.secret`, | ||
* the method will go through these steps: | ||
* | ||
* 1. If the environment variable `SETTINGS_SESSION_SECRET` exists, then return its value. | ||
* 2. If `.env` exists and has a line `SETTINGS_SESSION_SECRET=`, then return its value. | ||
* 3. If `config/${NODE_ENV}.json` exists and the property `config['settings']['session']['secret']` | ||
* does too, then return its value. | ||
* 4. Same with `config/${NODE_ENV}.yml`. | ||
* 5. If `config/default.json` exists and the property `config['settings']['session']['secret']` | ||
* does too, then return its value. | ||
* 6. Same with `config/default.yml`. | ||
* | ||
* If none value is found, then the method returns the default value provided as second argument | ||
* to the function. If none was given, it returns undefined. | ||
* | ||
* @static | ||
* @template T - TypeScript type of the returned value. Default is `any`. | ||
* @param {string} key - Name of the config key using dots and camel case. | ||
* @param {T} [defaultValue] - Default value to return if no configuration is found with that key. | ||
* @returns {T} The configuration value. | ||
* @memberof Config | ||
*/ | ||
static get(key, defaultValue) { | ||
let value = this.readConfigValue(key); | ||
if (typeof value === 'string') { | ||
value = this.convertType(value); | ||
} | ||
if (value !== undefined) { | ||
return value; | ||
} | ||
return defaultValue; | ||
} | ||
static get2(key, type, defaultValue) { | ||
static get(key, type, defaultValue) { | ||
const value = this.readConfigValue(key); | ||
@@ -59,3 +26,6 @@ if (value === undefined) { | ||
} | ||
if (type === 'boolean|string' && typeof value !== 'boolean') { | ||
if (type === 'string' && typeof value !== 'string') { | ||
throw new config_type_error_1.ConfigTypeError(key, 'string', typeof value); | ||
} | ||
if (type === 'boolean' && typeof value !== 'boolean') { | ||
if (value === 'true') { | ||
@@ -67,20 +37,4 @@ return true; | ||
} | ||
if (typeof value !== 'string') { | ||
throw new config_type_error_1.ConfigTypeError(key, 'boolean|string', typeof value); | ||
} | ||
throw new config_type_error_1.ConfigTypeError(key, 'boolean', typeof value); | ||
} | ||
if (type === 'number|string' && typeof value !== 'number') { | ||
if (typeof value !== 'string') { | ||
throw new config_type_error_1.ConfigTypeError(key, 'number|string', typeof value); | ||
} | ||
if (value.replace(/ /g, '') !== '') { | ||
const n = Number(value); | ||
if (!isNaN(n)) { | ||
return n; | ||
} | ||
} | ||
} | ||
if (type === 'string' && typeof value !== 'string') { | ||
throw new config_type_error_1.ConfigTypeError(key, 'string', typeof value); | ||
} | ||
if (type === 'number' && typeof value !== 'number') { | ||
@@ -95,3 +49,3 @@ if (typeof value === 'string' && value.replace(/ /g, '') !== '') { | ||
} | ||
if (type === 'boolean' && typeof value !== 'boolean') { | ||
if (type === 'boolean|string' && typeof value !== 'boolean') { | ||
if (value === 'true') { | ||
@@ -103,4 +57,17 @@ return true; | ||
} | ||
throw new config_type_error_1.ConfigTypeError(key, 'boolean', typeof value); | ||
if (typeof value !== 'string') { | ||
throw new config_type_error_1.ConfigTypeError(key, 'boolean|string', typeof value); | ||
} | ||
} | ||
if (type === 'number|string' && typeof value !== 'number') { | ||
if (typeof value !== 'string') { | ||
throw new config_type_error_1.ConfigTypeError(key, 'number|string', typeof value); | ||
} | ||
if (value.replace(/ /g, '') !== '') { | ||
const n = Number(value); | ||
if (!isNaN(n)) { | ||
return n; | ||
} | ||
} | ||
} | ||
return value; | ||
@@ -122,3 +89,3 @@ } | ||
static getOrThrow(key, type, msg) { | ||
const value = this.get2(key, type); | ||
const value = this.get(key, type); | ||
if (value === undefined) { | ||
@@ -136,80 +103,81 @@ throw new config_not_found_error_1.ConfigNotFoundError(key, msg); | ||
static clearCache() { | ||
this.cache = { | ||
dotEnv: undefined, | ||
json: {}, | ||
yaml: {}, | ||
}; | ||
this.config = null; | ||
this.testConfig.clear(); | ||
} | ||
static readConfigValue(key) { | ||
const underscoreName = utils_1.dotToUnderscore(key); | ||
const envValue = process.env[underscoreName]; | ||
if (envValue !== undefined) { | ||
return envValue; | ||
static set(key, value) { | ||
this.testConfig.set(key, value); | ||
} | ||
static remove(key) { | ||
this.testConfig.delete(key); | ||
} | ||
static readJSON(path) { | ||
if (!fs_1.existsSync(path)) { | ||
return {}; | ||
} | ||
const dotEnvValue = this.readDotEnvValue(underscoreName); | ||
if (dotEnvValue !== undefined) { | ||
return dotEnvValue; | ||
const fileContent = fs_1.readFileSync(path, 'utf8'); | ||
return JSON.parse(fileContent); | ||
} | ||
static readYAML(path) { | ||
if (!fs_1.existsSync(path)) { | ||
return {}; | ||
} | ||
const envJSONFilePath = `config/${process.env.NODE_ENV || 'development'}.json`; | ||
const envJSONValue = this.readJSONValue(envJSONFilePath, key); | ||
if (envJSONValue !== undefined) { | ||
return envJSONValue; | ||
const yaml = this.getYAMLInstance(); | ||
if (!yaml) { | ||
console.log(`Impossible to read ${path}. The package "yamljs" is not installed.`); | ||
return {}; | ||
} | ||
const envYamlFilePath = `config/${process.env.NODE_ENV || 'development'}.yml`; | ||
const envYAMLValue = this.readYAMLValue(envYamlFilePath, key); | ||
if (envYAMLValue !== undefined) { | ||
return envYAMLValue; | ||
const fileContent = fs_1.readFileSync(path, 'utf8'); | ||
return yaml.parse(fileContent); | ||
} | ||
static readJS(path) { | ||
if (!fs_1.existsSync(path)) { | ||
return {}; | ||
} | ||
const defaultJSONValue = this.readJSONValue('config/default.json', key); | ||
if (defaultJSONValue !== undefined) { | ||
return defaultJSONValue; | ||
return require(path_1.join(process.cwd(), path)); | ||
} | ||
static readConfigValue(key) { | ||
if (this.testConfig.has(key)) { | ||
return this.testConfig.get(key); | ||
} | ||
const defaultYAMLValue = this.readYAMLValue('config/default.yml', key); | ||
if (defaultYAMLValue !== undefined) { | ||
return defaultYAMLValue; | ||
if (this.config === null) { | ||
this.config = [ | ||
this.readJS('config/default.js'), | ||
this.readYAML('config/default.yml'), | ||
this.readJSON('config/default.json'), | ||
this.readJS(`config/${process.env.NODE_ENV || 'development'}.js`), | ||
this.readYAML(`config/${process.env.NODE_ENV || 'development'}.yml`), | ||
this.readJSON(`config/${process.env.NODE_ENV || 'development'}.json`), | ||
].reduce((config1, config2) => this.mergeDeep(config1, config2)); | ||
} | ||
} | ||
static readDotEnvValue(name) { | ||
if (!this.cache.dotEnv) { | ||
if (!fs_1.existsSync('.env')) { | ||
return; | ||
const properties = key.split('.'); | ||
let result = this.config; | ||
for (const property of properties) { | ||
result = result[property]; | ||
if (result === undefined) { | ||
break; | ||
} | ||
const envFileContent = fs_1.readFileSync('.env', 'utf8'); | ||
this.cache.dotEnv = {}; | ||
envFileContent.replace(/\r\n/g, '\n').split('\n').forEach(line => { | ||
const [key, ...values] = line.split('='); | ||
const value = values.join('='); | ||
this.cache.dotEnv[key] = value; | ||
}); | ||
} | ||
if (this.cache.dotEnv[name] !== undefined) { | ||
return this.cache.dotEnv[name]; | ||
if (typeof result === 'string' && result.startsWith('env(') && result.endsWith(')')) { | ||
const envVarName = result.substr(4, result.length - 5); | ||
return env_1.Env.get(envVarName); | ||
} | ||
return result; | ||
} | ||
static readJSONValue(path, key) { | ||
if (!this.cache.json[path]) { | ||
if (!fs_1.existsSync(path)) { | ||
return; | ||
} | ||
const fileContent = fs_1.readFileSync(path, 'utf8'); | ||
this.cache.json[path] = JSON.parse(fileContent); | ||
static mergeDeep(target, source) { | ||
// TODO: improve the tests of this function. | ||
function isObject(o) { | ||
return typeof o === 'object' && o !== null; | ||
} | ||
return this.getValue(this.cache.json[path], key); | ||
} | ||
static readYAMLValue(path, key) { | ||
if (!this.cache.yaml[path]) { | ||
if (!fs_1.existsSync(path)) { | ||
return; | ||
for (const key in source) { | ||
if (isObject(target[key]) && isObject(source[key])) { | ||
this.mergeDeep(target[key], source[key]); | ||
} | ||
const yaml = this.getYAMLInstance(); | ||
if (!yaml) { | ||
console.log(`Impossible to read ${path}. The package "yamljs" is not installed.`); | ||
return; | ||
else { | ||
target[key] = source[key]; | ||
} | ||
const fileContent = fs_1.readFileSync(path, 'utf8'); | ||
this.cache.yaml[path] = yaml.parse(fileContent); | ||
} | ||
return this.getValue(this.cache.yaml[path], key); | ||
return target; | ||
} | ||
static getYAMLInstance() { | ||
// TODO: test this method (hard). | ||
if (this.yaml === false) { | ||
@@ -229,62 +197,5 @@ return false; | ||
} | ||
static convertType(value) { | ||
if (value === 'true') { | ||
return true; | ||
} | ||
if (value === 'false') { | ||
return false; | ||
} | ||
if (value.replace(/ /g, '') === '') { | ||
return value; | ||
} | ||
const n = Number(value); | ||
if (!isNaN(n)) { | ||
return n; | ||
} | ||
return value; | ||
} | ||
static getValue(config, propertyPath) { | ||
const properties = propertyPath.split('.'); | ||
let result = config; | ||
for (const property of properties) { | ||
result = result[property]; | ||
if (result === undefined) { | ||
break; | ||
} | ||
} | ||
return result; | ||
} | ||
/** | ||
* Access environment variables and configuration files. | ||
* | ||
* For example, if it is called with the string `settings.session.secret`, | ||
* the method will go through these steps: | ||
* | ||
* 1. If the environment variable `SETTINGS_SESSION_SECRET` exists, then return its value. | ||
* 2. If `.env` exists and has a line `SETTINGS_SESSION_SECRET=`, then return its value. | ||
* 3. If `config/${NODE_ENV}.json` exists and the property `config['settings']['session']['secret']` | ||
* does too, then return its value. | ||
* 4. Same with `config/${NODE_ENV}.yml`. | ||
* 5. If `config/default.json` exists and the property `config['settings']['session']['secret']` | ||
* does too, then return its value. | ||
* 6. Same with `config/default.yml`. | ||
* | ||
* If none value is found, then the method returns the default value provided as second argument | ||
* to the function. If none was given, it returns undefined. | ||
* | ||
* @template T - TypeScript type of the returned value. Default is `any`. | ||
* @param {string} key - Name of the config key using dots and camel case. | ||
* @param {T} [defaultValue] - Default value to return if no configuration is found with that key. | ||
* @returns {T} The configuration value. | ||
* @memberof Config | ||
*/ | ||
get(key, defaultValue) { | ||
return Config.get(key, defaultValue); | ||
} | ||
} | ||
Config.cache = { | ||
dotEnv: undefined, | ||
json: {}, | ||
yaml: {}, | ||
}; | ||
exports.Config = Config; | ||
Config.config = null; | ||
Config.testConfig = new Map(); |
@@ -1,4 +0,4 @@ | ||
export { ConfigMock } from './config-mock'; | ||
export { ConfigNotFoundError } from './config-not-found.error'; | ||
export { ConfigTypeError } from './config-type.error'; | ||
export { Config } from './config'; | ||
export { Env } from './env'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var config_mock_1 = require("./config-mock"); | ||
exports.ConfigMock = config_mock_1.ConfigMock; | ||
exports.Env = exports.Config = exports.ConfigTypeError = exports.ConfigNotFoundError = void 0; | ||
var config_not_found_error_1 = require("./config-not-found.error"); | ||
exports.ConfigNotFoundError = config_not_found_error_1.ConfigNotFoundError; | ||
Object.defineProperty(exports, "ConfigNotFoundError", { enumerable: true, get: function () { return config_not_found_error_1.ConfigNotFoundError; } }); | ||
var config_type_error_1 = require("./config-type.error"); | ||
exports.ConfigTypeError = config_type_error_1.ConfigTypeError; | ||
Object.defineProperty(exports, "ConfigTypeError", { enumerable: true, get: function () { return config_type_error_1.ConfigTypeError; } }); | ||
var config_1 = require("./config"); | ||
exports.Config = config_1.Config; | ||
Object.defineProperty(exports, "Config", { enumerable: true, get: function () { return config_1.Config; } }); | ||
var env_1 = require("./env"); | ||
Object.defineProperty(exports, "Env", { enumerable: true, get: function () { return env_1.Env; } }); |
@@ -1,1 +0,1 @@ | ||
export declare function dotToUnderscore(str: string): string; | ||
export declare function makeBox(title: string, content: string[]): string; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
function dotToUnderscore(str) { | ||
return str | ||
.replace(/([A-Z])/g, letter => `_${letter}`) | ||
.replace(/\./g, '_') | ||
.toUpperCase(); | ||
exports.makeBox = void 0; | ||
function makeLine(str) { | ||
const length = 58; | ||
const spacesAfter = length - str.length; | ||
if (spacesAfter <= 0) { | ||
return str; | ||
} | ||
return '|' + str + ' '.repeat(spacesAfter) + '|\n'; | ||
} | ||
exports.dotToUnderscore = dotToUnderscore; | ||
function makeBox(title, content) { | ||
return ' --------------------------------------------------------\n' | ||
+ '| |\n' | ||
+ makeLine(' ' + title) | ||
+ '| |\n' | ||
+ '| -------------------------------------------------------- |\n' | ||
+ '| |\n' | ||
+ content.map(line => makeLine(line)).join('') | ||
+ '| |\n' | ||
+ ' --------------------------------------------------------\n'; | ||
} | ||
exports.makeBox = makeBox; |
import 'reflect-metadata'; | ||
import { Class } from './class.interface'; | ||
import { ServiceManager } from './service-manager'; | ||
/** | ||
@@ -10,6 +9,5 @@ * Create a new controller with its dependencies. | ||
* @param {Class<Controller>} controllerClass - The controller class. | ||
* @param {(object|ServiceManager)} [dependencies] - Either a ServiceManager or an | ||
* object which key/values are the controller properties/instances. | ||
* @param {object} [dependencies] - An object which key/values are the controller properties/instances. | ||
* @returns {Controller} - The created controller. | ||
*/ | ||
export declare function createController<Controller>(controllerClass: Class<Controller>, dependencies?: object | ServiceManager): Controller; | ||
export declare function createController<Controller>(controllerClass: Class<Controller>, dependencies?: object): Controller; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.createController = void 0; | ||
// 3p | ||
@@ -12,4 +13,3 @@ require("reflect-metadata"); | ||
* @param {Class<Controller>} controllerClass - The controller class. | ||
* @param {(object|ServiceManager)} [dependencies] - Either a ServiceManager or an | ||
* object which key/values are the controller properties/instances. | ||
* @param {object} [dependencies] - An object which key/values are the controller properties/instances. | ||
* @returns {Controller} - The created controller. | ||
@@ -16,0 +16,0 @@ */ |
import 'reflect-metadata'; | ||
import { Context, HttpResponse } from './http'; | ||
import { OpenApiDecorator } from './openapi'; | ||
import { ServiceManager } from './service-manager'; | ||
@@ -27,6 +28,8 @@ /** | ||
* @export | ||
* @param {...HookFunction[]} hookFunctions - The function(s) from which the hook should be created. | ||
* @param {HookFunction[]} hookFunction - The function from which the hook should be created. | ||
* @returns {HookDecorator} - The hook decorator. | ||
*/ | ||
export declare function Hook(...hookFunctions: HookFunction[]): HookDecorator; | ||
export declare function Hook(hookFunction: HookFunction, openApiDecorators?: OpenApiDecorator[], options?: { | ||
openapi?: boolean; | ||
}): HookDecorator; | ||
/** | ||
@@ -33,0 +36,0 @@ * Get the function from which the hook was made. |
@@ -9,4 +9,7 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.MergeHooks = exports.getHookFunctions = exports.getHookFunction = exports.Hook = void 0; | ||
// 3p | ||
require("reflect-metadata"); | ||
// FoalTS | ||
const config_1 = require("./config"); | ||
/** | ||
@@ -16,11 +19,19 @@ * Create a hook from one or several functions. | ||
* @export | ||
* @param {...HookFunction[]} hookFunctions - The function(s) from which the hook should be created. | ||
* @param {HookFunction[]} hookFunction - The function from which the hook should be created. | ||
* @returns {HookDecorator} - The hook decorator. | ||
*/ | ||
function Hook(...hookFunctions) { | ||
function Hook(hookFunction, openApiDecorators = [], options = {}) { | ||
return (target, propertyKey) => { | ||
var _a; | ||
// Note that propertyKey can be undefined as it's an optional parameter in getMetadata. | ||
const hooks = Reflect.getOwnMetadata('hooks', target, propertyKey) || []; | ||
hooks.unshift(...hookFunctions); | ||
hooks.unshift(hookFunction); | ||
Reflect.defineMetadata('hooks', hooks, target, propertyKey); | ||
// tslint:disable-next-line | ||
if (!((_a = options.openapi) !== null && _a !== void 0 ? _a : config_1.Config.get('settings.openapi.useHooks', 'boolean', true))) { | ||
return; | ||
} | ||
for (const openApiDecorator of openApiDecorators.reverse()) { | ||
openApiDecorator(target, propertyKey); | ||
} | ||
}; | ||
@@ -69,8 +80,8 @@ } | ||
function MergeHooks(...hookDecorators) { | ||
const hookFunctions = []; | ||
for (const hook of hookDecorators) { | ||
hookFunctions.push(...getHookFunctions(hook)); | ||
} | ||
return Hook(...hookFunctions); | ||
return (target, propertyKey) => { | ||
for (const hookDecorator of hookDecorators.reverse()) { | ||
hookDecorator(target, propertyKey); | ||
} | ||
}; | ||
} | ||
exports.MergeHooks = MergeHooks; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Context = void 0; | ||
/** | ||
@@ -4,0 +5,0 @@ * Class instantiated on each request. It includes: |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Delete = exports.Patch = exports.Put = exports.Post = exports.Get = exports.Options = exports.Head = void 0; | ||
// 3p | ||
@@ -4,0 +5,0 @@ require("reflect-metadata"); |
@@ -0,1 +1,2 @@ | ||
import { Context } from './contexts'; | ||
/** | ||
@@ -224,23 +225,2 @@ * Cookie options of the HttpResponse.setCookie method. | ||
/** | ||
* Create an HttpResponseOK whose content is the specified file. If returned in a controller, | ||
* the server sends the file in streaming. | ||
* | ||
* @param {Object} options - The options used to create the HttpResponseOK. | ||
* @param {string} options.directory - Directory where the file is located. | ||
* @param {string} options.file - Name of the file with its extension. If a path is given, | ||
* only the basename is kept. | ||
* @param {boolean} [options.forceDownload=false] - Indicate if the browser should download | ||
* the file directly without trying to display it in the window. | ||
* @param {filename} [options.string=options.file] - Default name used by the browser when | ||
* saving the file to the disk. | ||
* @deprecated | ||
* @returns {Promise<HttpResponseOK>} | ||
*/ | ||
export declare function createHttpResponseFile(options: { | ||
directory: string; | ||
file: string; | ||
forceDownload?: boolean; | ||
filename?: string; | ||
}): Promise<HttpResponseOK>; | ||
/** | ||
* Represent an HTTP response with the status 201 - CREATED. | ||
@@ -803,2 +783,4 @@ * | ||
readonly isHttpResponseInternalServerError = true; | ||
readonly error?: Error; | ||
readonly ctx?: Context; | ||
statusCode: number; | ||
@@ -813,2 +795,4 @@ statusMessage: string; | ||
stream?: boolean; | ||
error?: Error; | ||
ctx?: Context; | ||
}); | ||
@@ -815,0 +799,0 @@ } |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
// std | ||
const fs_1 = require("fs"); | ||
const path_1 = require("path"); | ||
const util_1 = require("util"); | ||
// 3p | ||
const mime_1 = require("mime"); | ||
exports.isHttpResponseNotImplemented = exports.HttpResponseNotImplemented = exports.isHttpResponseInternalServerError = exports.HttpResponseInternalServerError = exports.isHttpResponseServerError = exports.HttpResponseServerError = exports.isHttpResponseTooManyRequests = exports.HttpResponseTooManyRequests = exports.isHttpResponseConflict = exports.HttpResponseConflict = exports.isHttpResponseMethodNotAllowed = exports.HttpResponseMethodNotAllowed = exports.isHttpResponseNotFound = exports.HttpResponseNotFound = exports.isHttpResponseForbidden = exports.HttpResponseForbidden = exports.isHttpResponseUnauthorized = exports.HttpResponseUnauthorized = exports.isHttpResponseBadRequest = exports.HttpResponseBadRequest = exports.isHttpResponseClientError = exports.HttpResponseClientError = exports.isHttpResponseRedirect = exports.HttpResponseRedirect = exports.isHttpResponseMovedPermanently = exports.HttpResponseMovedPermanently = exports.isHttpResponseRedirection = exports.HttpResponseRedirection = exports.isHttpResponseNoContent = exports.HttpResponseNoContent = exports.isHttpResponseCreated = exports.HttpResponseCreated = exports.isHttpResponseOK = exports.HttpResponseOK = exports.isHttpResponseSuccess = exports.HttpResponseSuccess = exports.isHttpResponse = exports.HttpResponse = void 0; | ||
/** | ||
@@ -227,40 +222,2 @@ * Represent an HTTP response. This class must be extended. | ||
/** | ||
* Create an HttpResponseOK whose content is the specified file. If returned in a controller, | ||
* the server sends the file in streaming. | ||
* | ||
* @param {Object} options - The options used to create the HttpResponseOK. | ||
* @param {string} options.directory - Directory where the file is located. | ||
* @param {string} options.file - Name of the file with its extension. If a path is given, | ||
* only the basename is kept. | ||
* @param {boolean} [options.forceDownload=false] - Indicate if the browser should download | ||
* the file directly without trying to display it in the window. | ||
* @param {filename} [options.string=options.file] - Default name used by the browser when | ||
* saving the file to the disk. | ||
* @deprecated | ||
* @returns {Promise<HttpResponseOK>} | ||
*/ | ||
async function createHttpResponseFile(options) { | ||
const file = path_1.basename(options.file); | ||
const filePath = path_1.join(options.directory, file); | ||
if (!await new Promise(resolve => fs_1.exists(filePath, resolve))) { | ||
throw new Error(`The file "${filePath}" does not exist.`); | ||
} | ||
const stats = await util_1.promisify(fs_1.stat)(filePath); | ||
if (stats.isDirectory()) { | ||
throw new Error(`The directory "${filePath}" is not a file.`); | ||
} | ||
const stream = fs_1.createReadStream(filePath); | ||
const response = new HttpResponseOK(stream, { stream: true }); | ||
const mimeType = mime_1.getType(options.file); | ||
if (mimeType) { | ||
response.setHeader('Content-Type', mimeType); | ||
} | ||
response | ||
.setHeader('Content-Length', stats.size.toString()) | ||
.setHeader('Content-Disposition', (options.forceDownload ? 'attachment' : 'inline') | ||
+ `; filename="${options.filename || file}"`); | ||
return response; | ||
} | ||
exports.createHttpResponseFile = createHttpResponseFile; | ||
/** | ||
* Represent an HTTP response with the status 201 - CREATED. | ||
@@ -910,2 +867,4 @@ * | ||
this.statusMessage = 'INTERNAL SERVER ERROR'; | ||
this.error = options.error; | ||
this.ctx = options.ctx; | ||
} | ||
@@ -912,0 +871,0 @@ } |
"use strict"; | ||
function __export(m) { | ||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; | ||
} | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
__export(require("./contexts")); | ||
__export(require("./http-methods")); | ||
__export(require("./http-responses")); | ||
__exportStar(require("./contexts"), exports); | ||
__exportStar(require("./http-methods"), exports); | ||
__exportStar(require("./http-responses"), exports); |
@@ -0,4 +1,6 @@ | ||
export * from './app.controller.interface'; | ||
export * from './class.interface'; | ||
export { createController } from './controllers'; | ||
export * from './http'; | ||
export * from './openapi'; | ||
export * from './hooks'; | ||
@@ -5,0 +7,0 @@ export * from './routes'; |
"use strict"; | ||
function __export(m) { | ||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; | ||
} | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ServiceManager = exports.Dependency = exports.dependency = exports.createService = exports.createController = void 0; | ||
__exportStar(require("./app.controller.interface"), exports); | ||
__exportStar(require("./class.interface"), exports); | ||
var controllers_1 = require("./controllers"); | ||
exports.createController = controllers_1.createController; | ||
__export(require("./http")); | ||
__export(require("./hooks")); | ||
__export(require("./routes")); | ||
__export(require("./config")); | ||
Object.defineProperty(exports, "createController", { enumerable: true, get: function () { return controllers_1.createController; } }); | ||
__exportStar(require("./http"), exports); | ||
__exportStar(require("./openapi"), exports); | ||
__exportStar(require("./hooks"), exports); | ||
__exportStar(require("./routes"), exports); | ||
__exportStar(require("./config"), exports); | ||
var service_manager_1 = require("./service-manager"); | ||
exports.createService = service_manager_1.createService; | ||
exports.dependency = service_manager_1.dependency; | ||
exports.Dependency = service_manager_1.Dependency; | ||
exports.ServiceManager = service_manager_1.ServiceManager; | ||
Object.defineProperty(exports, "createService", { enumerable: true, get: function () { return service_manager_1.createService; } }); | ||
Object.defineProperty(exports, "dependency", { enumerable: true, get: function () { return service_manager_1.dependency; } }); | ||
Object.defineProperty(exports, "Dependency", { enumerable: true, get: function () { return service_manager_1.Dependency; } }); | ||
Object.defineProperty(exports, "ServiceManager", { enumerable: true, get: function () { return service_manager_1.ServiceManager; } }); |
@@ -1,3 +0,3 @@ | ||
export * from './route.interface'; | ||
export * from './get-response'; | ||
export { makeControllerRoutes } from './make-controller-routes'; | ||
export { getPath, getHttpMethod } from './utils'; |
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.getHttpMethod = exports.getPath = exports.makeControllerRoutes = void 0; | ||
__exportStar(require("./get-response"), exports); | ||
var make_controller_routes_1 = require("./make-controller-routes"); | ||
exports.makeControllerRoutes = make_controller_routes_1.makeControllerRoutes; | ||
Object.defineProperty(exports, "makeControllerRoutes", { enumerable: true, get: function () { return make_controller_routes_1.makeControllerRoutes; } }); | ||
var utils_1 = require("./utils"); | ||
exports.getPath = utils_1.getPath; | ||
exports.getHttpMethod = utils_1.getHttpMethod; | ||
Object.defineProperty(exports, "getPath", { enumerable: true, get: function () { return utils_1.getPath; } }); | ||
Object.defineProperty(exports, "getHttpMethod", { enumerable: true, get: function () { return utils_1.getHttpMethod; } }); |
import { Class } from '../class.interface'; | ||
import { HookFunction } from '../hooks'; | ||
import { IApiComponents, IApiOperation, IApiTag } from '../openapi'; | ||
import { ServiceManager } from '../service-manager'; | ||
@@ -23,2 +23,7 @@ import { Route } from './route.interface'; | ||
*/ | ||
export declare function makeControllerRoutes(parentPath: string, parentHooks: HookFunction[], controllerClass: Class, services: ServiceManager): Route[]; | ||
export declare function makeControllerRoutes(controllerClass: Class, services: ServiceManager, openapi?: boolean, documentControllers?: object[]): Generator<{ | ||
route: Route; | ||
components: IApiComponents; | ||
operation: IApiOperation; | ||
tags?: IApiTag[]; | ||
}>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.makeControllerRoutes = exports.getMethods = void 0; | ||
const openapi_1 = require("../openapi"); | ||
const utils_1 = require("./utils"); | ||
@@ -17,2 +19,29 @@ /** | ||
exports.getMethods = getMethods; | ||
function normalizePath(path) { | ||
return (path.startsWith('/') ? path : `/${path}`) | ||
.replace(/\:\w*/g, $1 => `{${$1.slice(1)}}`); | ||
} | ||
function throwErrorIfDuplicatePaths(paths) { | ||
const originalPaths = []; | ||
const convertedPaths = []; | ||
for (const path in paths) { | ||
const convertedPath = path.replace(/{.*}/g, () => '#'); | ||
const index = convertedPaths.indexOf(convertedPath); | ||
if (index !== -1) { | ||
throw new Error('[OpenAPI] Templated paths with the same hierarchy but different templated names' | ||
+ ' MUST NOT exist as they are identical.' | ||
+ `\n Path 1: ${originalPaths[index]}` | ||
+ `\n Path 2: ${path}`); | ||
} | ||
originalPaths.push(path); | ||
convertedPaths.push(convertedPath); | ||
} | ||
} | ||
function getPath(controllerClass, propertyKey) { | ||
return utils_1.getMetadata('path', controllerClass, propertyKey) || ''; | ||
} | ||
function getHooks(controllerClass, controller, propertyKey) { | ||
return (utils_1.getMetadata('hooks', controllerClass, propertyKey) || []) | ||
.map(hook => hook.bind(controller)); | ||
} | ||
/** | ||
@@ -29,28 +58,102 @@ * Recursively create the routes of a controller and its subcontrollers from the | ||
*/ | ||
function makeControllerRoutes(parentPath, parentHooks, controllerClass, services) { | ||
const routes = []; | ||
const controllerHooks = utils_1.getMetadata('hooks', controllerClass) || []; | ||
const controllerPath = utils_1.getMetadata('path', controllerClass); | ||
function* makeControllerRoutes(controllerClass, services, openapi = false, documentControllers) { | ||
// FoalTS stores as well the controllers in the service manager. | ||
const controller = services.get(controllerClass); | ||
const leftPath = utils_1.join(parentPath, controllerPath); | ||
const leftHooks = parentHooks.concat(controllerHooks.map(hook => hook.bind(controller))); | ||
const controllerPath = getPath(controllerClass); | ||
const controllerHooks = getHooks(controllerClass, controller); | ||
/* OpenAPI */ | ||
const info = openapi_1.getApiInfo(controllerClass); | ||
// Check if the controller is inside an OpenAPI api. If not, components, operations and tags are discarded. | ||
openapi = !!info || openapi; | ||
/* OpenAPI */ | ||
const controllerComponents = openapi ? openapi_1.getApiComponents(controllerClass, controller) : {}; | ||
const controllerOperation = openapi ? openapi_1.getApiCompleteOperation(controllerClass, controller) : { responses: {} }; | ||
const controllerTags = openapi ? openapi_1.getApiTags(controllerClass) : undefined; | ||
if (openapi) { | ||
delete controllerOperation.servers; | ||
delete controllerOperation.externalDocs; | ||
delete controllerOperation.security; | ||
} | ||
/* OpenAPI */ | ||
const openApi = services.get(openapi_1.OpenApi); | ||
let document; | ||
/* OpenAPI */ | ||
if (info) { | ||
document = { | ||
info: typeof info === 'function' ? info(controller) : info, | ||
openapi: '3.0.0', | ||
paths: {} | ||
}; | ||
const operation = openapi_1.getApiCompleteOperation(controllerClass, controller); | ||
if (operation.servers) { | ||
document.servers = operation.servers; | ||
} | ||
if (operation.security) { | ||
document.security = operation.security; | ||
} | ||
if (operation.externalDocs) { | ||
document.externalDocs = operation.externalDocs; | ||
} | ||
document.components = controllerComponents; | ||
document.tags = controllerTags; | ||
} | ||
documentControllers = document ? [] : documentControllers; | ||
if (documentControllers) { | ||
documentControllers.push(controller); | ||
} | ||
function processRoute(route, components, operation, tags) { | ||
/* OpenAPI */ | ||
if (document) { | ||
const normalizedPath = normalizePath(route.path); | ||
document.paths[normalizedPath] = Object.assign(Object.assign({}, document.paths[normalizedPath]), { [route.httpMethod.toLowerCase()]: openapi_1.mergeOperations(controllerOperation, operation) }); | ||
document.tags = Array.from(new Set(openapi_1.mergeTags(document.tags, tags))); | ||
document.components = openapi_1.mergeComponents(document.components || {}, components); | ||
} | ||
return { | ||
// OpenAPI | ||
components: openapi ? openapi_1.mergeComponents(controllerComponents, components) : {}, | ||
// OpenAPI | ||
operation: openapi ? openapi_1.mergeOperations(controllerOperation, operation) : { responses: {} }, | ||
route: { | ||
controller: route.controller, | ||
hooks: controllerHooks.concat(route.hooks), | ||
httpMethod: route.httpMethod, | ||
path: utils_1.join(controllerPath, route.path), | ||
propertyKey: route.propertyKey, | ||
}, | ||
// OpenAPI | ||
tags: openapi ? openapi_1.mergeTags(controllerTags, tags) : undefined | ||
}; | ||
} | ||
for (const controllerClass of controller.subControllers || []) { | ||
routes.push(...makeControllerRoutes(leftPath, leftHooks, controllerClass, services)); | ||
for (const { route, components, operation, tags } of makeControllerRoutes(controllerClass, services, openapi, documentControllers)) { | ||
yield processRoute(route, components, operation, tags); | ||
} | ||
} | ||
getMethods(controllerClass.prototype).forEach(propertyKey => { | ||
if (propertyKey === 'constructor') { | ||
return; | ||
} | ||
for (const propertyKey of getMethods(controllerClass.prototype)) { | ||
const httpMethod = utils_1.getMetadata('httpMethod', controllerClass, propertyKey); | ||
if (httpMethod) { | ||
const methodPath = utils_1.getMetadata('path', controllerClass, propertyKey); | ||
const methodHooks = utils_1.getMetadata('hooks', controllerClass, propertyKey) || []; | ||
const path = utils_1.join(leftPath, methodPath); | ||
const hooks = [...leftHooks, ...methodHooks.map(hook => hook.bind(controller))]; | ||
routes.push({ controller, hooks, httpMethod, path, propertyKey }); | ||
if (!httpMethod) { | ||
continue; | ||
} | ||
}); | ||
return routes; | ||
const path = getPath(controllerClass, propertyKey); | ||
const hooks = getHooks(controllerClass, controller, propertyKey); | ||
const route = { controller, hooks, httpMethod, path, propertyKey }; | ||
/* OpenAPI */ | ||
const components = openapi ? openapi_1.getApiComponents(controllerClass, controller, propertyKey) : {}; | ||
const operation = openapi ? openapi_1.getApiCompleteOperation(controllerClass, controller, propertyKey) : { responses: {} }; | ||
const tags = openapi ? openapi_1.getApiTags(controllerClass, propertyKey) : undefined; | ||
yield processRoute(route, components, operation, tags); | ||
} | ||
/* OpenAPI */ | ||
if (document) { | ||
if (document.components && Object.keys(document.components).length === 0) { | ||
delete document.components; | ||
} | ||
if (document.tags && Object.keys(document.tags).length === 0) { | ||
delete document.tags; | ||
} | ||
throwErrorIfDuplicatePaths(document.paths); | ||
openApi.addDocument(controllerClass, document, documentControllers); | ||
} | ||
} | ||
exports.makeControllerRoutes = makeControllerRoutes; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.join = exports.getPath = exports.getHttpMethod = exports.getMetadata = void 0; | ||
// 3p | ||
@@ -4,0 +5,0 @@ require("reflect-metadata"); |
@@ -5,3 +5,3 @@ import 'reflect-metadata'; | ||
propertyKey: string; | ||
serviceClass: string | Class; | ||
serviceClassOrID: string | Class; | ||
} | ||
@@ -26,8 +26,7 @@ /** | ||
* @param {ClassOrAbstractClass<Service>} serviceClass - The service class. | ||
* @param {(object|ServiceManager)} [dependencies] - Either a ServiceManager or an | ||
* object which key/values are the service properties/instances. | ||
* @param {object} [dependencies] - An object which key/values are the service properties/instances. | ||
* @returns {Service} - The created service. | ||
*/ | ||
export declare function createService<Service>(serviceClass: ClassOrAbstractClass<Service>, dependencies?: object | ServiceManager): Service; | ||
export declare function createControllerOrService<T>(serviceClass: ClassOrAbstractClass<T>, dependencies?: object | ServiceManager): T; | ||
export declare function createService<Service>(serviceClass: ClassOrAbstractClass<Service>, dependencies?: object): Service; | ||
export declare function createControllerOrService<T>(serviceClass: ClassOrAbstractClass<T>, dependencies?: object): T; | ||
/** | ||
@@ -34,0 +33,0 @@ * Identity Mapper that instantiates and returns service singletons. |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ServiceManager = exports.createControllerOrService = exports.createService = exports.dependency = exports.Dependency = void 0; | ||
// std | ||
@@ -16,3 +17,3 @@ const path_1 = require("path"); | ||
const dependencies = [...(Reflect.getMetadata('dependencies', target) || [])]; | ||
dependencies.push({ propertyKey, serviceClass: id }); | ||
dependencies.push({ propertyKey, serviceClassOrID: id }); | ||
Reflect.defineMetadata('dependencies', dependencies, target); | ||
@@ -30,3 +31,3 @@ }; | ||
const dependencies = [...(Reflect.getMetadata('dependencies', target) || [])]; | ||
dependencies.push({ propertyKey, serviceClass }); | ||
dependencies.push({ propertyKey, serviceClassOrID: serviceClass }); | ||
Reflect.defineMetadata('dependencies', dependencies, target); | ||
@@ -41,4 +42,3 @@ } | ||
* @param {ClassOrAbstractClass<Service>} serviceClass - The service class. | ||
* @param {(object|ServiceManager)} [dependencies] - Either a ServiceManager or an | ||
* object which key/values are the service properties/instances. | ||
* @param {object} [dependencies] - An object which key/values are the service properties/instances. | ||
* @returns {Service} - The created service. | ||
@@ -52,11 +52,8 @@ */ | ||
const metadata = Reflect.getMetadata('dependencies', serviceClass.prototype) || []; | ||
let serviceManager = new ServiceManager(); | ||
if (dependencies instanceof ServiceManager) { | ||
serviceManager = dependencies; | ||
} | ||
else if (typeof dependencies === 'object') { | ||
const serviceManager = new ServiceManager(); | ||
if (dependencies) { | ||
metadata.forEach(dep => { | ||
const serviceMock = dependencies[dep.propertyKey]; | ||
if (serviceMock) { | ||
serviceManager.set(dep.serviceClass, serviceMock); | ||
serviceManager.set(dep.serviceClassOrID, serviceMock); | ||
} | ||
@@ -144,3 +141,3 @@ }); | ||
for (const dependency of dependencies) { | ||
service[dependency.propertyKey] = this.get(dependency.serviceClass); | ||
service[dependency.propertyKey] = this.get(dependency.serviceClassOrID); | ||
} | ||
@@ -165,3 +162,3 @@ // Save the service. | ||
if (cls.hasOwnProperty('defaultConcreteClassPath')) { | ||
concreteClassPath = config_1.Config.get2(concreteClassConfigPath, 'string', 'local'); | ||
concreteClassPath = config_1.Config.get(concreteClassConfigPath, 'string', 'local'); | ||
} | ||
@@ -168,0 +165,0 @@ else { |
@@ -1,3 +0,3 @@ | ||
import { Class, ServiceManager } from '../core'; | ||
export declare type ExpressApplication = any; | ||
import { Class, IAppController, ServiceManager } from '../core'; | ||
export declare const OPENAPI_SERVICE_ID = "OPENAPI_SERVICE_ID_a5NWKbBNBxVVZ"; | ||
declare type Middleware = (req: any, res: any, next: (err?: any) => any) => any; | ||
@@ -7,5 +7,2 @@ declare type ErrorMiddleware = (err: any, req: any, res: any, next: (err?: any) => any) => any; | ||
expressInstance?: any; | ||
methods?: { | ||
handleError?: boolean; | ||
}; | ||
serviceManager?: ServiceManager; | ||
@@ -19,38 +16,18 @@ preMiddlewares?: (Middleware | ErrorMiddleware)[]; | ||
* @export | ||
* @param {Class} AppController - The root controller, usually called `AppController` and located in `src/app`. | ||
* @param {(any|CreateAppOptions)} [expressInstanceOrOptions] - Express instance or options containaining | ||
* Express middlewares or other settings. | ||
* @param {any} [expressInstanceOrOptions.expressInstance] - Express instance to be used as base for the | ||
* @param {Class<IAppController>} AppController - The root controller, usually called `AppController` | ||
* and located in `src/app`. | ||
* @param {CreateAppOptions} [options] - Options containaining Express middlewares or other settings. | ||
* @param {any} [options.expressInstance] - Express instance to be used as base for the | ||
* returned application. | ||
* @param {boolean} [expressInstanceOrOptions.methods.handleError] - Specifies if AppController.handleError should be | ||
* @param {boolean} [options.methods.handleError] - Specifies if AppController.handleError should be | ||
* used to handle errors. | ||
* @param {ServiceManager} [expressInstanceOrOptions.serviceManager] - Prebuilt and configured Service Manager for | ||
* @param {ServiceManager} [options.serviceManager] - Prebuilt and configured Service Manager for | ||
* optionally overriding the mapped identities. | ||
* @param {(RequestHandler | ErrorRequestHandler)[]} [expressInstanceOrOptions.preMiddlewares] Express | ||
* @param {(RequestHandler | ErrorRequestHandler)[]} [options.preMiddlewares] Express | ||
* middlewares to be executed before the controllers and hooks. | ||
* @param {(RequestHandler | ErrorRequestHandler)[]} [expressInstanceOrOptions.postMiddlewares] Express | ||
* @param {(RequestHandler | ErrorRequestHandler)[]} [options.postMiddlewares] Express | ||
* middlewares to be executed after the controllers and hooks, but before the 500 or 404 handler get called. | ||
* @returns {any} The express application. | ||
*/ | ||
export declare function createApp(AppController: Class, expressInstanceOrOptions?: any | CreateAppOptions): any; | ||
/** | ||
* Create an Express application from the root controller and call its "init" method if it exists. | ||
* | ||
* @export | ||
* @param {Class} AppController - The root controller, usually called `AppController` and located in `src/app`. | ||
* @param {(any|CreateAppOptions)} [expressInstanceOrOptions] - Express instance or options containaining | ||
* Express middlewares or other settings. | ||
* @param {any} [expressInstanceOrOptions.expressInstance] - Express instance to be used as base for the | ||
* returned application. | ||
* @param {boolean} [expressInstanceOrOptions.methods.handleError] - Specifies if AppController.handleError should be | ||
* used to handle errors. | ||
* @param {ServiceManager} [expressInstanceOrOptions.serviceManager] - Prebuilt and configured Service Manager for | ||
* optionally overriding the mapped identities. | ||
* @param {(RequestHandler | ErrorRequestHandler)[]} [expressInstanceOrOptions.preMiddlewares] Express | ||
* middlewares to be executed before the controllers and hooks. | ||
* @param {(RequestHandler | ErrorRequestHandler)[]} [expressInstanceOrOptions.postMiddlewares] Express | ||
* middlewares to be executed after the controllers and hooks, but before the 500 or 404 handler get called. | ||
* @returns {Promise<any>} The express application. | ||
*/ | ||
export declare function createAndInitApp(AppController: Class, expressInstanceOrOptions?: any | CreateAppOptions): Promise<any>; | ||
export declare function createApp(AppController: Class<IAppController>, options?: CreateAppOptions): Promise<any>; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.createApp = exports.OPENAPI_SERVICE_ID = void 0; | ||
// 3p | ||
@@ -9,5 +10,4 @@ const cookieParser = require("cookie-parser"); | ||
const core_1 = require("../core"); | ||
const create_middleware_1 = require("./create-middleware"); | ||
const handle_errors_1 = require("./handle-errors"); | ||
const not_found_1 = require("./not-found"); | ||
const send_response_1 = require("./send-response"); | ||
exports.OPENAPI_SERVICE_ID = 'OPENAPI_SERVICE_ID_a5NWKbBNBxVVZ'; | ||
function handleJsonErrors(err, req, res, next) { | ||
@@ -26,4 +26,2 @@ if (err.type !== 'entity.parse.failed') { | ||
res.setHeader('X-Content-Type-Options', 'nosniff'); | ||
res.setHeader('X-DNS-Prefetch-Control', 'off'); | ||
res.setHeader('X-Download-Options', 'noopen'); | ||
res.setHeader('X-Frame-Options', 'SAMEORIGIN'); | ||
@@ -34,11 +32,2 @@ res.setHeader('X-XSS-Protection', '1; mode=block'); | ||
} | ||
function getOptions(expressInstanceOrOptions) { | ||
if (!expressInstanceOrOptions) { | ||
return {}; | ||
} | ||
if (typeof expressInstanceOrOptions === 'function') { | ||
return { expressInstance: expressInstanceOrOptions }; | ||
} | ||
return expressInstanceOrOptions; | ||
} | ||
/** | ||
@@ -48,19 +37,18 @@ * Create an Express application from the root controller. | ||
* @export | ||
* @param {Class} AppController - The root controller, usually called `AppController` and located in `src/app`. | ||
* @param {(any|CreateAppOptions)} [expressInstanceOrOptions] - Express instance or options containaining | ||
* Express middlewares or other settings. | ||
* @param {any} [expressInstanceOrOptions.expressInstance] - Express instance to be used as base for the | ||
* @param {Class<IAppController>} AppController - The root controller, usually called `AppController` | ||
* and located in `src/app`. | ||
* @param {CreateAppOptions} [options] - Options containaining Express middlewares or other settings. | ||
* @param {any} [options.expressInstance] - Express instance to be used as base for the | ||
* returned application. | ||
* @param {boolean} [expressInstanceOrOptions.methods.handleError] - Specifies if AppController.handleError should be | ||
* @param {boolean} [options.methods.handleError] - Specifies if AppController.handleError should be | ||
* used to handle errors. | ||
* @param {ServiceManager} [expressInstanceOrOptions.serviceManager] - Prebuilt and configured Service Manager for | ||
* @param {ServiceManager} [options.serviceManager] - Prebuilt and configured Service Manager for | ||
* optionally overriding the mapped identities. | ||
* @param {(RequestHandler | ErrorRequestHandler)[]} [expressInstanceOrOptions.preMiddlewares] Express | ||
* @param {(RequestHandler | ErrorRequestHandler)[]} [options.preMiddlewares] Express | ||
* middlewares to be executed before the controllers and hooks. | ||
* @param {(RequestHandler | ErrorRequestHandler)[]} [expressInstanceOrOptions.postMiddlewares] Express | ||
* @param {(RequestHandler | ErrorRequestHandler)[]} [options.postMiddlewares] Express | ||
* middlewares to be executed after the controllers and hooks, but before the 500 or 404 handler get called. | ||
* @returns {any} The express application. | ||
* @returns {Promise<any>} The express application. | ||
*/ | ||
function createApp(AppController, expressInstanceOrOptions) { | ||
const options = getOptions(expressInstanceOrOptions); | ||
async function createApp(AppController, options = {}) { | ||
const app = options.expressInstance || express(); | ||
@@ -72,3 +60,3 @@ // Add optional pre-middlewares. | ||
// Log requests. | ||
const loggerFormat = core_1.Config.get2('settings.loggerFormat', 'string', '[:date] ":method :url HTTP/:http-version" :status - :response-time ms'); | ||
const loggerFormat = core_1.Config.get('settings.loggerFormat', 'string', '[:date] ":method :url HTTP/:http-version" :status - :response-time ms'); | ||
if (loggerFormat !== 'none') { | ||
@@ -79,5 +67,5 @@ app.use(logger(loggerFormat)); | ||
// Serve static files. | ||
app.use(core_1.Config.get2('settings.staticPathPrefix', 'string', ''), express.static(core_1.Config.get2('settings.staticPath', 'string', 'public'))); | ||
app.use(core_1.Config.get('settings.staticPathPrefix', 'string', ''), express.static(core_1.Config.get('settings.staticPath', 'string', 'public'))); | ||
// Parse request body. | ||
const limit = core_1.Config.get2('settings.bodyParser.limit', 'number|string'); | ||
const limit = core_1.Config.get('settings.bodyParser.limit', 'number|string'); | ||
app.use(express.json({ limit })); | ||
@@ -92,6 +80,25 @@ app.use(handleJsonErrors); | ||
app.foal = { services }; | ||
// Inject the OpenAPI service with an ID string to avoid duplicated singletons | ||
// across several npm packages. | ||
services.set(exports.OPENAPI_SERVICE_ID, services.get(core_1.OpenApi)); | ||
// Retrieve the AppController instance. | ||
const appController = services.get(AppController); | ||
// Resolve the controllers and hooks and add them to the express instance. | ||
const routes = core_1.makeControllerRoutes('', [], AppController, services); | ||
for (const route of routes) { | ||
app[route.httpMethod.toLowerCase()](route.path, create_middleware_1.createMiddleware(route, services)); | ||
const routes = core_1.makeControllerRoutes(AppController, services); | ||
for (const { route } of routes) { | ||
app[route.httpMethod.toLowerCase()](route.path, async (req, res, next) => { | ||
try { | ||
const ctx = new core_1.Context(req); | ||
// TODO: better test this line. | ||
const response = await core_1.getResponse(route, ctx, services, appController); | ||
send_response_1.sendResponse(response, res); | ||
} | ||
catch (error) { | ||
// This try/catch will never be called: the `getResponse` function catches any errors | ||
// thrown or rejected in the application and converts it into a response. | ||
// However, for more security, this line has been added to avoid crashing the server | ||
// in case the function is badly implemented. | ||
next(error); | ||
} | ||
}); | ||
} | ||
@@ -102,36 +109,8 @@ // Add optional post-middlewares. | ||
} | ||
// Handle errors. | ||
app.use(not_found_1.notFound()); | ||
const controller = app.foal.services.get(AppController); | ||
app.use(handle_errors_1.handleErrors(options, controller)); | ||
await services.boot(); | ||
if (appController.init) { | ||
await appController.init(); | ||
} | ||
return app; | ||
} | ||
exports.createApp = createApp; | ||
/** | ||
* Create an Express application from the root controller and call its "init" method if it exists. | ||
* | ||
* @export | ||
* @param {Class} AppController - The root controller, usually called `AppController` and located in `src/app`. | ||
* @param {(any|CreateAppOptions)} [expressInstanceOrOptions] - Express instance or options containaining | ||
* Express middlewares or other settings. | ||
* @param {any} [expressInstanceOrOptions.expressInstance] - Express instance to be used as base for the | ||
* returned application. | ||
* @param {boolean} [expressInstanceOrOptions.methods.handleError] - Specifies if AppController.handleError should be | ||
* used to handle errors. | ||
* @param {ServiceManager} [expressInstanceOrOptions.serviceManager] - Prebuilt and configured Service Manager for | ||
* optionally overriding the mapped identities. | ||
* @param {(RequestHandler | ErrorRequestHandler)[]} [expressInstanceOrOptions.preMiddlewares] Express | ||
* middlewares to be executed before the controllers and hooks. | ||
* @param {(RequestHandler | ErrorRequestHandler)[]} [expressInstanceOrOptions.postMiddlewares] Express | ||
* middlewares to be executed after the controllers and hooks, but before the 500 or 404 handler get called. | ||
* @returns {Promise<any>} The express application. | ||
*/ | ||
async function createAndInitApp(AppController, expressInstanceOrOptions) { | ||
const app = createApp(AppController, expressInstanceOrOptions); | ||
const controller = app.foal.services.get(AppController); | ||
if (controller.init) { | ||
await controller.init(); | ||
} | ||
return app; | ||
} | ||
exports.createAndInitApp = createAndInitApp; |
@@ -1,1 +0,1 @@ | ||
export { createApp, createAndInitApp, ExpressApplication } from './create-app'; | ||
export { createApp, OPENAPI_SERVICE_ID } from './create-app'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.OPENAPI_SERVICE_ID = exports.createApp = void 0; | ||
var create_app_1 = require("./create-app"); | ||
exports.createApp = create_app_1.createApp; | ||
exports.createAndInitApp = create_app_1.createAndInitApp; | ||
Object.defineProperty(exports, "createApp", { enumerable: true, get: function () { return create_app_1.createApp; } }); | ||
Object.defineProperty(exports, "OPENAPI_SERVICE_ID", { enumerable: true, get: function () { return create_app_1.OPENAPI_SERVICE_ID; } }); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
// 3p | ||
const pump = require("pump"); | ||
exports.sendResponse = void 0; | ||
// std | ||
const stream_1 = require("stream"); | ||
// FoalTS | ||
@@ -35,3 +36,7 @@ const core_1 = require("../core"); | ||
if (response.stream === true) { | ||
pump(response.body, res); | ||
stream_1.pipeline(response.body, res, err => { | ||
if (err) { | ||
console.log(err); | ||
} | ||
}); | ||
return; | ||
@@ -38,0 +43,0 @@ } |
@@ -6,6 +6,5 @@ /** | ||
*/ | ||
export * from './common'; | ||
export * from './core'; | ||
export * from './express'; | ||
export * from './openapi'; | ||
export * from './sessions'; | ||
export { Log, LogOptions, UserRequired, ValidateBody, ValidateCookie, ValidateHeader, ValidatePathParam, ValidateQueryParam, controller, convertBase64ToBase64url, escape, escapeProp, generateSignedToken, generateToken, getAjvInstance, hashPassword, isInFile, render, renderError, signToken, verifyPassword, verifySignedToken, } from './common'; | ||
export { ApiCallback, ApiDefineCallback, ApiDefineExample, ApiDefineHeader, ApiDefineLink, ApiDefineParameter, ApiDefineRequestBody, ApiDefineResponse, ApiDefineSchema, ApiDefineSecurityScheme, ApiDefineTag, ApiDeprecated, ApiExternalDoc, ApiInfo, ApiOperation, ApiOperationDescription, ApiOperationId, ApiOperationSummary, ApiParameter, ApiRequestBody, ApiResponse, ApiSecurityRequirement, ApiServer, ApiUseTag, Class, ClassOrAbstractClass, Config, ConfigNotFoundError, ConfigTypeError, Context, CookieOptions, Delete, Dependency, Env, Get, Head, Hook, HookDecorator, HookFunction, HookPostFunction, HttpMethod, HttpResponse, HttpResponseBadRequest, HttpResponseClientError, HttpResponseConflict, HttpResponseCreated, HttpResponseForbidden, HttpResponseInternalServerError, HttpResponseMethodNotAllowed, HttpResponseMovedPermanently, HttpResponseNoContent, HttpResponseNotFound, HttpResponseNotImplemented, HttpResponseOK, HttpResponseRedirect, HttpResponseRedirection, HttpResponseServerError, HttpResponseSuccess, HttpResponseTooManyRequests, HttpResponseUnauthorized, IApiAbstractParameter, IApiAbstractSecurityScheme, IApiApiKeySecurityScheme, IApiAuthorizationCodeOAuthFlow, IApiCallback, IApiClientCredentialsOAuthFlow, IApiComponents, IApiContact, IApiCookieParameter, IApiDiscriminator, IApiEncoding, IApiExample, IApiExternalDocumentation, IApiHeader, IApiHeaderParameter, IApiHttpSecurityScheme, IApiImplicitOAuthFlow, IApiInfo, IApiLicense, IApiLink, IApiMediaType, IApiOAuth2SecurityScheme, IApiOAuthFlow, IApiOAuthFlows, IApiOpenIdConnectSecurityScheme, IApiOperation, IApiParameter, IApiPasswordOAuthFlow, IApiPathItem, IApiPathParameter, IApiPaths, IApiQueryParameter, IApiReference, IApiRequestBody, IApiResponse, IApiResponses, IApiSchema, IApiSecurityRequirement, IApiSecurityScheme, IApiServer, IApiServerVariable, IApiTag, IApiXML, IAppController, IController, IOpenAPI, MergeHooks, OpenApi, OpenApiDecorator, Options, Patch, Post, Put, ServiceManager, createController, createOpenApiDocument, createService, dependency, getApiCallbacks, getApiCompleteOperation, getApiComponents, getApiDeprecated, getApiExternalDocs, getApiInfo, getApiOperation, getApiOperationDescription, getApiOperationId, getApiOperationSummary, getApiParameters, getApiRequestBody, getApiResponses, getApiSecurity, getApiServers, getApiTags, getApiUsedTags, getHookFunction, getHookFunctions, getHttpMethod, getPath, isHttpResponse, isHttpResponseBadRequest, isHttpResponseClientError, isHttpResponseConflict, isHttpResponseCreated, isHttpResponseForbidden, isHttpResponseInternalServerError, isHttpResponseMethodNotAllowed, isHttpResponseMovedPermanently, isHttpResponseNoContent, isHttpResponseNotFound, isHttpResponseNotImplemented, isHttpResponseOK, isHttpResponseRedirect, isHttpResponseRedirection, isHttpResponseServerError, isHttpResponseSuccess, isHttpResponseTooManyRequests, isHttpResponseUnauthorized, } from './core'; | ||
export { OPENAPI_SERVICE_ID, createApp, } from './express'; | ||
export { Session, SessionAlreadyExists, SessionState, SessionStore, Store, UseSessions, createSession, readSession, } from './sessions'; |
155
lib/index.js
@@ -7,10 +7,149 @@ "use strict"; | ||
*/ | ||
function __export(m) { | ||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.readSession = exports.createSession = exports.UseSessions = exports.Store = exports.SessionStore = exports.SessionAlreadyExists = exports.Session = exports.createApp = exports.OPENAPI_SERVICE_ID = exports.isHttpResponseUnauthorized = exports.isHttpResponseTooManyRequests = exports.isHttpResponseSuccess = exports.isHttpResponseServerError = exports.isHttpResponseRedirection = exports.isHttpResponseRedirect = exports.isHttpResponseOK = exports.isHttpResponseNotImplemented = exports.isHttpResponseNotFound = exports.isHttpResponseNoContent = exports.isHttpResponseMovedPermanently = exports.isHttpResponseMethodNotAllowed = exports.isHttpResponseInternalServerError = exports.isHttpResponseForbidden = exports.isHttpResponseCreated = exports.isHttpResponseConflict = exports.isHttpResponseClientError = exports.isHttpResponseBadRequest = exports.isHttpResponse = exports.getPath = exports.getHttpMethod = exports.getHookFunctions = exports.getHookFunction = exports.getApiUsedTags = exports.getApiTags = exports.getApiServers = exports.getApiSecurity = exports.getApiResponses = exports.getApiRequestBody = exports.getApiParameters = exports.getApiOperationSummary = exports.getApiOperationId = exports.getApiOperationDescription = exports.getApiOperation = exports.getApiInfo = exports.getApiExternalDocs = exports.getApiDeprecated = exports.getApiComponents = exports.getApiCompleteOperation = exports.getApiCallbacks = exports.dependency = exports.createService = exports.createOpenApiDocument = exports.createController = exports.ServiceManager = exports.Put = exports.Post = exports.Patch = exports.Options = exports.OpenApi = exports.MergeHooks = exports.HttpResponseUnauthorized = exports.HttpResponseTooManyRequests = exports.HttpResponseSuccess = exports.HttpResponseServerError = exports.HttpResponseRedirection = exports.HttpResponseRedirect = exports.HttpResponseOK = exports.HttpResponseNotImplemented = exports.HttpResponseNotFound = exports.HttpResponseNoContent = exports.HttpResponseMovedPermanently = exports.HttpResponseMethodNotAllowed = exports.HttpResponseInternalServerError = exports.HttpResponseForbidden = exports.HttpResponseCreated = exports.HttpResponseConflict = exports.HttpResponseClientError = exports.HttpResponseBadRequest = exports.HttpResponse = exports.Hook = exports.Head = exports.Get = exports.Env = exports.Dependency = exports.Delete = exports.Context = exports.ConfigTypeError = exports.ConfigNotFoundError = exports.Config = exports.ApiUseTag = exports.ApiServer = exports.ApiSecurityRequirement = exports.ApiResponse = exports.ApiRequestBody = exports.ApiParameter = exports.ApiOperationSummary = exports.ApiOperationId = exports.ApiOperationDescription = exports.ApiOperation = exports.ApiInfo = exports.ApiExternalDoc = exports.ApiDeprecated = exports.ApiDefineTag = exports.ApiDefineSecurityScheme = exports.ApiDefineSchema = exports.ApiDefineResponse = exports.ApiDefineRequestBody = exports.ApiDefineParameter = exports.ApiDefineLink = exports.ApiDefineHeader = exports.ApiDefineExample = exports.ApiDefineCallback = exports.ApiCallback = exports.verifySignedToken = exports.verifyPassword = exports.signToken = exports.renderError = exports.render = exports.isInFile = exports.hashPassword = exports.getAjvInstance = exports.generateToken = exports.generateSignedToken = exports.escapeProp = exports.escape = exports.convertBase64ToBase64url = exports.controller = exports.ValidateQueryParam = exports.ValidatePathParam = exports.ValidateHeader = exports.ValidateCookie = exports.ValidateBody = exports.UserRequired = exports.Log = void 0; | ||
try { | ||
const version = process.versions.node; | ||
const NODE_MAJOR_VERSION = parseInt(version.split('.')[0], 10); | ||
if (NODE_MAJOR_VERSION < 10) { | ||
console.warn(`[Warning] You are using version ${version} of Node. FoalTS requires at least version 10.`); | ||
} | ||
} | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
__export(require("./common")); | ||
__export(require("./core")); | ||
__export(require("./express")); | ||
__export(require("./openapi")); | ||
__export(require("./sessions")); | ||
finally { } | ||
var common_1 = require("./common"); | ||
Object.defineProperty(exports, "Log", { enumerable: true, get: function () { return common_1.Log; } }); | ||
Object.defineProperty(exports, "UserRequired", { enumerable: true, get: function () { return common_1.UserRequired; } }); | ||
Object.defineProperty(exports, "ValidateBody", { enumerable: true, get: function () { return common_1.ValidateBody; } }); | ||
Object.defineProperty(exports, "ValidateCookie", { enumerable: true, get: function () { return common_1.ValidateCookie; } }); | ||
Object.defineProperty(exports, "ValidateHeader", { enumerable: true, get: function () { return common_1.ValidateHeader; } }); | ||
Object.defineProperty(exports, "ValidatePathParam", { enumerable: true, get: function () { return common_1.ValidatePathParam; } }); | ||
Object.defineProperty(exports, "ValidateQueryParam", { enumerable: true, get: function () { return common_1.ValidateQueryParam; } }); | ||
Object.defineProperty(exports, "controller", { enumerable: true, get: function () { return common_1.controller; } }); | ||
Object.defineProperty(exports, "convertBase64ToBase64url", { enumerable: true, get: function () { return common_1.convertBase64ToBase64url; } }); | ||
Object.defineProperty(exports, "escape", { enumerable: true, get: function () { return common_1.escape; } }); | ||
Object.defineProperty(exports, "escapeProp", { enumerable: true, get: function () { return common_1.escapeProp; } }); | ||
Object.defineProperty(exports, "generateSignedToken", { enumerable: true, get: function () { return common_1.generateSignedToken; } }); | ||
Object.defineProperty(exports, "generateToken", { enumerable: true, get: function () { return common_1.generateToken; } }); | ||
Object.defineProperty(exports, "getAjvInstance", { enumerable: true, get: function () { return common_1.getAjvInstance; } }); | ||
Object.defineProperty(exports, "hashPassword", { enumerable: true, get: function () { return common_1.hashPassword; } }); | ||
Object.defineProperty(exports, "isInFile", { enumerable: true, get: function () { return common_1.isInFile; } }); | ||
Object.defineProperty(exports, "render", { enumerable: true, get: function () { return common_1.render; } }); | ||
Object.defineProperty(exports, "renderError", { enumerable: true, get: function () { return common_1.renderError; } }); | ||
Object.defineProperty(exports, "signToken", { enumerable: true, get: function () { return common_1.signToken; } }); | ||
Object.defineProperty(exports, "verifyPassword", { enumerable: true, get: function () { return common_1.verifyPassword; } }); | ||
Object.defineProperty(exports, "verifySignedToken", { enumerable: true, get: function () { return common_1.verifySignedToken; } }); | ||
var core_1 = require("./core"); | ||
Object.defineProperty(exports, "ApiCallback", { enumerable: true, get: function () { return core_1.ApiCallback; } }); | ||
Object.defineProperty(exports, "ApiDefineCallback", { enumerable: true, get: function () { return core_1.ApiDefineCallback; } }); | ||
Object.defineProperty(exports, "ApiDefineExample", { enumerable: true, get: function () { return core_1.ApiDefineExample; } }); | ||
Object.defineProperty(exports, "ApiDefineHeader", { enumerable: true, get: function () { return core_1.ApiDefineHeader; } }); | ||
Object.defineProperty(exports, "ApiDefineLink", { enumerable: true, get: function () { return core_1.ApiDefineLink; } }); | ||
Object.defineProperty(exports, "ApiDefineParameter", { enumerable: true, get: function () { return core_1.ApiDefineParameter; } }); | ||
Object.defineProperty(exports, "ApiDefineRequestBody", { enumerable: true, get: function () { return core_1.ApiDefineRequestBody; } }); | ||
Object.defineProperty(exports, "ApiDefineResponse", { enumerable: true, get: function () { return core_1.ApiDefineResponse; } }); | ||
Object.defineProperty(exports, "ApiDefineSchema", { enumerable: true, get: function () { return core_1.ApiDefineSchema; } }); | ||
Object.defineProperty(exports, "ApiDefineSecurityScheme", { enumerable: true, get: function () { return core_1.ApiDefineSecurityScheme; } }); | ||
Object.defineProperty(exports, "ApiDefineTag", { enumerable: true, get: function () { return core_1.ApiDefineTag; } }); | ||
Object.defineProperty(exports, "ApiDeprecated", { enumerable: true, get: function () { return core_1.ApiDeprecated; } }); | ||
Object.defineProperty(exports, "ApiExternalDoc", { enumerable: true, get: function () { return core_1.ApiExternalDoc; } }); | ||
Object.defineProperty(exports, "ApiInfo", { enumerable: true, get: function () { return core_1.ApiInfo; } }); | ||
Object.defineProperty(exports, "ApiOperation", { enumerable: true, get: function () { return core_1.ApiOperation; } }); | ||
Object.defineProperty(exports, "ApiOperationDescription", { enumerable: true, get: function () { return core_1.ApiOperationDescription; } }); | ||
Object.defineProperty(exports, "ApiOperationId", { enumerable: true, get: function () { return core_1.ApiOperationId; } }); | ||
Object.defineProperty(exports, "ApiOperationSummary", { enumerable: true, get: function () { return core_1.ApiOperationSummary; } }); | ||
Object.defineProperty(exports, "ApiParameter", { enumerable: true, get: function () { return core_1.ApiParameter; } }); | ||
Object.defineProperty(exports, "ApiRequestBody", { enumerable: true, get: function () { return core_1.ApiRequestBody; } }); | ||
Object.defineProperty(exports, "ApiResponse", { enumerable: true, get: function () { return core_1.ApiResponse; } }); | ||
Object.defineProperty(exports, "ApiSecurityRequirement", { enumerable: true, get: function () { return core_1.ApiSecurityRequirement; } }); | ||
Object.defineProperty(exports, "ApiServer", { enumerable: true, get: function () { return core_1.ApiServer; } }); | ||
Object.defineProperty(exports, "ApiUseTag", { enumerable: true, get: function () { return core_1.ApiUseTag; } }); | ||
Object.defineProperty(exports, "Config", { enumerable: true, get: function () { return core_1.Config; } }); | ||
Object.defineProperty(exports, "ConfigNotFoundError", { enumerable: true, get: function () { return core_1.ConfigNotFoundError; } }); | ||
Object.defineProperty(exports, "ConfigTypeError", { enumerable: true, get: function () { return core_1.ConfigTypeError; } }); | ||
Object.defineProperty(exports, "Context", { enumerable: true, get: function () { return core_1.Context; } }); | ||
Object.defineProperty(exports, "Delete", { enumerable: true, get: function () { return core_1.Delete; } }); | ||
Object.defineProperty(exports, "Dependency", { enumerable: true, get: function () { return core_1.Dependency; } }); | ||
Object.defineProperty(exports, "Env", { enumerable: true, get: function () { return core_1.Env; } }); | ||
Object.defineProperty(exports, "Get", { enumerable: true, get: function () { return core_1.Get; } }); | ||
Object.defineProperty(exports, "Head", { enumerable: true, get: function () { return core_1.Head; } }); | ||
Object.defineProperty(exports, "Hook", { enumerable: true, get: function () { return core_1.Hook; } }); | ||
Object.defineProperty(exports, "HttpResponse", { enumerable: true, get: function () { return core_1.HttpResponse; } }); | ||
Object.defineProperty(exports, "HttpResponseBadRequest", { enumerable: true, get: function () { return core_1.HttpResponseBadRequest; } }); | ||
Object.defineProperty(exports, "HttpResponseClientError", { enumerable: true, get: function () { return core_1.HttpResponseClientError; } }); | ||
Object.defineProperty(exports, "HttpResponseConflict", { enumerable: true, get: function () { return core_1.HttpResponseConflict; } }); | ||
Object.defineProperty(exports, "HttpResponseCreated", { enumerable: true, get: function () { return core_1.HttpResponseCreated; } }); | ||
Object.defineProperty(exports, "HttpResponseForbidden", { enumerable: true, get: function () { return core_1.HttpResponseForbidden; } }); | ||
Object.defineProperty(exports, "HttpResponseInternalServerError", { enumerable: true, get: function () { return core_1.HttpResponseInternalServerError; } }); | ||
Object.defineProperty(exports, "HttpResponseMethodNotAllowed", { enumerable: true, get: function () { return core_1.HttpResponseMethodNotAllowed; } }); | ||
Object.defineProperty(exports, "HttpResponseMovedPermanently", { enumerable: true, get: function () { return core_1.HttpResponseMovedPermanently; } }); | ||
Object.defineProperty(exports, "HttpResponseNoContent", { enumerable: true, get: function () { return core_1.HttpResponseNoContent; } }); | ||
Object.defineProperty(exports, "HttpResponseNotFound", { enumerable: true, get: function () { return core_1.HttpResponseNotFound; } }); | ||
Object.defineProperty(exports, "HttpResponseNotImplemented", { enumerable: true, get: function () { return core_1.HttpResponseNotImplemented; } }); | ||
Object.defineProperty(exports, "HttpResponseOK", { enumerable: true, get: function () { return core_1.HttpResponseOK; } }); | ||
Object.defineProperty(exports, "HttpResponseRedirect", { enumerable: true, get: function () { return core_1.HttpResponseRedirect; } }); | ||
Object.defineProperty(exports, "HttpResponseRedirection", { enumerable: true, get: function () { return core_1.HttpResponseRedirection; } }); | ||
Object.defineProperty(exports, "HttpResponseServerError", { enumerable: true, get: function () { return core_1.HttpResponseServerError; } }); | ||
Object.defineProperty(exports, "HttpResponseSuccess", { enumerable: true, get: function () { return core_1.HttpResponseSuccess; } }); | ||
Object.defineProperty(exports, "HttpResponseTooManyRequests", { enumerable: true, get: function () { return core_1.HttpResponseTooManyRequests; } }); | ||
Object.defineProperty(exports, "HttpResponseUnauthorized", { enumerable: true, get: function () { return core_1.HttpResponseUnauthorized; } }); | ||
Object.defineProperty(exports, "MergeHooks", { enumerable: true, get: function () { return core_1.MergeHooks; } }); | ||
Object.defineProperty(exports, "OpenApi", { enumerable: true, get: function () { return core_1.OpenApi; } }); | ||
Object.defineProperty(exports, "Options", { enumerable: true, get: function () { return core_1.Options; } }); | ||
Object.defineProperty(exports, "Patch", { enumerable: true, get: function () { return core_1.Patch; } }); | ||
Object.defineProperty(exports, "Post", { enumerable: true, get: function () { return core_1.Post; } }); | ||
Object.defineProperty(exports, "Put", { enumerable: true, get: function () { return core_1.Put; } }); | ||
Object.defineProperty(exports, "ServiceManager", { enumerable: true, get: function () { return core_1.ServiceManager; } }); | ||
Object.defineProperty(exports, "createController", { enumerable: true, get: function () { return core_1.createController; } }); | ||
Object.defineProperty(exports, "createOpenApiDocument", { enumerable: true, get: function () { return core_1.createOpenApiDocument; } }); | ||
Object.defineProperty(exports, "createService", { enumerable: true, get: function () { return core_1.createService; } }); | ||
Object.defineProperty(exports, "dependency", { enumerable: true, get: function () { return core_1.dependency; } }); | ||
Object.defineProperty(exports, "getApiCallbacks", { enumerable: true, get: function () { return core_1.getApiCallbacks; } }); | ||
Object.defineProperty(exports, "getApiCompleteOperation", { enumerable: true, get: function () { return core_1.getApiCompleteOperation; } }); | ||
Object.defineProperty(exports, "getApiComponents", { enumerable: true, get: function () { return core_1.getApiComponents; } }); | ||
Object.defineProperty(exports, "getApiDeprecated", { enumerable: true, get: function () { return core_1.getApiDeprecated; } }); | ||
Object.defineProperty(exports, "getApiExternalDocs", { enumerable: true, get: function () { return core_1.getApiExternalDocs; } }); | ||
Object.defineProperty(exports, "getApiInfo", { enumerable: true, get: function () { return core_1.getApiInfo; } }); | ||
Object.defineProperty(exports, "getApiOperation", { enumerable: true, get: function () { return core_1.getApiOperation; } }); | ||
Object.defineProperty(exports, "getApiOperationDescription", { enumerable: true, get: function () { return core_1.getApiOperationDescription; } }); | ||
Object.defineProperty(exports, "getApiOperationId", { enumerable: true, get: function () { return core_1.getApiOperationId; } }); | ||
Object.defineProperty(exports, "getApiOperationSummary", { enumerable: true, get: function () { return core_1.getApiOperationSummary; } }); | ||
Object.defineProperty(exports, "getApiParameters", { enumerable: true, get: function () { return core_1.getApiParameters; } }); | ||
Object.defineProperty(exports, "getApiRequestBody", { enumerable: true, get: function () { return core_1.getApiRequestBody; } }); | ||
Object.defineProperty(exports, "getApiResponses", { enumerable: true, get: function () { return core_1.getApiResponses; } }); | ||
Object.defineProperty(exports, "getApiSecurity", { enumerable: true, get: function () { return core_1.getApiSecurity; } }); | ||
Object.defineProperty(exports, "getApiServers", { enumerable: true, get: function () { return core_1.getApiServers; } }); | ||
Object.defineProperty(exports, "getApiTags", { enumerable: true, get: function () { return core_1.getApiTags; } }); | ||
Object.defineProperty(exports, "getApiUsedTags", { enumerable: true, get: function () { return core_1.getApiUsedTags; } }); | ||
Object.defineProperty(exports, "getHookFunction", { enumerable: true, get: function () { return core_1.getHookFunction; } }); | ||
Object.defineProperty(exports, "getHookFunctions", { enumerable: true, get: function () { return core_1.getHookFunctions; } }); | ||
Object.defineProperty(exports, "getHttpMethod", { enumerable: true, get: function () { return core_1.getHttpMethod; } }); | ||
Object.defineProperty(exports, "getPath", { enumerable: true, get: function () { return core_1.getPath; } }); | ||
Object.defineProperty(exports, "isHttpResponse", { enumerable: true, get: function () { return core_1.isHttpResponse; } }); | ||
Object.defineProperty(exports, "isHttpResponseBadRequest", { enumerable: true, get: function () { return core_1.isHttpResponseBadRequest; } }); | ||
Object.defineProperty(exports, "isHttpResponseClientError", { enumerable: true, get: function () { return core_1.isHttpResponseClientError; } }); | ||
Object.defineProperty(exports, "isHttpResponseConflict", { enumerable: true, get: function () { return core_1.isHttpResponseConflict; } }); | ||
Object.defineProperty(exports, "isHttpResponseCreated", { enumerable: true, get: function () { return core_1.isHttpResponseCreated; } }); | ||
Object.defineProperty(exports, "isHttpResponseForbidden", { enumerable: true, get: function () { return core_1.isHttpResponseForbidden; } }); | ||
Object.defineProperty(exports, "isHttpResponseInternalServerError", { enumerable: true, get: function () { return core_1.isHttpResponseInternalServerError; } }); | ||
Object.defineProperty(exports, "isHttpResponseMethodNotAllowed", { enumerable: true, get: function () { return core_1.isHttpResponseMethodNotAllowed; } }); | ||
Object.defineProperty(exports, "isHttpResponseMovedPermanently", { enumerable: true, get: function () { return core_1.isHttpResponseMovedPermanently; } }); | ||
Object.defineProperty(exports, "isHttpResponseNoContent", { enumerable: true, get: function () { return core_1.isHttpResponseNoContent; } }); | ||
Object.defineProperty(exports, "isHttpResponseNotFound", { enumerable: true, get: function () { return core_1.isHttpResponseNotFound; } }); | ||
Object.defineProperty(exports, "isHttpResponseNotImplemented", { enumerable: true, get: function () { return core_1.isHttpResponseNotImplemented; } }); | ||
Object.defineProperty(exports, "isHttpResponseOK", { enumerable: true, get: function () { return core_1.isHttpResponseOK; } }); | ||
Object.defineProperty(exports, "isHttpResponseRedirect", { enumerable: true, get: function () { return core_1.isHttpResponseRedirect; } }); | ||
Object.defineProperty(exports, "isHttpResponseRedirection", { enumerable: true, get: function () { return core_1.isHttpResponseRedirection; } }); | ||
Object.defineProperty(exports, "isHttpResponseServerError", { enumerable: true, get: function () { return core_1.isHttpResponseServerError; } }); | ||
Object.defineProperty(exports, "isHttpResponseSuccess", { enumerable: true, get: function () { return core_1.isHttpResponseSuccess; } }); | ||
Object.defineProperty(exports, "isHttpResponseTooManyRequests", { enumerable: true, get: function () { return core_1.isHttpResponseTooManyRequests; } }); | ||
Object.defineProperty(exports, "isHttpResponseUnauthorized", { enumerable: true, get: function () { return core_1.isHttpResponseUnauthorized; } }); | ||
var express_1 = require("./express"); | ||
Object.defineProperty(exports, "OPENAPI_SERVICE_ID", { enumerable: true, get: function () { return express_1.OPENAPI_SERVICE_ID; } }); | ||
Object.defineProperty(exports, "createApp", { enumerable: true, get: function () { return express_1.createApp; } }); | ||
var sessions_1 = require("./sessions"); | ||
Object.defineProperty(exports, "Session", { enumerable: true, get: function () { return sessions_1.Session; } }); | ||
Object.defineProperty(exports, "SessionAlreadyExists", { enumerable: true, get: function () { return sessions_1.SessionAlreadyExists; } }); | ||
Object.defineProperty(exports, "SessionStore", { enumerable: true, get: function () { return sessions_1.SessionStore; } }); | ||
Object.defineProperty(exports, "Store", { enumerable: true, get: function () { return sessions_1.Store; } }); | ||
Object.defineProperty(exports, "UseSessions", { enumerable: true, get: function () { return sessions_1.UseSessions; } }); | ||
Object.defineProperty(exports, "createSession", { enumerable: true, get: function () { return sessions_1.createSession; } }); | ||
Object.defineProperty(exports, "readSession", { enumerable: true, get: function () { return sessions_1.readSession; } }); |
@@ -7,3 +7,6 @@ /** | ||
export declare const SESSION_DEFAULT_COOKIE_NAME: string; | ||
export declare const SESSION_DEFAULT_CSRF_COOKIE_NAME: string; | ||
export declare const SESSION_DEFAULT_SAME_SITE_ON_CSRF_ENABLED: 'strict' | 'lax' | 'none'; | ||
export declare const SESSION_DEFAULT_INACTIVITY_TIMEOUT: number; | ||
export declare const SESSION_DEFAULT_ABSOLUTE_TIMEOUT: number; | ||
export declare const SESSION_DEFAULT_GARBAGE_COLLECTOR_PERIODICITY = 50; |
@@ -6,7 +6,11 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.SESSION_DEFAULT_GARBAGE_COLLECTOR_PERIODICITY = exports.SESSION_DEFAULT_ABSOLUTE_TIMEOUT = exports.SESSION_DEFAULT_INACTIVITY_TIMEOUT = exports.SESSION_DEFAULT_SAME_SITE_ON_CSRF_ENABLED = exports.SESSION_DEFAULT_CSRF_COOKIE_NAME = exports.SESSION_DEFAULT_COOKIE_NAME = exports.SESSION_DEFAULT_COOKIE_HTTP_ONLY = exports.SESSION_DEFAULT_COOKIE_PATH = void 0; | ||
exports.SESSION_DEFAULT_COOKIE_PATH = '/'; | ||
exports.SESSION_DEFAULT_COOKIE_HTTP_ONLY = true; | ||
exports.SESSION_DEFAULT_COOKIE_NAME = 'sessionID'; | ||
exports.SESSION_DEFAULT_CSRF_COOKIE_NAME = 'XSRF-TOKEN'; | ||
exports.SESSION_DEFAULT_SAME_SITE_ON_CSRF_ENABLED = 'lax'; | ||
// Expiration timeouts in seconds | ||
exports.SESSION_DEFAULT_INACTIVITY_TIMEOUT = 15 * 60; // 15 minutes | ||
exports.SESSION_DEFAULT_ABSOLUTE_TIMEOUT = 7 * 24 * 60 * 60; // 1 week | ||
exports.SESSION_DEFAULT_GARBAGE_COLLECTOR_PERIODICITY = 50; |
@@ -1,6 +0,6 @@ | ||
export { removeSessionCookie } from './remove-session-cookie'; | ||
export { Store, SessionStore, SessionOptions } from './session-store'; | ||
export { createSession } from './create-session'; | ||
export { readSession } from './read-session'; | ||
export { Store, SessionStore, SessionAlreadyExists } from './session-store'; | ||
export { Session } from './session'; | ||
export { setSessionCookie } from './set-session-cookie'; | ||
export { TokenOptional } from './token-optional.hook'; | ||
export { TokenRequired } from './token-required.hook'; | ||
export { SessionState } from './session-state.interface'; | ||
export { UseSessions } from './use-sessions.hook'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var remove_session_cookie_1 = require("./remove-session-cookie"); | ||
exports.removeSessionCookie = remove_session_cookie_1.removeSessionCookie; | ||
exports.UseSessions = exports.Session = exports.SessionAlreadyExists = exports.SessionStore = exports.Store = exports.readSession = exports.createSession = void 0; | ||
var create_session_1 = require("./create-session"); | ||
Object.defineProperty(exports, "createSession", { enumerable: true, get: function () { return create_session_1.createSession; } }); | ||
var read_session_1 = require("./read-session"); | ||
Object.defineProperty(exports, "readSession", { enumerable: true, get: function () { return read_session_1.readSession; } }); | ||
var session_store_1 = require("./session-store"); | ||
exports.Store = session_store_1.Store; | ||
exports.SessionStore = session_store_1.SessionStore; | ||
Object.defineProperty(exports, "Store", { enumerable: true, get: function () { return session_store_1.Store; } }); | ||
Object.defineProperty(exports, "SessionStore", { enumerable: true, get: function () { return session_store_1.SessionStore; } }); | ||
Object.defineProperty(exports, "SessionAlreadyExists", { enumerable: true, get: function () { return session_store_1.SessionAlreadyExists; } }); | ||
var session_1 = require("./session"); | ||
exports.Session = session_1.Session; | ||
var set_session_cookie_1 = require("./set-session-cookie"); | ||
exports.setSessionCookie = set_session_cookie_1.setSessionCookie; | ||
var token_optional_hook_1 = require("./token-optional.hook"); | ||
exports.TokenOptional = token_optional_hook_1.TokenOptional; | ||
var token_required_hook_1 = require("./token-required.hook"); | ||
exports.TokenRequired = token_required_hook_1.TokenRequired; | ||
Object.defineProperty(exports, "Session", { enumerable: true, get: function () { return session_1.Session; } }); | ||
var use_sessions_hook_1 = require("./use-sessions.hook"); | ||
Object.defineProperty(exports, "UseSessions", { enumerable: true, get: function () { return use_sessions_hook_1.UseSessions; } }); |
import { HttpResponse } from '../core'; | ||
/** | ||
* Delete the browser cookie containing the session token. | ||
* Deletes the browser cookie containing the session token. | ||
* | ||
* If the CSRF protection is enabled, it also deletes the CSRF cookie containing the CSRF token. | ||
* | ||
* @export | ||
@@ -6,0 +8,0 @@ * @param {HttpResponse} response - The HTTP response |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.removeSessionCookie = void 0; | ||
// FoalTS | ||
@@ -7,4 +8,6 @@ const core_1 = require("../core"); | ||
/** | ||
* Delete the browser cookie containing the session token. | ||
* Deletes the browser cookie containing the session token. | ||
* | ||
* If the CSRF protection is enabled, it also deletes the CSRF cookie containing the CSRF token. | ||
* | ||
* @export | ||
@@ -14,13 +17,21 @@ * @param {HttpResponse} response - The HTTP response | ||
function removeSessionCookie(response) { | ||
const cookieName = core_1.Config.get2('settings.session.cookie.name', 'string', constants_1.SESSION_DEFAULT_COOKIE_NAME); | ||
const cookieName = core_1.Config.get('settings.session.cookie.name', 'string', constants_1.SESSION_DEFAULT_COOKIE_NAME); | ||
const csrfEnabled = core_1.Config.get('settings.session.csrf.enabled', 'boolean', false); | ||
let sameSite = core_1.Config.get('settings.session.cookie.sameSite', 'string'); | ||
if (csrfEnabled && sameSite === undefined) { | ||
sameSite = constants_1.SESSION_DEFAULT_SAME_SITE_ON_CSRF_ENABLED; | ||
} | ||
const options = { | ||
domain: core_1.Config.get2('settings.session.cookie.domain', 'string'), | ||
httpOnly: core_1.Config.get2('settings.session.cookie.httpOnly', 'boolean', constants_1.SESSION_DEFAULT_COOKIE_HTTP_ONLY), | ||
domain: core_1.Config.get('settings.session.cookie.domain', 'string'), | ||
maxAge: 0, | ||
path: core_1.Config.get2('settings.session.cookie.path', 'string', constants_1.SESSION_DEFAULT_COOKIE_PATH), | ||
sameSite: core_1.Config.get2('settings.session.cookie.sameSite', 'string'), | ||
secure: core_1.Config.get2('settings.session.cookie.secure', 'boolean') | ||
path: core_1.Config.get('settings.session.cookie.path', 'string', constants_1.SESSION_DEFAULT_COOKIE_PATH), | ||
sameSite, | ||
secure: core_1.Config.get('settings.session.cookie.secure', 'boolean'), | ||
}; | ||
response.setCookie(cookieName, '', options); | ||
response.setCookie(cookieName, '', Object.assign(Object.assign({}, options), { httpOnly: core_1.Config.get('settings.session.cookie.httpOnly', 'boolean', constants_1.SESSION_DEFAULT_COOKIE_HTTP_ONLY) })); | ||
if (csrfEnabled) { | ||
const csrfCookieName = core_1.Config.get('settings.session.csrf.cookie.name', 'string', constants_1.SESSION_DEFAULT_CSRF_COOKIE_NAME); | ||
response.setCookie(csrfCookieName, '', Object.assign(Object.assign({}, options), { httpOnly: false })); | ||
} | ||
} | ||
exports.removeSessionCookie = removeSessionCookie; |
@@ -1,12 +0,13 @@ | ||
import { Session } from './session'; | ||
export interface SessionOptions { | ||
csrfToken?: boolean; | ||
import { SessionState } from './session-state.interface'; | ||
export declare class SessionAlreadyExists extends Error { | ||
readonly name = "SessionAlreadyExists"; | ||
} | ||
/** | ||
* Abstract class to be override when creating a session storage service. | ||
* Store used to create, read, update and delete sessions. | ||
* | ||
* A session store peforms CRUD operations on sessions and can store them in | ||
* a database, file system, memory, etc. | ||
* All session stores must inherit this abstract class. | ||
* | ||
* Examples of Store: TypeORMStore, RedisStore, MongoDBStore. | ||
* When this class is used with the `@dependency` decorator, | ||
* it returns the `ConcreteSessionStore` class from the file or the package specified | ||
* with the configuration key "settings.session.store". | ||
* | ||
@@ -21,94 +22,49 @@ * @export | ||
/** | ||
* Read session expiration timeouts from the configuration. | ||
* Saves the session for the first time. | ||
* | ||
* The values are in seconds. | ||
* If a session already exists with the given ID, a SessionAlreadyExists error MUST be thrown. | ||
* | ||
* Default values are: | ||
* - 15 min for inactivity timeout | ||
* - 1 week for absolute timeout | ||
* | ||
* This method throws an error if one of the following is true: | ||
* - The given inactivity timeout is negative. | ||
* - The given absolute timeout is negative. | ||
* - The given inactivity timeout is greater than the absolute timeout. | ||
* | ||
* @static | ||
* @returns {{ inactivity: number , absolute: number }} The expiration timeouts | ||
* @abstract | ||
* @param {SessionState} state - The state of the session. | ||
* @param {number} maxInactivity - The maximum idle activity of the session (useful for cache stores). | ||
* @returns {Promise<void>} | ||
* @memberof Store | ||
*/ | ||
static getExpirationTimeouts(): { | ||
inactivity: number; | ||
absolute: number; | ||
}; | ||
abstract save(state: SessionState, maxInactivity: number): Promise<void>; | ||
/** | ||
* Create and save an new session from a user. | ||
* Reads a session. | ||
* | ||
* @param {({ id: string|number })} user - User id. | ||
* @param {SessionOptions} options - Session options. | ||
* @param {boolean} [options.csrfToken] - Generate and add a `csrfToken` to the sessionContent. | ||
* @returns {Promise<Session>} The created session. | ||
* @memberof Store | ||
*/ | ||
createAndSaveSessionFromUser(user: { | ||
id: string | number; | ||
}, options?: SessionOptions): Promise<Session>; | ||
/** | ||
* Create and save a new session. | ||
* If the session does not exist, the value `null` MUST be returned. | ||
* | ||
* This method *MUST* call the `generateSessionID` method to generate the session ID. | ||
* This method *MUST* call the `applySessionOptions` method to extend the sessionContent. | ||
* | ||
* @abstract | ||
* @param {object} sessionContent - The content of the session (often includes the user ID). | ||
* @param {SessionOptions} options - Session options. | ||
* @param {boolean} [options.csrfToken] - Generate and add a `csrfToken` to the sessionContent. | ||
* @returns {Promise<Session>} The created session. | ||
* @param {string} id - The ID of the session. | ||
* @returns {(Promise<SessionState|null>)} The state of the session. | ||
* @memberof Store | ||
*/ | ||
abstract createAndSaveSession(sessionContent: object, options?: SessionOptions): Promise<Session>; | ||
abstract read(id: string): Promise<SessionState | null>; | ||
/** | ||
* Update and extend the lifetime of a session. | ||
* Updates and extends the lifetime of a session. | ||
* | ||
* Depending on the implementation, the internal behavior can be similar to "update" or "upsert". | ||
* If the session no longer exists (i.e. has expired or been destroyed), the session MUST still be saved. | ||
* | ||
* @abstract | ||
* @param {Session} session - The session containaing the updated content. | ||
* @param {SessionState} state - The state of the session. | ||
* @param {number} maxInactivity - The maximum idle activity of the session (useful for cache stores). | ||
* @returns {Promise<void>} | ||
* @memberof Store | ||
*/ | ||
abstract update(session: Session): Promise<void>; | ||
abstract update(state: SessionState, maxInactivity: number): Promise<void>; | ||
/** | ||
* Delete a session, whether it exists or not. | ||
* Deletes a session. | ||
* | ||
* @abstract | ||
* @param {string} sessionID - The ID of the session. | ||
* @returns {Promise<void>} | ||
* @memberof Store | ||
*/ | ||
abstract destroy(sessionID: string): Promise<void>; | ||
/** | ||
* Read a session from its ID. | ||
* If the session does not exist, NO error MUST be thrown. | ||
* | ||
* Returns `undefined` if the session does not exist or has expired. | ||
* | ||
* @abstract | ||
* @param {string} sessionID - The ID of the session. | ||
* @returns {(Promise<Session|undefined>)} The Session object. | ||
* @memberof Store | ||
*/ | ||
abstract read(sessionID: string): Promise<Session | undefined>; | ||
/** | ||
* Extend the lifetime of a session from its ID. The duration is | ||
* the inactivity timeout. | ||
* | ||
* If the session does not exist, the method does not throw an error. | ||
* | ||
* @abstract | ||
* @param {string} sessionID - The ID of the session. | ||
* @param {string} id - The ID of the session. | ||
* @returns {Promise<void>} | ||
* @memberof Store | ||
*/ | ||
abstract extendLifeTime(sessionID: string): Promise<void>; | ||
abstract destroy(id: string): Promise<void>; | ||
/** | ||
* Clear all sessions. | ||
* Clears all sessions. | ||
* | ||
@@ -125,27 +81,13 @@ * @abstract | ||
* | ||
* If the store manages a cache database, then this method can remain empty but it must NOT throw an error. | ||
* | ||
* @abstract | ||
* @param {number} maxInactivity - The maximum idle activity of a session. | ||
* @param {number} maxLifeTime - The maximum absolute life time of a session. | ||
* @returns {Promise<void>} | ||
* @memberof Store | ||
*/ | ||
abstract cleanUpExpiredSessions(): Promise<void>; | ||
/** | ||
* Generate a 128-bit base64url-encoded session ID. | ||
* | ||
* @protected | ||
* @returns {Promise<string>} - The session ID. | ||
* @memberof Store | ||
*/ | ||
protected generateSessionID(): Promise<string>; | ||
/** | ||
* Apply session options to the given session content. | ||
* | ||
* @protected | ||
* @param {object} content - Session content. | ||
* @param {SessionOptions} options - Session options. | ||
* @param {boolean} [options.csrfToken] - Generate and add a `csrfToken` to the sessionContent. | ||
* @returns {Promise<void>} | ||
* @memberof Store | ||
*/ | ||
protected applySessionOptions(content: object, options: SessionOptions): Promise<void>; | ||
abstract cleanUpExpiredSessions(maxInactivity: number, maxLifeTime: number): Promise<void>; | ||
boot(): void | Promise<void>; | ||
} | ||
export { Store as SessionStore }; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
// FoalTS | ||
const common_1 = require("../common"); | ||
const core_1 = require("../core"); | ||
const constants_1 = require("./constants"); | ||
exports.SessionStore = exports.Store = exports.SessionAlreadyExists = void 0; | ||
class SessionAlreadyExists extends Error { | ||
constructor() { | ||
super(...arguments); | ||
this.name = 'SessionAlreadyExists'; | ||
} | ||
} | ||
exports.SessionAlreadyExists = SessionAlreadyExists; | ||
/** | ||
* Abstract class to be override when creating a session storage service. | ||
* Store used to create, read, update and delete sessions. | ||
* | ||
* A session store peforms CRUD operations on sessions and can store them in | ||
* a database, file system, memory, etc. | ||
* All session stores must inherit this abstract class. | ||
* | ||
* Examples of Store: TypeORMStore, RedisStore, MongoDBStore. | ||
* When this class is used with the `@dependency` decorator, | ||
* it returns the `ConcreteSessionStore` class from the file or the package specified | ||
* with the configuration key "settings.session.store". | ||
* | ||
@@ -20,77 +25,7 @@ * @export | ||
class Store { | ||
/** | ||
* Read session expiration timeouts from the configuration. | ||
* | ||
* The values are in seconds. | ||
* | ||
* Default values are: | ||
* - 15 min for inactivity timeout | ||
* - 1 week for absolute timeout | ||
* | ||
* This method throws an error if one of the following is true: | ||
* - The given inactivity timeout is negative. | ||
* - The given absolute timeout is negative. | ||
* - The given inactivity timeout is greater than the absolute timeout. | ||
* | ||
* @static | ||
* @returns {{ inactivity: number , absolute: number }} The expiration timeouts | ||
* @memberof Store | ||
*/ | ||
static getExpirationTimeouts() { | ||
const result = { | ||
absolute: core_1.Config.get2('settings.session.expirationTimeouts.absolute', 'number', constants_1.SESSION_DEFAULT_ABSOLUTE_TIMEOUT), | ||
inactivity: core_1.Config.get2('settings.session.expirationTimeouts.inactivity', 'number', constants_1.SESSION_DEFAULT_INACTIVITY_TIMEOUT), | ||
}; | ||
if (result.absolute < 0) { | ||
throw new Error('[CONFIG] The value of settings.session.expirationTimeouts.absolute must be a positive number.'); | ||
} | ||
if (result.inactivity < 0) { | ||
throw new Error('[CONFIG] The value of settings.session.expirationTimeouts.inactivity must be a positive number.'); | ||
} | ||
if (result.absolute < result.inactivity) { | ||
throw new Error('[CONFIG] The value of settings.session.expirationTimeouts.absolute must be greater than *.inactivity.'); | ||
} | ||
return result; | ||
} | ||
/** | ||
* Create and save an new session from a user. | ||
* | ||
* @param {({ id: string|number })} user - User id. | ||
* @param {SessionOptions} options - Session options. | ||
* @param {boolean} [options.csrfToken] - Generate and add a `csrfToken` to the sessionContent. | ||
* @returns {Promise<Session>} The created session. | ||
* @memberof Store | ||
*/ | ||
createAndSaveSessionFromUser(user, options) { | ||
return this.createAndSaveSession({ userId: user.id }, options); | ||
} | ||
/** | ||
* Generate a 128-bit base64url-encoded session ID. | ||
* | ||
* @protected | ||
* @returns {Promise<string>} - The session ID. | ||
* @memberof Store | ||
*/ | ||
async generateSessionID() { | ||
return common_1.generateToken(); | ||
} | ||
/** | ||
* Apply session options to the given session content. | ||
* | ||
* @protected | ||
* @param {object} content - Session content. | ||
* @param {SessionOptions} options - Session options. | ||
* @param {boolean} [options.csrfToken] - Generate and add a `csrfToken` to the sessionContent. | ||
* @returns {Promise<void>} | ||
* @memberof Store | ||
*/ | ||
async applySessionOptions(content, options) { | ||
if (options.csrfToken) { | ||
content.csrfToken = await common_1.generateToken(); | ||
} | ||
} | ||
boot() { } | ||
} | ||
exports.Store = Store; | ||
exports.SessionStore = Store; | ||
Store.concreteClassConfigPath = 'settings.session.store'; | ||
Store.concreteClassName = 'ConcreteSessionStore'; | ||
exports.Store = Store; | ||
exports.SessionStore = Store; |
@@ -0,3 +1,5 @@ | ||
import { SessionState } from './session-state.interface'; | ||
import { SessionStore } from './session-store'; | ||
/** | ||
* Representation of a server/database session. | ||
* Representation of a server/database/file session. | ||
* | ||
@@ -8,18 +10,18 @@ * @export | ||
export declare class Session { | ||
readonly sessionID: string; | ||
private sessionContent; | ||
readonly createdAt: number; | ||
private readonly store; | ||
private readonly state; | ||
private readonly oldFlash; | ||
private oldId; | ||
private status; | ||
/** | ||
* Verify a session token and return the sessionID if the token is valid. | ||
* Retuns the user ID. If the session is anonymous, the value is null. | ||
* | ||
* @static | ||
* @param {string} token - The session token to verify. | ||
* @returns {(string|false)} False if the token is invalid. Otherwise, the returned value is the session ID. | ||
* @readonly | ||
* @type {(string|number|null)} | ||
* @memberof Session | ||
*/ | ||
static verifyTokenAndGetId(token: string): string | false; | ||
private modified; | ||
constructor(sessionID: string, sessionContent: any, createdAt: number); | ||
get userId(): string | number | null; | ||
/** | ||
* Return true if an element was added/replaced in the session | ||
* Returns true if the session has expired due to inactivity | ||
* or because it reached the maximum lifetime allowed. | ||
* | ||
@@ -30,18 +32,44 @@ * @readonly | ||
*/ | ||
readonly isModified: boolean; | ||
get isExpired(): boolean; | ||
/** | ||
* Add/replace an element in the session. This operation is not saved | ||
* in the saved unless you call SessionStore.update(session). | ||
* Returns the session expiration time in seconds. | ||
* | ||
* @param {string} key | ||
* @param {*} value | ||
* @readonly | ||
* @type {number} | ||
* @memberof Session | ||
*/ | ||
set(key: string, value: any): void; | ||
get expirationTime(): number; | ||
constructor(store: SessionStore, state: SessionState, options: { | ||
exists: boolean; | ||
}); | ||
/** | ||
* The value of an element in the session content. | ||
* Sets or replaces the userId associated with the session. | ||
* | ||
* @param {({ id: number|string })} user - The user containing the ID. | ||
* @memberof Session | ||
*/ | ||
setUser(user: { | ||
id: number | string | object; | ||
} | { | ||
_id: number | string | object; | ||
}): void; | ||
/** | ||
* Adds or replaces an element in the session. This operation is not saved | ||
* in the saved unless you call the "commit" function. | ||
* | ||
* @param {string} key - The property key. | ||
* @param {*} value - The property value. | ||
* @param {{ flash?: boolean }} [options={}] If flash is true, the key/value | ||
* will be erased at the end of the next request. | ||
* @memberof Session | ||
*/ | ||
set(key: string, value: any, options?: { | ||
flash?: boolean; | ||
}): void; | ||
/** | ||
* Gets the value of a key in the session content. | ||
* | ||
* @template T | ||
* @param {string} key - The property key | ||
* @returns {(T | undefined)} The property valye | ||
* @param {string} key - The property key. | ||
* @returns {(T | undefined)} The property value. | ||
* @memberof Session | ||
@@ -52,6 +80,5 @@ */ | ||
/** | ||
* Get the session token. This token is used by `@TokenRequired` and `@TokenOptional` to retreive | ||
* the session and the authenticated user if she/he exists. | ||
* Gets the session ID. | ||
* | ||
* @returns {string} - The session token. | ||
* @returns {string} - The session ID. | ||
* @memberof Session | ||
@@ -61,8 +88,48 @@ */ | ||
/** | ||
* Get a copy of the session content. | ||
* Regenerates the session with a new ID. It is recommended | ||
* to regenerate the session ID after any privilege level change | ||
* within the associated user session. | ||
* | ||
* @returns {object} - The session content copy. | ||
* Common scenario: an anonymous user is authenticated. | ||
* | ||
* @returns {Promise<void>} | ||
* @memberof Session | ||
*/ | ||
getContent(): object; | ||
regenerateID(): Promise<void>; | ||
/** | ||
* Destroys the session. | ||
* | ||
* @returns {Promise<void>} | ||
* @memberof Session | ||
*/ | ||
destroy(): Promise<void>; | ||
/** | ||
* Returns true if the method `destroy` has previously been called. | ||
* | ||
* @readonly | ||
* @type {boolean} | ||
* @memberof Session | ||
*/ | ||
get isDestroyed(): boolean; | ||
/** | ||
* Saves or updates the session and extends its lifetime. | ||
* | ||
* If the session has already been destroyed, an error is thrown. | ||
* | ||
* This function calls periodically the store method "cleanUpExpiredSessions". | ||
* | ||
* @returns {Promise<void>} | ||
* @memberof Session | ||
*/ | ||
commit(): Promise<void>; | ||
/** | ||
* Returns the current time in seconds. | ||
* | ||
* @private | ||
* @returns {number} The current time. | ||
* @memberof Session | ||
*/ | ||
private getTime; | ||
private shouldCleanUpExpiredSessions; | ||
private getTimeouts; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Session = void 0; | ||
// FoalTS | ||
const common_1 = require("../common"); | ||
const core_1 = require("../core"); | ||
const constants_1 = require("./constants"); | ||
/** | ||
* Representation of a server/database session. | ||
* Representation of a server/database/file session. | ||
* | ||
@@ -13,25 +15,23 @@ * @export | ||
class Session { | ||
constructor(sessionID, sessionContent, createdAt) { | ||
this.sessionID = sessionID; | ||
this.sessionContent = sessionContent; | ||
this.createdAt = createdAt; | ||
this.modified = false; | ||
if (sessionID.includes('.')) { | ||
throw new Error('A session ID cannot include dots.'); | ||
} | ||
constructor(store, state, options) { | ||
this.store = store; | ||
this.state = state; | ||
this.oldId = ''; | ||
this.status = options.exists ? 'exists' : 'new'; | ||
this.oldFlash = state.flash; | ||
state.flash = {}; | ||
} | ||
/** | ||
* Verify a session token and return the sessionID if the token is valid. | ||
* Retuns the user ID. If the session is anonymous, the value is null. | ||
* | ||
* @static | ||
* @param {string} token - The session token to verify. | ||
* @returns {(string|false)} False if the token is invalid. Otherwise, the returned value is the session ID. | ||
* @readonly | ||
* @type {(string|number|null)} | ||
* @memberof Session | ||
*/ | ||
static verifyTokenAndGetId(token) { | ||
const secret = core_1.Config.getOrThrow('settings.session.secret', 'string', 'You must provide a secret when using sessions.'); | ||
return common_1.verifySignedToken(token, secret); | ||
get userId() { | ||
return this.state.userId; | ||
} | ||
/** | ||
* Return true if an element was added/replaced in the session | ||
* Returns true if the session has expired due to inactivity | ||
* or because it reached the maximum lifetime allowed. | ||
* | ||
@@ -42,44 +42,175 @@ * @readonly | ||
*/ | ||
get isModified() { | ||
return this.modified; | ||
get isExpired() { | ||
const { absoluteTimeout, inactivityTimeout } = this.getTimeouts(); | ||
const now = this.getTime(); | ||
if (now - this.state.updatedAt >= inactivityTimeout) { | ||
return true; | ||
} | ||
if (now - this.state.createdAt >= absoluteTimeout) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
/** | ||
* Add/replace an element in the session. This operation is not saved | ||
* in the saved unless you call SessionStore.update(session). | ||
* Returns the session expiration time in seconds. | ||
* | ||
* @param {string} key | ||
* @param {*} value | ||
* @readonly | ||
* @type {number} | ||
* @memberof Session | ||
*/ | ||
set(key, value) { | ||
this.sessionContent[key] = value; | ||
this.modified = true; | ||
get expirationTime() { | ||
const { absoluteTimeout, inactivityTimeout } = this.getTimeouts(); | ||
return Math.min(this.state.updatedAt + inactivityTimeout, this.state.createdAt + absoluteTimeout); | ||
} | ||
/** | ||
* Sets or replaces the userId associated with the session. | ||
* | ||
* @param {({ id: number|string })} user - The user containing the ID. | ||
* @memberof Session | ||
*/ | ||
setUser(user) { | ||
var _a; | ||
// tslint:disable-next-line | ||
const id = (_a = user.id) !== null && _a !== void 0 ? _a : user._id; | ||
if (typeof id === 'object') { | ||
this.state.userId = id.toString(); | ||
return; | ||
} | ||
this.state.userId = id; | ||
} | ||
/** | ||
* Adds or replaces an element in the session. This operation is not saved | ||
* in the saved unless you call the "commit" function. | ||
* | ||
* @param {string} key - The property key. | ||
* @param {*} value - The property value. | ||
* @param {{ flash?: boolean }} [options={}] If flash is true, the key/value | ||
* will be erased at the end of the next request. | ||
* @memberof Session | ||
*/ | ||
set(key, value, options = {}) { | ||
if (options.flash) { | ||
this.state.flash[key] = value; | ||
} | ||
else { | ||
this.state.content[key] = value; | ||
} | ||
} | ||
get(key, defaultValue) { | ||
if (!this.sessionContent.hasOwnProperty(key)) { | ||
return defaultValue; | ||
if (this.oldFlash.hasOwnProperty(key)) { | ||
return this.oldFlash[key]; | ||
} | ||
return this.sessionContent[key]; | ||
if (this.state.content.hasOwnProperty(key)) { | ||
return this.state.content[key]; | ||
} | ||
return defaultValue; | ||
} | ||
/** | ||
* Get the session token. This token is used by `@TokenRequired` and `@TokenOptional` to retreive | ||
* the session and the authenticated user if she/he exists. | ||
* Gets the session ID. | ||
* | ||
* @returns {string} - The session token. | ||
* @returns {string} - The session ID. | ||
* @memberof Session | ||
*/ | ||
getToken() { | ||
const secret = core_1.Config.getOrThrow('settings.session.secret', 'string', 'You must provide a secret when using sessions.'); | ||
return common_1.signToken(this.sessionID, secret); | ||
return this.state.id; | ||
} | ||
/** | ||
* Get a copy of the session content. | ||
* Regenerates the session with a new ID. It is recommended | ||
* to regenerate the session ID after any privilege level change | ||
* within the associated user session. | ||
* | ||
* @returns {object} - The session content copy. | ||
* Common scenario: an anonymous user is authenticated. | ||
* | ||
* @returns {Promise<void>} | ||
* @memberof Session | ||
*/ | ||
getContent() { | ||
return Object.assign({}, this.sessionContent); | ||
async regenerateID() { | ||
this.oldId = this.state.id; | ||
this.state.id = await common_1.generateToken(); | ||
this.status = 'regenerated'; | ||
} | ||
/** | ||
* Destroys the session. | ||
* | ||
* @returns {Promise<void>} | ||
* @memberof Session | ||
*/ | ||
async destroy() { | ||
await this.store.destroy(this.state.id); | ||
this.status = 'destroyed'; | ||
} | ||
/** | ||
* Returns true if the method `destroy` has previously been called. | ||
* | ||
* @readonly | ||
* @type {boolean} | ||
* @memberof Session | ||
*/ | ||
get isDestroyed() { | ||
return this.status === 'destroyed'; | ||
} | ||
/** | ||
* Saves or updates the session and extends its lifetime. | ||
* | ||
* If the session has already been destroyed, an error is thrown. | ||
* | ||
* This function calls periodically the store method "cleanUpExpiredSessions". | ||
* | ||
* @returns {Promise<void>} | ||
* @memberof Session | ||
*/ | ||
async commit() { | ||
const { absoluteTimeout, inactivityTimeout } = this.getTimeouts(); | ||
if (this.shouldCleanUpExpiredSessions()) { | ||
await this.store.cleanUpExpiredSessions(inactivityTimeout, absoluteTimeout); | ||
} | ||
this.state.updatedAt = this.getTime(); | ||
switch (this.status) { | ||
case 'regenerated': | ||
await this.store.destroy(this.oldId); | ||
await this.store.save(this.state, inactivityTimeout); | ||
this.status = 'exists'; | ||
break; | ||
case 'new': | ||
await this.store.save(this.state, inactivityTimeout); | ||
this.status = 'exists'; | ||
break; | ||
case 'exists': | ||
await this.store.update(this.state, inactivityTimeout); | ||
break; | ||
case 'destroyed': | ||
throw new Error('Impossible to commit the session. Session already destroyed.'); | ||
default: | ||
break; | ||
} | ||
} | ||
/** | ||
* Returns the current time in seconds. | ||
* | ||
* @private | ||
* @returns {number} The current time. | ||
* @memberof Session | ||
*/ | ||
getTime() { | ||
return Math.trunc(Date.now() / 1000); | ||
} | ||
shouldCleanUpExpiredSessions() { | ||
const periodicity = core_1.Config.get('settings.session.garbageCollector.periodicity', 'number', constants_1.SESSION_DEFAULT_GARBAGE_COLLECTOR_PERIODICITY); | ||
return Math.trunc(Math.random() * periodicity) === 0; | ||
} | ||
getTimeouts() { | ||
const inactivityTimeout = core_1.Config.get('settings.session.expirationTimeouts.inactivity', 'number', constants_1.SESSION_DEFAULT_INACTIVITY_TIMEOUT); | ||
if (inactivityTimeout < 0) { | ||
throw new Error('[CONFIG] The value of settings.session.expirationTimeouts.inactivity must be a positive number.'); | ||
} | ||
const absoluteTimeout = core_1.Config.get('settings.session.expirationTimeouts.absolute', 'number', constants_1.SESSION_DEFAULT_ABSOLUTE_TIMEOUT); | ||
if (absoluteTimeout < 0) { | ||
throw new Error('[CONFIG] The value of settings.session.expirationTimeouts.absolute must be a positive number.'); | ||
} | ||
if (absoluteTimeout < inactivityTimeout) { | ||
throw new Error('[CONFIG] The value of settings.session.expirationTimeouts.absolute must be greater than *.inactivity.'); | ||
} | ||
return { absoluteTimeout, inactivityTimeout }; | ||
} | ||
} | ||
exports.Session = Session; |
import { HttpResponse } from '../core'; | ||
import { Session } from './session'; | ||
/** | ||
* Send the session token in a cookie. | ||
* Sends the session token in a cookie. | ||
* | ||
* If the CSRF protection is enabled, it also sends the CSRF token in a CSRF cookie. | ||
* | ||
* @export | ||
* @param {HttpResponse} response - The HTTP response | ||
* @param {string} token - The session token | ||
* @param {HttpResponse} response - The HTTP response. | ||
* @param {Session} session - The session object. | ||
*/ | ||
export declare function setSessionCookie(response: HttpResponse, token: string): void; | ||
export declare function setSessionCookie(response: HttpResponse, session: Session): void; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.setSessionCookie = void 0; | ||
// FoalTS | ||
const core_1 = require("../core"); | ||
const constants_1 = require("./constants"); | ||
const session_store_1 = require("./session-store"); | ||
/** | ||
* Send the session token in a cookie. | ||
* Sends the session token in a cookie. | ||
* | ||
* If the CSRF protection is enabled, it also sends the CSRF token in a CSRF cookie. | ||
* | ||
* @export | ||
* @param {HttpResponse} response - The HTTP response | ||
* @param {string} token - The session token | ||
* @param {HttpResponse} response - The HTTP response. | ||
* @param {Session} session - The session object. | ||
*/ | ||
function setSessionCookie(response, token) { | ||
const cookieName = core_1.Config.get2('settings.session.cookie.name', 'string', constants_1.SESSION_DEFAULT_COOKIE_NAME); | ||
function setSessionCookie(response, session) { | ||
const cookieName = core_1.Config.get('settings.session.cookie.name', 'string', constants_1.SESSION_DEFAULT_COOKIE_NAME); | ||
const csrfEnabled = core_1.Config.get('settings.session.csrf.enabled', 'boolean', false); | ||
let sameSite = core_1.Config.get('settings.session.cookie.sameSite', 'string'); | ||
if (csrfEnabled && sameSite === undefined) { | ||
sameSite = constants_1.SESSION_DEFAULT_SAME_SITE_ON_CSRF_ENABLED; | ||
} | ||
const options = { | ||
domain: core_1.Config.get2('settings.session.cookie.domain', 'string'), | ||
httpOnly: core_1.Config.get2('settings.session.cookie.httpOnly', 'boolean', constants_1.SESSION_DEFAULT_COOKIE_HTTP_ONLY), | ||
maxAge: session_store_1.SessionStore.getExpirationTimeouts().inactivity, | ||
path: core_1.Config.get2('settings.session.cookie.path', 'string', constants_1.SESSION_DEFAULT_COOKIE_PATH), | ||
sameSite: core_1.Config.get2('settings.session.cookie.sameSite', 'string'), | ||
secure: core_1.Config.get2('settings.session.cookie.secure', 'boolean') | ||
domain: core_1.Config.get('settings.session.cookie.domain', 'string'), | ||
expires: new Date(session.expirationTime * 1000), | ||
path: core_1.Config.get('settings.session.cookie.path', 'string', constants_1.SESSION_DEFAULT_COOKIE_PATH), | ||
sameSite, | ||
secure: core_1.Config.get('settings.session.cookie.secure', 'boolean') | ||
}; | ||
response.setCookie(cookieName, token, options); | ||
response.setCookie(cookieName, session.getToken(), Object.assign(Object.assign({}, options), { httpOnly: core_1.Config.get('settings.session.cookie.httpOnly', 'boolean', constants_1.SESSION_DEFAULT_COOKIE_HTTP_ONLY) })); | ||
if (csrfEnabled) { | ||
const csrfCookieName = core_1.Config.get('settings.session.csrf.cookie.name', 'string', constants_1.SESSION_DEFAULT_CSRF_COOKIE_NAME); | ||
response.setCookie(csrfCookieName, session.get('csrfToken') || '', Object.assign(Object.assign({}, options), { httpOnly: false })); | ||
} | ||
} | ||
exports.setSessionCookie = setSessionCookie; |
{ | ||
"name": "@foal/core", | ||
"version": "1.11.1", | ||
"version": "2.0.0-beta.0", | ||
"description": "A Node.js and TypeScript framework, all-inclusive.", | ||
@@ -9,11 +9,11 @@ "main": "./lib/index.js", | ||
"docs": "typedoc --out ../../docs/api/core src/index.ts --readme none --theme markdown", | ||
"test": "nyc --reporter=json --reporter=text mocha --require ts-node/register --require source-map-support/register \"./src/**/*.spec.ts\"", | ||
"dev:test": "mocha --require ts-node/register --watch --watch-extensions ts \"./src/**/*.spec.ts\"", | ||
"dev:test:auth": "mocha --require ts-node/register --watch --watch-extensions ts \"./src/auth/**/*.spec.ts\"", | ||
"dev:test:common": "mocha --require ts-node/register --watch --watch-extensions ts \"./src/common/**/*.spec.ts\"", | ||
"test": "nyc --reporter=json --reporter=text mocha --parallel --require ts-node/register --require source-map-support/register \"./src/**/*.spec.ts\"", | ||
"dev:test": "mocha --require ts-node/register --watch --extension ts \"./src/**/*.spec.ts\"", | ||
"dev:test:auth": "mocha --require ts-node/register --watch --extension ts \"./src/auth/**/*.spec.ts\"", | ||
"dev:test:common": "mocha --require ts-node/register --watch --extension ts \"./src/common/**/*.spec.ts\"", | ||
"test:common": "mocha --require ts-node/register \"./src/common/**/*.spec.ts\"", | ||
"dev:test:core": "mocha --require ts-node/register --watch --watch-extensions ts \"./src/core/**/*.spec.ts\"", | ||
"dev:test:express": "mocha --require ts-node/register --watch --watch-extensions ts \"./src/express/**/*.spec.ts\"", | ||
"dev:test:openapi": "mocha --require ts-node/register --watch --watch-extensions ts \"./src/openapi/**/*.spec.ts\"", | ||
"dev:test:sessions": "mocha --require ts-node/register --watch --watch-extensions ts \"./src/sessions/**/*.spec.ts\"", | ||
"dev:test:core": "mocha --require ts-node/register --watch --extension ts \"./src/core/**/*.spec.ts\"", | ||
"dev:test:express": "mocha --require ts-node/register --watch --extension ts \"./src/express/**/*.spec.ts\"", | ||
"dev:test:openapi": "mocha --require ts-node/register --watch --extension ts \"./src/openapi/**/*.spec.ts\"", | ||
"dev:test:sessions": "mocha --require ts-node/register --watch --extension ts \"./src/sessions/**/*.spec.ts\"", | ||
"build": "rimraf lib && copy-cli \"./src/**/500.debug.html\" lib && tsc -p tsconfig-build.json", | ||
@@ -26,3 +26,3 @@ "prepublish": "npm run build" | ||
"engines": { | ||
"node": ">=8" | ||
"node": ">=10" | ||
}, | ||
@@ -87,31 +87,25 @@ "publishConfig": { | ||
"express": "~4.17.1", | ||
"mime": "~2.4.4", | ||
"morgan": "~1.10.0", | ||
"pump": "~3.0.0", | ||
"reflect-metadata": "~0.1.13" | ||
}, | ||
"devDependencies": { | ||
"@foal/ejs": "^1.11.1", | ||
"@foal/internal-test": "^1.11.1", | ||
"@types/mocha": "~2.2.43", | ||
"@types/node": "~10.1.2", | ||
"@types/supertest": "~2.0.5", | ||
"@foal/internal-test": "^2.0.0-beta.0", | ||
"@types/mocha": "7.0.2", | ||
"@types/node": "10.17.24", | ||
"@types/supertest": "2.0.10", | ||
"copy": "~0.3.2", | ||
"ejs": "~2.6.2", | ||
"mocha": "~5.2.0", | ||
"mysql": "~2.15.0", | ||
"node-mocks-http": "~1.7.0", | ||
"mocha": "~8.2.0", | ||
"nyc": "~12.0.2", | ||
"pg": "~7.4.3", | ||
"rimraf": "~2.6.2", | ||
"source-map-support": "~0.5.6", | ||
"supertest": "~3.1.0", | ||
"ts-node": "~3.3.0", | ||
"source-map-support": "~0.5.19", | ||
"supertest": "~6.0.0", | ||
"ts-node": "~9.0.0", | ||
"twig": "~1.13.3", | ||
"typedoc": "~0.14.2", | ||
"typedoc-plugin-markdown": "~1.2.0", | ||
"typescript": "~3.5.3", | ||
"typedoc": "~0.19.0", | ||
"typedoc-plugin-markdown": "~3.0.0", | ||
"typescript": "~4.0.2", | ||
"yamljs": "~0.3.0" | ||
}, | ||
"gitHead": "3dec926f141773926de45e44457216146647e48f" | ||
"gitHead": "5d8941fbd4765812b6c965f4a36a860a50f61d30" | ||
} |
<p align="center"> | ||
<a href="https://foalts.org" target="blank"> | ||
<img src="https://raw.githubusercontent.com/FoalTS/foal/master/docs/logo_title.png" height="160px" alt="Logo" /> | ||
<img src="https://raw.githubusercontent.com/FoalTS/foal/master/docs/images/logo_title.png" height="160px" alt="Logo" /> | ||
</a> | ||
@@ -15,3 +15,3 @@ <br> | ||
</a> | ||
<img src="https://img.shields.io/badge/node-%3E%3D8-brightgreen.svg" alt="node version"> | ||
<img src="https://img.shields.io/badge/node-%3E%3D10-brightgreen.svg" alt="node version"> | ||
<a href="https://badge.fury.io/js/%40foal%2Fcore"> | ||
@@ -18,0 +18,0 @@ <img src="https://badge.fury.io/js/%40foal%2Fcore.svg" alt="npm version"> |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
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
363057
5
17
2228
184
8596
1
13
1
- Removedmime@~2.4.4
- Removedpump@~3.0.0
- Removedend-of-stream@1.4.4(transitive)
- Removedmime@2.4.7(transitive)
- Removedonce@1.4.0(transitive)
- Removedpump@3.0.2(transitive)
- Removedwrappy@1.0.2(transitive)