Moved from CJS to ESM + small improvements like logging
This commit is contained in:
parent
61df35a271
commit
c57160e05d
16 changed files with 512 additions and 488 deletions
|
|
@ -31,8 +31,12 @@
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"republish": "yarn build && cp package.json dist/package.json && cd dist && npm unpublish --registry https://npm.pkg.bridgemanaccessible.ca --force @BridgemanAccessible/ba-web-framework@1.0.0 && npm publish --registry https://npm.pkg.bridgemanaccessible.ca && cd ../"
|
"republish": "yarn build && cp package.json dist/package.json && cd dist && npm unpublish --registry https://npm.pkg.bridgemanaccessible.ca --force @BridgemanAccessible/ba-web-framework@1.0.0 && npm publish --registry https://npm.pkg.bridgemanaccessible.ca && cd ../"
|
||||||
},
|
},
|
||||||
|
"bin": {
|
||||||
|
"create-ba-web-app": "node ./bin/create-project.js"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@BridgemanAccessible/ba-auth": "^1.0.0",
|
"@BridgemanAccessible/ba-auth": "^1.0.10",
|
||||||
|
"@BridgemanAccessible/ba-logging": "^1.0.1",
|
||||||
"express": "^4.19.2",
|
"express": "^4.19.2",
|
||||||
"fs-extra": "^11.2.0",
|
"fs-extra": "^11.2.0",
|
||||||
"jsdom": "^24.1.0",
|
"jsdom": "^24.1.0",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
import 'reflect-metadata';
|
import 'reflect-metadata';
|
||||||
import { Application } from 'express';
|
import { Application } from 'express';
|
||||||
|
|
||||||
import { Initializer } from './Initializer';
|
import { logMessage, LogLevel } from '@BridgemanAccessible/ba-logging';
|
||||||
|
|
||||||
|
import { Initializer } from './Initializer.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The top level container for running the web app
|
* The top level container for running the web app
|
||||||
|
|
@ -42,7 +44,7 @@ export class App {
|
||||||
// Start the server
|
// Start the server
|
||||||
const port = process.env.PORT || this.DEFAULT_PORT;
|
const port = process.env.PORT || this.DEFAULT_PORT;
|
||||||
this.getExpressApp().listen(port, async () => {
|
this.getExpressApp().listen(port, async () => {
|
||||||
console.log(`Server is running on port ${port}`);
|
logMessage(`Server is running on port ${port}`, LogLevel.DEBUG);
|
||||||
|
|
||||||
// Run the callback if one is provided
|
// Run the callback if one is provided
|
||||||
if(typeof callback !== 'undefined') {
|
if(typeof callback !== 'undefined') {
|
||||||
|
|
@ -50,7 +52,7 @@ export class App {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.on('error', async (error) => {
|
.on('error', async (error) => {
|
||||||
console.error('Error starting server:', error);
|
logMessage(`Error starting server: ${error}`, LogLevel.ERROR);
|
||||||
|
|
||||||
if(typeof onErrorCallback !== 'undefined') {
|
if(typeof onErrorCallback !== 'undefined') {
|
||||||
await onErrorCallback(error);
|
await onErrorCallback(error);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import express, { Application, RequestHandler } from 'express';
|
import express, { Application, RequestHandler } from 'express';
|
||||||
|
|
||||||
import { Router } from './Router';
|
import { Router } from './Router.js';
|
||||||
import { StaticFileResolver } from './StaticFileResolver';
|
import { StaticFileResolver } from './StaticFileResolver.js';
|
||||||
import { Renderer } from './Renderer';
|
import { Renderer } from './Renderer.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object to encapsulate the setup of the app
|
* Object to encapsulate the setup of the app
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
import { Application } from 'express';
|
import { Application } from 'express';
|
||||||
import { Scopes } from '@BridgemanAccessible/ba-auth';
|
import { Scopes } from '@BridgemanAccessible/ba-auth';
|
||||||
import Client, { OnAuthCallback } from '@BridgemanAccessible/ba-auth/client';
|
import Client, { OnAuthCallback } from '@BridgemanAccessible/ba-auth/client';
|
||||||
|
import { logMessage, LogLevel } from '@BridgemanAccessible/ba-logging';
|
||||||
|
|
||||||
import { App } from './App';
|
import { App } from './App.js';
|
||||||
import { Initializer } from './Initializer';
|
import { Initializer } from './Initializer.js';
|
||||||
|
|
||||||
import { getValueFromEnvironmentVariable } from './utils/env-vars';
|
import { getValueFromEnvironmentVariable } from './utils/env-vars.js';
|
||||||
|
|
||||||
type OAuthAppOptions = {
|
type OAuthAppOptions = {
|
||||||
/** The base URL of the app */
|
/** The base URL of the app */
|
||||||
|
|
@ -140,25 +141,36 @@ export class OAuthApp extends App {
|
||||||
appAbbrv = getValueFromEnvironmentVariable('APP_ABBRV', { description: 'app abbreviation', blank_allowed: false });
|
appAbbrv = getValueFromEnvironmentVariable('APP_ABBRV', { description: 'app abbreviation', blank_allowed: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Attempting to create/register the app:\n\tApp Base URL: ${baseAppUrl}\n\tApp Abbreviation: ${appAbbrv}\n\tApp Name: ${typeof this.appName === 'undefined' ? 'uses APP_NAME environment variable (' + process.env.APP_NAME + ')' : this.appName}\n\tScopes: ${typeof this.scopes === 'undefined' ? 'uses SCOPES environment variable (' + process.env.SCOPES + ')' : this.scopes.join(', ')}`);
|
logMessage(`Attempting to create/register the app:\n\tApp Base URL: ${baseAppUrl}\n\tApp Abbreviation: ${appAbbrv}\n\tApp Name: ${typeof this.appName === 'undefined' ? 'uses APP_NAME environment variable (' + process.env.APP_NAME + ')' : this.appName}\n\tScopes: ${typeof this.scopes === 'undefined' ? 'uses SCOPES environment variable (' + process.env.SCOPES + ')' : this.scopes.join(', ')}`, LogLevel.DEBUG);
|
||||||
|
|
||||||
// Because we need this for registration to work properly. It make sense to put it here
|
// Because we need this for registration to work properly. It make sense to put it here
|
||||||
app.getInitializer().getRouter().addOutsideFrameworkRoute('/.well-known/jwks.json');
|
app.getInitializer()
|
||||||
|
.getRouter()
|
||||||
|
.addOutsideFrameworkRoute('/.well-known/jwks.json');
|
||||||
|
|
||||||
const client = await Client.setup(app.getExpressApp(), baseAppUrl, this.onAuth, this.saveSecret, appAbbrv, this.appName, this.scopes, {
|
const client = await Client.setup(
|
||||||
contacts: this.contacts,
|
app.getExpressApp(),
|
||||||
logo_url: this.logo_url,
|
baseAppUrl,
|
||||||
tos_url: this.tos_url,
|
this.onAuth,
|
||||||
policy_url: this.policy_url,
|
this.saveSecret,
|
||||||
vault_type: this.vault_type,
|
appAbbrv,
|
||||||
auth_default_method: this.auth_default_method,
|
this.appName,
|
||||||
auth_default_use_JWT: this.auth_default_use_JWT,
|
this.scopes,
|
||||||
auth_default_response_mode: this.auth_default_response_mode,
|
{
|
||||||
client_secret: this.client_secret
|
contacts: this.contacts,
|
||||||
});
|
logo_url: this.logo_url,
|
||||||
|
tos_url: this.tos_url,
|
||||||
|
policy_url: this.policy_url,
|
||||||
|
vault_type: this.vault_type,
|
||||||
|
auth_default_method: this.auth_default_method,
|
||||||
|
auth_default_use_JWT: this.auth_default_use_JWT,
|
||||||
|
auth_default_response_mode: this.auth_default_response_mode,
|
||||||
|
client_secret: this.client_secret
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
client.getSetupRoutes().forEach((route) => {
|
client.getSetupRoutes().forEach((route) => {
|
||||||
console.log(`Adding outside framework route: ${route}`);
|
logMessage(`Adding outside framework route: ${route}`, LogLevel.DEBUG);
|
||||||
app.getInitializer().getRouter().addOutsideFrameworkRoute(route);
|
app.getInitializer().getRouter().addOutsideFrameworkRoute(route);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -184,9 +196,9 @@ export class OAuthApp extends App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(err) {
|
catch(err) {
|
||||||
console.error('Error setting up the BA User Auth');
|
logMessage('Error setting up the BA User Auth', LogLevel.ERROR);
|
||||||
console.error('---------------------------------');
|
logMessage('---------------------------------', LogLevel.ERROR);
|
||||||
console.error(err);
|
logMessage(JSON.stringify(err), LogLevel.ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { existsSync, statSync } from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { Application } from 'express';
|
import { Application } from 'express';
|
||||||
|
|
||||||
import { BaseTemplateInputs, BaseTemplateCreator } from './BaseTemplateCreator';
|
import { BaseTemplateInputs, BaseTemplateCreator } from './BaseTemplateCreator.js';
|
||||||
|
|
||||||
export class Renderer {
|
export class Renderer {
|
||||||
/** The default folder name for the views */
|
/** The default folder name for the views */
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,10 @@ import path from 'path';
|
||||||
import { Application } from 'express';
|
import { Application } from 'express';
|
||||||
import fse from 'fs-extra';
|
import fse from 'fs-extra';
|
||||||
|
|
||||||
import { BaseController } from './controllers/BaseController';
|
import { logMessage, LogLevel } from '@BridgemanAccessible/ba-logging';
|
||||||
import { ErrorController } from './controllers/ErrorController';
|
|
||||||
|
import { BaseController } from './controllers/BaseController.js';
|
||||||
|
import { ErrorController } from './controllers/ErrorController.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Router sets up the routes/endpoints for the App.
|
* The Router sets up the routes/endpoints for the App.
|
||||||
|
|
@ -87,7 +89,7 @@ export class Router {
|
||||||
// Load the file as a module
|
// Load the file as a module
|
||||||
const controllerModule = require(controllerPath);
|
const controllerModule = require(controllerPath);
|
||||||
|
|
||||||
console.log(`${controllerPath} loaded successfully: ${JSON.stringify(Object.keys(controllerModule))} exports found.`)
|
logMessage(`${controllerPath} loaded successfully: ${JSON.stringify(Object.keys(controllerModule))} exports found.`, LogLevel.DEBUG);
|
||||||
|
|
||||||
// Get all the classes in the module
|
// Get all the classes in the module
|
||||||
const classes = Object.keys(controllerModule)
|
const classes = Object.keys(controllerModule)
|
||||||
|
|
@ -152,7 +154,7 @@ export class Router {
|
||||||
*/
|
*/
|
||||||
private getRoutesInController(controller: any) {
|
private getRoutesInController(controller: any) {
|
||||||
if (typeof controller === 'undefined') {
|
if (typeof controller === 'undefined') {
|
||||||
console.error(`Something went wrong while processing ${JSON.stringify(controller)}`);
|
logMessage(`Something went wrong while processing ${JSON.stringify(controller)}`, LogLevel.ERROR);
|
||||||
throw new Error('The controller must be a class');
|
throw new Error('The controller must be a class');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -239,7 +241,7 @@ export class Router {
|
||||||
routes = this.getRoutesInController(controller);
|
routes = this.getRoutesInController(controller);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
console.error(`Something went wrong while processing ${JSON.stringify(controller)} (${JSON.stringify(decoratedController)})`);
|
logMessage(`Something went wrong while processing ${JSON.stringify(controller)} (${JSON.stringify(decoratedController)})`, LogLevel.ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
routes.GET.forEach((path) => {
|
routes.GET.forEach((path) => {
|
||||||
|
|
@ -315,8 +317,8 @@ export class Router {
|
||||||
// Add the routes for the top level controllers to the list of added routes and call the setup method
|
// Add the routes for the top level controllers to the list of added routes and call the setup method
|
||||||
addedRoutes = addedRoutes.concat((await Promise.all(topLevelControllers.map(async (decoratedController) => await this.processControllerRoutes(app, decoratedController)))).flat());
|
addedRoutes = addedRoutes.concat((await Promise.all(topLevelControllers.map(async (decoratedController) => await this.processControllerRoutes(app, decoratedController)))).flat());
|
||||||
|
|
||||||
console.log('Routes added:');
|
logMessage('Routes added:', LogLevel.DEBUG);
|
||||||
addedRoutes.forEach(route => console.log('\t' + route));
|
addedRoutes.forEach(route => logMessage('\t' + route, LogLevel.DEBUG));
|
||||||
|
|
||||||
// Adding a GET handler/middleware to handle 404 errors
|
// Adding a GET handler/middleware to handle 404 errors
|
||||||
// This is done by adding this as the last path (after all other routes)
|
// This is done by adding this as the last path (after all other routes)
|
||||||
|
|
@ -340,7 +342,7 @@ export class Router {
|
||||||
let handledErrors: string[] = [];
|
let handledErrors: string[] = [];
|
||||||
loadedErrorControllers.forEach(errorController => {
|
loadedErrorControllers.forEach(errorController => {
|
||||||
if (typeof errorController.handle === 'undefined') {
|
if (typeof errorController.handle === 'undefined') {
|
||||||
console.error(`Something went wrong while processing ${JSON.stringify(Object.entries(errorController))}`);
|
logMessage(`Something went wrong while processing ${JSON.stringify(Object.entries(errorController))}`, LogLevel.ERROR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -348,8 +350,8 @@ export class Router {
|
||||||
handledErrors.push(errorController.handlesError ?? '');
|
handledErrors.push(errorController.handlesError ?? '');
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('Error controllers added:');
|
logMessage('Error controllers added:', LogLevel.DEBUG);
|
||||||
handledErrors.forEach(error => console.log('\t' + error));
|
handledErrors.forEach(errorControllers => logMessage('\t' + errorControllers, LogLevel.DEBUG));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -358,7 +360,7 @@ export class Router {
|
||||||
* @param app The Express app to add the routes to
|
* @param app The Express app to add the routes to
|
||||||
*/
|
*/
|
||||||
async setup(app: Application) {
|
async setup(app: Application) {
|
||||||
console.log('Setting up routes...')
|
logMessage('Setting up routes...', LogLevel.DEBUG);
|
||||||
|
|
||||||
await this.setupControllers(app);
|
await this.setupControllers(app);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,5 @@ export abstract class ErrorController {
|
||||||
/** A human readable string to describe the error this controller handles. */
|
/** A human readable string to describe the error this controller handles. */
|
||||||
public handlesError?: string;
|
public handlesError?: string;
|
||||||
|
|
||||||
|
|
||||||
abstract handle(error: unknown, req: Request, res: Response, next: NextFunction): any | Promise<any>;
|
abstract handle(error: unknown, req: Request, res: Response, next: NextFunction): any | Promise<any>;
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { BaseController } from './BaseController';
|
import { BaseController } from './BaseController.js';
|
||||||
import { ErrorController } from './ErrorController';
|
import { ErrorController } from './ErrorController.js';
|
||||||
|
|
||||||
export { BaseController, ErrorController };
|
export { BaseController, ErrorController };
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { BaseController } from '../controllers/BaseController';
|
import { BaseController } from '../controllers/BaseController.js';
|
||||||
|
|
||||||
export const CHILD_CONTROLLER_METADATA_KEY = 'ChildController';
|
export const CHILD_CONTROLLER_METADATA_KEY = 'ChildController';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import { Application, Request, Response, NextFunction } from 'express';
|
import { Application, Request, Response, NextFunction } from 'express';
|
||||||
|
|
||||||
import { BaseController } from '../controllers/BaseController';
|
import { BaseController } from '../controllers/BaseController.js';
|
||||||
|
|
||||||
import { CHILD_CONTROLLER_METADATA_KEY } from './ChildController';
|
import { CHILD_CONTROLLER_METADATA_KEY } from './ChildController.js';
|
||||||
import { GET_METADATA_KEY } from './GET';
|
import { GET_METADATA_KEY } from './GET.js';
|
||||||
import { POST_METADATA_KEY } from './POST';
|
import { POST_METADATA_KEY } from './POST.js';
|
||||||
import { PUT_METADATA_KEY } from './PUT';
|
import { PUT_METADATA_KEY } from './PUT.js';
|
||||||
import { DELETE_METADATA_KEY } from './DELETE';
|
import { DELETE_METADATA_KEY } from './DELETE.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class decorator to "fill in" the setup method which is called on server startup and connects the methods/functions and their desired paths in the express app.
|
* Class decorator to "fill in" the setup method which is called on server startup and connects the methods/functions and their desired paths in the express app.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { Request, Response, NextFunction } from 'express';
|
import { Request, Response, NextFunction } from 'express';
|
||||||
|
|
||||||
import { ErrorController } from '../controllers/ErrorController';
|
import { ErrorController } from '../controllers/ErrorController.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class decorator to create custom error handling for the app.
|
* Class decorator to create custom error handling for the app.
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { Controller } from './Controller';
|
import { Controller } from './Controller.js';
|
||||||
import { ChildController } from './ChildController';
|
import { ChildController } from './ChildController.js';
|
||||||
import { Page } from './Page';
|
import { Page } from './Page.js';
|
||||||
import { GET } from './GET';
|
import { GET } from './GET.js';
|
||||||
import { POST } from './POST';
|
import { POST } from './POST.js';
|
||||||
import { PUT } from './PUT';
|
import { PUT } from './PUT.js';
|
||||||
import { DELETE } from './DELETE';
|
import { DELETE } from './DELETE.js';
|
||||||
import { ErrorHandler } from './ErrorHandler';
|
import { ErrorHandler } from './ErrorHandler.js';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Controller,
|
Controller,
|
||||||
|
|
|
||||||
12
src/index.ts
12
src/index.ts
|
|
@ -1,9 +1,9 @@
|
||||||
import { App } from './App';
|
import { App } from './App.js';
|
||||||
import { Initializer } from './Initializer';
|
import { Initializer } from './Initializer.js';
|
||||||
import { Router } from './Router';
|
import { Router } from './Router.js';
|
||||||
import { Renderer } from './Renderer';
|
import { Renderer } from './Renderer.js';
|
||||||
import { StaticFileResolver } from './StaticFileResolver';
|
import { StaticFileResolver } from './StaticFileResolver.js';
|
||||||
import { OAuthApp } from './OAuthApp';
|
import { OAuthApp } from './OAuthApp.js';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
App,
|
App,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { globalTemplateValues } from './GlobalTemplateValuesMiddleware';
|
import { globalTemplateValues } from './GlobalTemplateValuesMiddleware.js';
|
||||||
import { HealthCheckStatus, HealthCheckMiddleware, healthCheckMiddleware } from './HealthCheckMiddleware';
|
import { HealthCheckStatus, HealthCheckMiddleware, healthCheckMiddleware } from './HealthCheckMiddleware.js';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
globalTemplateValues,
|
globalTemplateValues,
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,10 @@
|
||||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||||
|
|
||||||
/* Modules */
|
/* Modules */
|
||||||
"module": "CommonJS", /* Specify what module code is generated. */
|
"module": "nodenext", /* Specify what module code is generated. */
|
||||||
"rootDir": "src", /* Specify the root folder within your source files. */
|
"rootDir": "src", /* Specify the root folder within your source files. */
|
||||||
"moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
|
"moduleResolution": "nodenext", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||||
"baseUrl": ".", /* Specify the base directory to resolve non-relative module names. */
|
// "baseUrl": "", /* Specify the base directory to resolve non-relative module names. */
|
||||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||||
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue