@haibun/web-server-express 1.26.1 → 1.26.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,15 @@
1
+ export declare const WEBSERVER = "webserver";
2
+ export declare const CHECK_LISTENER = "CHECK_LISTENER";
3
+ import * as express from 'express';
4
+ export interface IWebServer {
5
+ addStaticFolder(subdir: string, loc: string): void;
6
+ addKnownStaticFolder(subdir: string, mountAt?: string): void;
7
+ listen(): Promise<unknown>;
8
+ close(): Promise<void>;
9
+ addRoute(type: TRouteTypes, path: string, route: TRequestHandler): void;
10
+ use(middleware: express.RequestHandler): void;
11
+ }
12
+ export type TRouteTypes = 'get' | 'post';
13
+ export type IRequest = typeof express.request;
14
+ export type IResponse = typeof express.response;
15
+ export type TRequestHandler = (req: IRequest, res: IResponse) => void;
package/build/defs.js ADDED
@@ -0,0 +1,3 @@
1
+ export const WEBSERVER = 'webserver';
2
+ export const CHECK_LISTENER = 'CHECK_LISTENER';
3
+ //# sourceMappingURL=defs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defs.js","sourceRoot":"","sources":["../src/defs.ts"],"names":[],"mappings":"AACA,MAAM,CAAC,MAAM,SAAS,GAAG,WAAW,CAAC;AACrC,MAAM,CAAC,MAAM,cAAc,GAAG,gBAAgB,CAAC"}
@@ -0,0 +1,28 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ import http from 'http';
3
+ import { RequestHandler } from 'express';
4
+ import { IWebServer, TRouteTypes } from './defs.js';
5
+ import { ILogger } from '@haibun/core/build/lib/interfaces/logger.js';
6
+ export declare const DEFAULT_PORT = 8123;
7
+ export declare class ServerExpress implements IWebServer {
8
+ logger: ILogger;
9
+ static listening: boolean;
10
+ listener?: http.Server;
11
+ app: import("express-serve-static-core").Express;
12
+ static mounted: {
13
+ get: {};
14
+ post: {};
15
+ };
16
+ base: string;
17
+ port: number;
18
+ constructor(logger: ILogger, base: string, port?: number);
19
+ use(middleware: RequestHandler): void;
20
+ listen(): Promise<unknown>;
21
+ addRoute(type: TRouteTypes, path: string, route: RequestHandler): void;
22
+ private addMounted;
23
+ addStaticFolder(relativeFolder: string, mountAt?: string): void;
24
+ addKnownStaticFolder(folder: string, mountAt?: string): void;
25
+ private doAddStaticFolder;
26
+ checkMountBadOrMounted(type: string, loc: string, what: string): void;
27
+ close(): Promise<void>;
28
+ }
@@ -0,0 +1,99 @@
1
+ import { statSync, existsSync } from 'fs';
2
+ import express from 'express';
3
+ import cookieParser from 'cookie-parser';
4
+ export const DEFAULT_PORT = 8123;
5
+ export class ServerExpress {
6
+ logger;
7
+ static listening = false;
8
+ listener;
9
+ app = express();
10
+ static mounted = { get: {}, post: {} };
11
+ base;
12
+ port;
13
+ constructor(logger, base, port = DEFAULT_PORT) {
14
+ this.logger = logger;
15
+ this.base = base;
16
+ this.port = port;
17
+ this.app.use(cookieParser());
18
+ this.app.use(express.json({ limit: '50mb' }));
19
+ }
20
+ use(middleware) {
21
+ this.app.use(middleware);
22
+ }
23
+ listen() {
24
+ return new Promise((resolve, reject) => {
25
+ if (!ServerExpress.listening) {
26
+ try {
27
+ this.listener = this.app.listen(this.port, () => {
28
+ this.logger.log(`Server listening on port: ${this.port}`);
29
+ ServerExpress.listening = true;
30
+ this.logger.log('express listening');
31
+ resolve('started');
32
+ });
33
+ }
34
+ catch (e) {
35
+ console.error(e);
36
+ reject(e);
37
+ }
38
+ }
39
+ else {
40
+ this.logger.log('express already listening');
41
+ resolve('already listening');
42
+ }
43
+ });
44
+ }
45
+ addRoute(type, path, route) {
46
+ if (type !== 'get' && type !== 'post') {
47
+ throw Error(`invalid route type ${type}`);
48
+ }
49
+ this.checkMountBadOrMounted(type, path, route.toString());
50
+ this.logger.log(`adding ${type} route from ${path}`);
51
+ this.app[type](path, route);
52
+ this.addMounted(type, path, route.toString());
53
+ }
54
+ async addMounted(type, path, what) {
55
+ ServerExpress.mounted[type][path] = what;
56
+ if (!this.listener) {
57
+ await this.listen();
58
+ }
59
+ }
60
+ // add a static folder restricted to relative paths from files
61
+ addStaticFolder(relativeFolder, mountAt = '/') {
62
+ const folder = [this.base, relativeFolder].join('/');
63
+ this.doAddStaticFolder(folder, mountAt);
64
+ }
65
+ // add a static folder at any path
66
+ addKnownStaticFolder(folder, mountAt = '/') {
67
+ this.doAddStaticFolder(folder, mountAt);
68
+ }
69
+ doAddStaticFolder(folder, mountAt = '/') {
70
+ this.checkMountBadOrMounted('get', mountAt, folder);
71
+ if (!existsSync(folder)) {
72
+ throw Error(`"${folder}" doesn't exist`);
73
+ }
74
+ const stat = statSync(folder);
75
+ if (!stat.isDirectory()) {
76
+ throw Error(`"${folder}" is not a directory`);
77
+ }
78
+ this.app.use(mountAt, express.static(folder));
79
+ this.addMounted('get', mountAt, folder);
80
+ this.logger.info(`serving files from ${folder} at ${mountAt}`);
81
+ return;
82
+ }
83
+ checkMountBadOrMounted(type, loc, what) {
84
+ if (loc !== loc.replace(/[^a-zA-Z-0-9/-_]/g, '')) {
85
+ throw Error(`mount folder ${loc} has illegal characters`);
86
+ }
87
+ const alreadyMounted = ServerExpress.mounted[type][loc] || Object.keys(ServerExpress.mounted[type]).find((m) => m.startsWith(`${loc}/`));
88
+ if (alreadyMounted) {
89
+ throw Error(`cannot mount ${type} ${what} at ${loc}, ${alreadyMounted} is already mounted}`);
90
+ }
91
+ }
92
+ async close() {
93
+ this.logger.info('closing server');
94
+ this.listener?.close();
95
+ ServerExpress.mounted = { get: {}, post: {} };
96
+ ServerExpress.listening = false;
97
+ }
98
+ }
99
+ //# sourceMappingURL=server-express.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-express.js","sourceRoot":"","sources":["../src/server-express.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,17 @@
1
+ import { ServerExpress } from "./server-express.js";
2
+ import TestLogger from '@haibun/core/build/lib/TestLogger.js';
3
+ describe('mounts', () => {
4
+ it('mounts a route', () => {
5
+ const tl = new TestLogger();
6
+ const se = new ServerExpress(tl, '/', 8999);
7
+ se.listen = async () => 'started';
8
+ expect(() => se.addRoute('get', '/', () => undefined)).not.toThrow();
9
+ });
10
+ it('fails to double mount a route', () => {
11
+ const tl = new TestLogger();
12
+ const se = new ServerExpress(tl, '/', 8999);
13
+ se.listen = async () => 'started';
14
+ expect(() => se.addRoute('get', '/', () => undefined)).toThrow();
15
+ });
16
+ });
17
+ //# sourceMappingURL=server-express.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-express.test.js","sourceRoot":"","sources":["../src/server-express.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,UAAU,MAAM,sCAAsC,CAAC;AAE9D,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE;IACpB,EAAE,CAAC,gBAAgB,EAAE,GAAG,EAAE;QACtB,MAAM,EAAE,GAAG,IAAI,UAAU,EAAE,CAAC;QAC5B,MAAM,EAAE,GAAG,IAAI,aAAa,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QAC5C,EAAE,CAAC,MAAM,GAAG,KAAK,IAAI,EAAE,CAAC,SAAS,CAAC;QAClC,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IACzE,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACrC,MAAM,EAAE,GAAG,IAAI,UAAU,EAAE,CAAC;QAC5B,MAAM,EAAE,GAAG,IAAI,aAAa,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QAC5C,EAAE,CAAC,MAAM,GAAG,KAAK,IAAI,EAAE,CAAC,SAAS,CAAC;QAClC,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;IACrE,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,35 @@
1
+ import WebHttp from '@haibun/web-http/build/web-http.js';
2
+ import { actionOK, getFromRuntime, getStepperOptionName } from '@haibun/core/build/lib/util/index.js';
3
+ import { DEFAULT_DEST } from '@haibun/core/build/lib/defs.js';
4
+ import { WEBSERVER } from './defs.js';
5
+ import Server from './web-server-stepper.js';
6
+ import { AStepper } from '@haibun/core/build/lib/defs.js';
7
+ import { testWithDefaults } from '@haibun/core/build/lib/test/lib.js';
8
+ import WebServerStepper from './web-server-stepper.js';
9
+ describe('route mount', () => {
10
+ it.skip('mounts a route', async () => {
11
+ const TestRoute = class TestRoute extends AStepper {
12
+ steps = {
13
+ addRoute: {
14
+ gwta: 'serve test route to {loc}',
15
+ action: async ({ loc }) => {
16
+ const route = (req, res) => res.status(200).send('ok');
17
+ const webserver = await getFromRuntime(this.getWorld().runtime, WEBSERVER);
18
+ await webserver.addRoute('get', loc, route);
19
+ return actionOK();
20
+ },
21
+ },
22
+ };
23
+ };
24
+ const wss = new WebServerStepper();
25
+ const feature = { path: '/features/test.feature', content: `serve test route to /test\nwebserver is listening\nfetch from http://localhost:8124/test is "ok"` };
26
+ const result = await testWithDefaults([feature], [Server, TestRoute, WebHttp], {
27
+ options: { DEST: DEFAULT_DEST, },
28
+ extraOptions: {
29
+ [getStepperOptionName(wss, 'PORT')]: '8124',
30
+ },
31
+ });
32
+ expect(result.ok).toBe(true);
33
+ });
34
+ });
35
+ //# sourceMappingURL=web-server-stepper-route.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-server-stepper-route.test.js","sourceRoot":"","sources":["../src/web-server-stepper-route.test.ts"],"names":[],"mappings":"AACA,OAAO,OAAO,MAAM,oCAAoC,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AACtG,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAmC,SAAS,EAAE,MAAM,WAAW,CAAC;AAEvE,OAAO,MAAM,MAAM,yBAAyB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAU,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACtE,OAAO,gBAAgB,MAAM,yBAAyB,CAAC;AAEvD,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,KAAK,IAAI,EAAE;QACnC,MAAM,SAAS,GAAG,MAAM,SAAU,SAAQ,QAAQ;YAChD,KAAK,GAAG;gBACN,QAAQ,EAAE;oBACR,IAAI,EAAE,2BAA2B;oBACjC,MAAM,EAAE,KAAK,EAAE,EAAE,GAAG,EAAU,EAAE,EAAE;wBAChC,MAAM,KAAK,GAAG,CAAC,GAAa,EAAE,GAAc,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;wBAC5E,MAAM,SAAS,GAAe,MAAM,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;wBACvF,MAAM,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;wBAC5C,OAAO,QAAQ,EAAE,CAAC;oBACpB,CAAC;iBACF;aACF,CAAC;SACH,CAAC;QACF,MAAM,GAAG,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,EAAE,IAAI,EAAE,wBAAwB,EAAE,OAAO,EAAE,kGAAkG,EAAE,CAAC;QAChK,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE;YAC7E,OAAO,EAAE,EAAE,IAAI,EAAE,YAAY,GAAG;YAChC,YAAY,EAAE;gBACZ,CAAC,oBAAoB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,EAAE,MAAM;aAC5C;SACF,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,59 @@
1
+ import { TWorld, TNamed, TOptions, AStepper, TVStep } from '@haibun/core/build/lib/defs.js';
2
+ import { IWebServer } from './defs.js';
3
+ import { ServerExpress } from './server-express.js';
4
+ declare const WebServerStepper: {
5
+ new (): {
6
+ webserver: ServerExpress | undefined;
7
+ options: {
8
+ PORT: {
9
+ desc: string;
10
+ parse: (port: string) => {
11
+ error: string;
12
+ result?: undefined;
13
+ } | {
14
+ result: number;
15
+ error?: undefined;
16
+ };
17
+ };
18
+ };
19
+ setWorld(world: TWorld, steppers: AStepper[]): void;
20
+ close(): Promise<void>;
21
+ steps: {
22
+ thisURI: {
23
+ gwta: string;
24
+ action: ({ where }: TNamed, vstep: TVStep) => Promise<import("@haibun/core/build/lib/defs.js").TOKActionResult>;
25
+ };
26
+ webpage: {
27
+ gwta: string;
28
+ action: ({ name, location }: TNamed, vsteps: TVStep) => Promise<import("@haibun/core/build/lib/defs.js").TOKActionResult>;
29
+ };
30
+ isListening: {
31
+ gwta: string;
32
+ action: () => Promise<import("@haibun/core/build/lib/defs.js").TOKActionResult>;
33
+ };
34
+ showMounts: {
35
+ gwta: string;
36
+ action: () => Promise<import("@haibun/core/build/lib/defs.js").TOKActionResult>;
37
+ };
38
+ serveFilesAt: {
39
+ gwta: string;
40
+ action: ({ where, loc }: TNamed) => Promise<import("@haibun/core/build/lib/defs.js").TOKActionResult | import("@haibun/core/build/lib/defs.js").TNotOKActionResult>;
41
+ };
42
+ serveFiles: {
43
+ gwta: string;
44
+ action: ({ loc }: TNamed) => Promise<import("@haibun/core/build/lib/defs.js").TOKActionResult | import("@haibun/core/build/lib/defs.js").TNotOKActionResult>;
45
+ };
46
+ };
47
+ doServeFiles(where: any, loc: any): import("@haibun/core/build/lib/defs.js").TOKActionResult | import("@haibun/core/build/lib/defs.js").TNotOKActionResult;
48
+ world?: TWorld;
49
+ endFeature?(): void;
50
+ onFailure?(result: import("@haibun/core/build/lib/defs.js").TStepResult): void;
51
+ getWorld(): TWorld;
52
+ };
53
+ };
54
+ export default WebServerStepper;
55
+ export type ICheckListener = (options: TOptions, webserver: IWebServer) => void;
56
+ export interface IWebServerStepper {
57
+ webserver: IWebServer;
58
+ close: () => void;
59
+ }
@@ -0,0 +1,112 @@
1
+ import { OK, AStepper } from '@haibun/core/build/lib/defs.js';
2
+ import { actionNotOK, getFromRuntime, getStepperOption, intOrError } from '@haibun/core/build/lib/util/index.js';
3
+ import { WEBSERVER, } from './defs.js';
4
+ import { ServerExpress, DEFAULT_PORT } from './server-express.js';
5
+ import { WEB_PAGE } from '@haibun/domain-webpage/build/domain-webpage.js';
6
+ const WebServerStepper = class WebServerStepper extends AStepper {
7
+ webserver;
8
+ options = {
9
+ PORT: {
10
+ desc: `change web server port from ${DEFAULT_PORT}`,
11
+ parse: (port) => intOrError(port)
12
+ },
13
+ };
14
+ setWorld(world, steppers) {
15
+ super.setWorld(world, steppers);
16
+ // this.world.runtime[CHECK_LISTENER] = WebServerStepper.checkListener;
17
+ const port = parseInt(getStepperOption(this, 'PORT', world.extraOptions)) || DEFAULT_PORT;
18
+ this.webserver = new ServerExpress(world.logger, [process.cwd(), 'files'].join('/'), port);
19
+ world.runtime[WEBSERVER] = this.webserver;
20
+ }
21
+ async close() {
22
+ await this.webserver?.close();
23
+ }
24
+ steps = {
25
+ thisURI: {
26
+ gwta: `a ${WEB_PAGE} at {where}`,
27
+ action: async ({ where }, vstep) => {
28
+ const page = vstep.source.name;
29
+ const webserver = getFromRuntime(this.getWorld().runtime, WEBSERVER);
30
+ webserver.addStaticFolder(page, where);
31
+ console.debug('added page', page);
32
+ return OK;
33
+ },
34
+ },
35
+ /// generator
36
+ webpage: {
37
+ gwta: `A ${WEB_PAGE} {name} hosted at {location}`,
38
+ action: async ({ name, location }, vsteps) => {
39
+ const page = vsteps.source.name;
40
+ const webserver = getFromRuntime(this.getWorld().runtime, WEBSERVER);
41
+ // TODO mount the page
42
+ return OK;
43
+ },
44
+ /*
45
+ build: async ({ location }: TNamed, { source }: TVStep, workspace: WorkspaceContext) => {
46
+ if (location !== location.replace(/[^a-zA-Z-0-9.]/g, '')) {
47
+ throw Error(`${WEB_PAGE} location ${location} has illegal characters`);
48
+ }
49
+ const subdir = this.getWorld().shared.get('file_location');
50
+ if (!subdir) {
51
+ throw Error(`must declare a file_location`);
52
+ }
53
+ const folder = `files/${subdir}`;
54
+ workspace.addBuilder(new WebPageBuilder(source.name, this.getWorld().logger, location, folder));
55
+ return { ...OK, finalize: this.finalize };
56
+ },
57
+ */
58
+ },
59
+ isListening: {
60
+ gwta: 'webserver is listening',
61
+ action: async () => {
62
+ await this.webserver.listen();
63
+ return OK;
64
+ },
65
+ },
66
+ showMounts: {
67
+ gwta: 'show mounts',
68
+ action: async () => {
69
+ const mounts = ServerExpress.mounted;
70
+ this.getWorld().logger.info(`mounts: ${JSON.stringify(mounts)}`);
71
+ return OK;
72
+ },
73
+ },
74
+ serveFilesAt: {
75
+ gwta: 'serve files at {where} from {loc}',
76
+ action: async ({ where, loc }) => {
77
+ return this.doServeFiles(where, loc);
78
+ },
79
+ /*
80
+ build: async ({ loc }: TNamed) => {
81
+ this.getWorld().shared.set('file_location', loc);
82
+ return OK;
83
+ }
84
+ */
85
+ },
86
+ serveFiles: {
87
+ gwta: 'serve files from {loc}',
88
+ action: async ({ loc }) => {
89
+ return this.doServeFiles('/', loc);
90
+ },
91
+ /*
92
+ build: async ({ loc }: TNamed) => {
93
+ this.getWorld().shared.set('file_location', loc);
94
+ return OK;
95
+ }
96
+ */
97
+ },
98
+ };
99
+ doServeFiles(where, loc) {
100
+ const ws = getFromRuntime(this.getWorld().runtime, WEBSERVER);
101
+ try {
102
+ ws.addStaticFolder(loc, where);
103
+ this.getWorld().shared.set('file_location', loc);
104
+ return OK;
105
+ }
106
+ catch (error) {
107
+ return actionNotOK(error);
108
+ }
109
+ }
110
+ };
111
+ export default WebServerStepper;
112
+ //# sourceMappingURL=web-server-stepper.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@haibun/web-server-express",
3
3
  "type": "module",
4
- "version": "1.26.1",
4
+ "version": "1.26.2",
5
5
  "description": "",
6
6
  "main": "build/web-server-stepper.js",
7
7
  "files": [
@@ -31,4 +31,4 @@
31
31
  "@types/express": "^4.17.15"
32
32
  },
33
33
  "gitHead": "7cf9680bd922fb622fb59f1e6bf5b65284cb8fd5"
34
- }
34
+ }