@haibun/web-server-express
Advanced tools
Comparing version 0.2.1 to 1.0.0
import { RequestHandler } from 'express'; | ||
import { TLogger } from '@haibun/core/build/lib/defs'; | ||
import { IWebServer, TRouteType } from './web-server-stepper'; | ||
import { IWebServer, TRouteType } from './defs'; | ||
import { ILogger } from '@haibun/core/src/lib/interfaces/logger'; | ||
export declare const DEFAULT_PORT = 8123; | ||
export declare class ServerExpress implements IWebServer { | ||
logger: TLogger; | ||
static listener: any; | ||
static app: import("express-serve-static-core").Express; | ||
logger: ILogger; | ||
static listening: boolean; | ||
listener: any; | ||
app: import("express-serve-static-core").Express; | ||
static mounted: { | ||
@@ -13,6 +14,9 @@ [named: string]: string; | ||
base: string; | ||
constructor(logger: TLogger, base: string, port?: number); | ||
listening(port: number): Promise<void>; | ||
port: number; | ||
constructor(logger: ILogger, base: string, port?: number); | ||
listen(): Promise<IWebServer>; | ||
addRoute(type: TRouteType, path: string, route: RequestHandler): Promise<any>; | ||
addStaticFolder(subdir: string): Promise<string | undefined>; | ||
addStaticFolder(relativeFolder: string, mountAt?: string): Promise<string | undefined>; | ||
addKnownStaticFolder(folder: string, mountAt?: string): Promise<string | undefined>; | ||
doAddStaticFolder(folder: string, mountAt?: string): Promise<string | undefined>; | ||
checkMountBadOrMounted(loc: string, what: string): boolean; | ||
@@ -19,0 +23,0 @@ close(): Promise<void>; |
@@ -12,12 +12,22 @@ "use strict"; | ||
constructor(logger, base, port = exports.DEFAULT_PORT) { | ||
this.app = express_1.default(); | ||
this.logger = logger; | ||
this.base = base; | ||
this.port = port; | ||
} | ||
async listening(port) { | ||
if (!ServerExpress.listener) { | ||
ServerExpress.listener = await ServerExpress.app.listen(port, () => this.logger.log(`Server listening on port: ${port}`)); | ||
async listen() { | ||
if (!ServerExpress.listening) { | ||
try { | ||
ServerExpress.listening = true; | ||
this.listener = await this.app.listen(this.port, () => this.logger.log(`Server listening on port: ${this.port}`)); | ||
this.logger.log('express listening'); | ||
} | ||
catch (e) { | ||
console.error(e); | ||
} | ||
} | ||
else { | ||
this.logger.log('express already started'); | ||
this.logger.log('express already listening'); | ||
} | ||
return this; | ||
} | ||
@@ -35,11 +45,23 @@ async addRoute(type, path, route) { | ||
this.logger.log(`serving route from ${path}`); | ||
await ServerExpress.app[type](path, route); | ||
await this.app[type](path, route); | ||
await this.listen(); | ||
} | ||
async addStaticFolder(subdir) { | ||
const folder = [this.base, subdir].join('/'); | ||
const loc = '/'; | ||
// add a static folder restricted to relative paths from files | ||
async addStaticFolder(relativeFolder, mountAt = '/') { | ||
if (relativeFolder !== relativeFolder.replace(/[^a-zA-Z-0-9\/-_]/g, '').replace(/^\//g, '')) { | ||
throw Error(`mount folder ${relativeFolder} has illegal characters`); | ||
} | ||
const folder = [this.base, relativeFolder].join('/'); | ||
return this.doAddStaticFolder(folder, mountAt); | ||
} | ||
// add a static folder at any path | ||
async addKnownStaticFolder(folder, mountAt = '/') { | ||
return this.doAddStaticFolder(folder, mountAt); | ||
} | ||
async doAddStaticFolder(folder, mountAt = '/') { | ||
try { | ||
const alreadyMounted = this.checkMountBadOrMounted(loc, folder); | ||
const alreadyMounted = this.checkMountBadOrMounted(mountAt, folder); | ||
if (alreadyMounted) { | ||
return; | ||
// FIXME | ||
// return; | ||
} | ||
@@ -57,10 +79,11 @@ } | ||
} | ||
ServerExpress.mounted[loc] = folder; | ||
this.logger.info(`serving files from ${folder} at ${loc}`); | ||
await ServerExpress.app.use(express_1.default.static(folder)); | ||
ServerExpress.mounted[mountAt] = folder; | ||
this.logger.info(`serving files from ${folder} at ${mountAt}`); | ||
await this.app.use(mountAt, express_1.default.static(folder)); | ||
await this.listen(); | ||
return; | ||
} | ||
checkMountBadOrMounted(loc, what) { | ||
if (!ServerExpress.listener) { | ||
throw Error(`listening must be called before mount`); | ||
if (!ServerExpress.listening) { | ||
throw Error(`listen must be called before mount`); | ||
} | ||
@@ -70,5 +93,2 @@ if (!loc) { | ||
} | ||
if (loc !== loc.replace(/[^a-zA-Z-0-9\/]/g, '')) { | ||
throw Error(`mount folder ${loc} has illegal characters`); | ||
} | ||
const alreadyMounted = ServerExpress.mounted[loc]; | ||
@@ -86,8 +106,8 @@ if (alreadyMounted === what) { | ||
this.logger.info('closing server'); | ||
await ServerExpress.listener?.close(); | ||
await this.listener?.close(); | ||
} | ||
} | ||
exports.ServerExpress = ServerExpress; | ||
ServerExpress.app = express_1.default(); | ||
ServerExpress.listening = false; | ||
ServerExpress.mounted = {}; | ||
//# sourceMappingURL=server-express.js.map |
"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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
}) : function(o, v) { | ||
o["default"] = v; | ||
}); | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||
__setModuleDefault(result, mod); | ||
return result; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
@@ -27,4 +8,5 @@ return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
const util_1 = require("@haibun/core/build/lib/util"); | ||
const TestSteps_1 = require("@haibun/core/build/lib/TestSteps"); | ||
const web_server_stepper_1 = __importStar(require("./web-server-stepper")); | ||
const defs_1 = require("./defs"); | ||
const web_server_stepper_1 = __importDefault(require("./web-server-stepper")); | ||
const TestSteps_1 = require("@haibun/core/src/lib/TestSteps"); | ||
describe('route mount', () => { | ||
@@ -39,6 +21,5 @@ it('mounts a route', async () => { | ||
const route = (req, res) => res.status(200).send('ok'); | ||
const webserver = util_1.getFromRuntime(this.world.runtime, web_server_stepper_1.WEBSERVER); | ||
const checkListener = util_1.getFromRuntime(this.world.runtime, web_server_stepper_1.CHECK_LISTENER); | ||
await checkListener(this.world.options, webserver); | ||
const webserver = await util_1.getFromRuntime(this.world.runtime, defs_1.WEBSERVER); | ||
await webserver.addRoute('get', loc, route); | ||
webserver.listen(8123); | ||
return util_1.actionOK(); | ||
@@ -51,15 +32,15 @@ }, | ||
}; | ||
const { world } = util_1.getDefaultWorld(); | ||
const { result, steppers } = await TestSteps_1.testRun('/test/route', [web_server_stepper_1.default, TestRoute], world, { | ||
const feature = { path: '/features/test.feature', content: `serve test route to /test\n` }; | ||
const { result, steppers } = await TestSteps_1.testWithDefaults([feature], [web_server_stepper_1.default, TestRoute], { | ||
options: {}, | ||
extraOptions: { | ||
[`HAIBUN_O_${web_server_stepper_1.WEBSERVER_STEPPER.toUpperCase()}_PORT`]: '8124', | ||
[`HAIBUN_O_${defs_1.WEBSERVER_STEPPER.toUpperCase()}_PORT`]: '8124', | ||
}, | ||
}); | ||
expect(result.ok).toBe(true); | ||
const content = await node_fetch_1.default('http://localhost:8124/test'); | ||
const content = await node_fetch_1.default('http://localhost:8123/test'); | ||
expect(await content.text()).toEqual('ok'); | ||
util_1.getStepper(steppers, web_server_stepper_1.WEBSERVER_STEPPER).close(); | ||
util_1.getStepper(steppers, defs_1.WEBSERVER_STEPPER).close(); | ||
}); | ||
}); | ||
//# sourceMappingURL=web-server-stepper-route.test.js.map |
import { IExtensionConstructor, TOptions } from '@haibun/core/build/lib/defs'; | ||
import { RequestHandler } from 'express'; | ||
export declare const WEBSERVER = "webserver"; | ||
export declare const WEBSERVER_STEPPER = "WebServerStepper"; | ||
export declare const CHECK_LISTENER = "CHECK_LISTENER"; | ||
import { IWebServer } from './defs'; | ||
declare const WebServerStepper: IExtensionConstructor; | ||
@@ -14,8 +11,2 @@ export default WebServerStepper; | ||
} | ||
export interface IWebServer { | ||
addStaticFolder(subdir: string): Promise<string | undefined>; | ||
listening(port: number): void; | ||
addRoute(type: TRouteType, path: string, route: RequestHandler): void; | ||
} | ||
export declare type TRouteType = 'get'; | ||
//# sourceMappingURL=web-server-stepper.d.ts.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.CHECK_LISTENER = exports.WEBSERVER_STEPPER = exports.WEBSERVER = void 0; | ||
const defs_1 = require("@haibun/core/build/lib/defs"); | ||
const util_1 = require("@haibun/core/build/lib/util"); | ||
const defs_2 = require("./defs"); | ||
const server_express_1 = require("./server-express"); | ||
exports.WEBSERVER = 'webserver'; | ||
exports.WEBSERVER_STEPPER = 'WebServerStepper'; | ||
exports.CHECK_LISTENER = 'CHECK_LISTENER'; | ||
const WebServerStepper = class WebServerStepper { | ||
@@ -19,10 +16,22 @@ constructor(world) { | ||
this.steps = { | ||
isListening: { | ||
gwta: 'webserver is listening', | ||
action: async () => { | ||
await this.checkListener(this.world.options); | ||
return defs_1.OK; | ||
}, | ||
}, | ||
serveFiles: { | ||
gwta: 'serve files from {loc}', | ||
action: async ({ loc }) => { | ||
await WebServerStepper.checkListener(this.world.options, this.world.runtime[exports.WEBSERVER]); | ||
const ws = await this.world.runtime[exports.WEBSERVER]; | ||
const ws = await this.world.runtime[defs_2.WEBSERVER]; | ||
await ws.listen(8123); | ||
const error = await ws.addStaticFolder(loc); | ||
this.world.shared.set('file_location', loc); | ||
return error === undefined ? defs_1.OK : util_1.actionNotOK(error); | ||
}, | ||
build: async ({ loc }) => { | ||
this.world.shared.set('file_location', loc); | ||
return defs_1.OK; | ||
} | ||
}, | ||
@@ -32,11 +41,11 @@ }; | ||
this.webserver = new server_express_1.ServerExpress(this.world.logger, [process.cwd(), 'files'].join('/')); | ||
this.world.runtime[exports.WEBSERVER] = this.webserver; | ||
this.world.runtime[exports.CHECK_LISTENER] = WebServerStepper.checkListener; | ||
this.world.runtime[defs_2.WEBSERVER] = this.webserver; | ||
// this.world.runtime[CHECK_LISTENER] = WebServerStepper.checkListener; | ||
} | ||
async close() { | ||
async finish() { | ||
await this.webserver?.close(); | ||
} | ||
static async checkListener(options, webserver) { | ||
const port = options[`HAIBUN_O_${exports.WEBSERVER_STEPPER.toUpperCase()}_PORT`]; | ||
await webserver.listening(port || server_express_1.DEFAULT_PORT); | ||
async checkListener(options) { | ||
const port = options[`HAIBUN_O_${defs_2.WEBSERVER_STEPPER.toUpperCase()}_PORT`]; | ||
await this.webserver.listen(); | ||
} | ||
@@ -43,0 +52,0 @@ }; |
"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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
}) : function(o, v) { | ||
o["default"] = v; | ||
}); | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||
__setModuleDefault(result, mod); | ||
return result; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
@@ -26,35 +7,29 @@ return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
const node_fetch_1 = __importDefault(require("node-fetch")); | ||
const Executor_1 = require("@haibun/core/build/lib/Executor"); | ||
const util_1 = require("@haibun/core/build/lib/util"); | ||
const TestSteps_1 = require("@haibun/core/build/lib/TestSteps"); | ||
const web_server_stepper_1 = __importStar(require("./web-server-stepper")); | ||
const web_server_stepper_1 = __importDefault(require("./web-server-stepper")); | ||
const serverLoc = [process.cwd(), 'build', 'web-server-stepper'].join('/'); | ||
describe('static mount', () => { | ||
it('listens on serve files', async () => { | ||
const { world, vstep, steppers } = await TestSteps_1.getTestEnv([serverLoc], 'serve files from test', util_1.getDefaultWorld().world); | ||
const res = await Executor_1.Executor.doFeatureStep(vstep, world); | ||
expect(res.ok).toBe(true); | ||
const server = util_1.getStepper(steppers, web_server_stepper_1.WEBSERVER_STEPPER); | ||
expect(server.webserver).toBeDefined(); | ||
it('serves files', async () => { | ||
const feature = { path: '/features/test.feature', content: `serve files from test\n` }; | ||
const { result } = await TestSteps_1.testWithDefaults([feature], [web_server_stepper_1.default]); | ||
expect(result.ok).toBe(true); | ||
const content = await node_fetch_1.default('http://localhost:8123/testfile'); | ||
expect(await content.text()).toEqual('content'); | ||
await server.close(); | ||
}); | ||
it('restricts characters used in static mount folder name', async () => { | ||
const { world, vstep, steppers } = await TestSteps_1.getTestEnv([serverLoc], 'serve files from l*(*$**', util_1.getDefaultWorld().world); | ||
const res = await Executor_1.Executor.doFeatureStep(vstep, world); | ||
expect(res.ok).toBe(false); | ||
util_1.getStepper(steppers, web_server_stepper_1.WEBSERVER_STEPPER).close(); | ||
const feature = { path: '/features/test.feature', content: `serve files from l*(*$\n` }; | ||
const { result } = await TestSteps_1.testWithDefaults([feature], [web_server_stepper_1.default]); | ||
expect(result.ok).toBe(false); | ||
}); | ||
it("doesn't re-mount same static mount", async () => { | ||
const { result, steppers } = await TestSteps_1.testRun('/test/static-no-remount', [web_server_stepper_1.default], util_1.getDefaultWorld().world); | ||
const feature = { path: '/features/test.feature', content: `serve files from test\nserve files from test\n` }; | ||
const { result } = await TestSteps_1.testWithDefaults([feature], [web_server_stepper_1.default]); | ||
expect(result.ok).toBe(true); | ||
util_1.getStepper(steppers, web_server_stepper_1.WEBSERVER_STEPPER).close(); | ||
}); | ||
it("doesn't permit different static mount", async () => { | ||
const { result, steppers } = await TestSteps_1.testRun('/test/static-fails', [web_server_stepper_1.default], util_1.getDefaultWorld().world); | ||
const feature = { path: '/features/test.feature', content: `serve files from test\nserve files from fails\n` }; | ||
const { result } = await TestSteps_1.testWithDefaults([feature], [web_server_stepper_1.default]); | ||
expect(result.ok).toBe(false); | ||
util_1.getStepper(steppers, web_server_stepper_1.WEBSERVER_STEPPER).close(); | ||
}); | ||
}); | ||
//# sourceMappingURL=web-server-stepper.test.js.map |
{ | ||
"name": "@haibun/web-server-express", | ||
"version": "0.2.1", | ||
"version": "1.0.0", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "main": "build/web-server-stepper.js", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
24791
21
290
1