@lytical/app 1.0.0

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.
package/README.md ADDED
@@ -0,0 +1,233 @@
1
+ # @lytical/app
2
+
3
+ a typescript api server library built for your express project, with dependency injection support and auto router registration
4
+
5
+ ## Features
6
+
7
+ - router handler dependency injection
8
+ - auto `app.use()` router registration
9
+ - use middleware, only for routes that require it
10
+
11
+ ## Getting Started
12
+
13
+ after installing `@lytical/app` to your express project, configure your `tsconfig.json` file to enable decorators.
14
+
15
+ ```json
16
+ // tsconfig.json
17
+ {
18
+ "compilerOptions": {
19
+ "experimentalDecorators": true,
20
+ "emitDecoratorMetadata": true
21
+ }
22
+ }
23
+ ```
24
+
25
+ if this is a new project, we recommended installing `express@5.2..`, and the following project structure:
26
+
27
+ ```
28
+ project
29
+ |- dist
30
+ |- src
31
+ | |- middleware
32
+ | | |- my-middleware.ts
33
+ | | |- ...
34
+ | |- routes
35
+ | | |- my-route.ts
36
+ | | |- ...
37
+ | |- services
38
+ | | |- my-service.ts
39
+ | | |- ...
40
+ | |- index.ts
41
+ |- .gitignore
42
+ |- package.json
43
+ |- tsconfig.json
44
+ ```
45
+
46
+ for the above project structure:
47
+
48
+ - configure your `tsconfig.json` file.
49
+
50
+ ```json
51
+ // tsconfig.json
52
+ {
53
+ "compilerOptions": {
54
+ "rootDir": "src",
55
+ "outDir": "dist"
56
+ }
57
+ }
58
+ ```
59
+
60
+ - configure your `package.json` file to indicate where your routes are located.
61
+
62
+ ```json
63
+ // package.json
64
+ {
65
+ "main": "./{index.js,routes/**/*.js}"
66
+ }
67
+ ```
68
+
69
+ a simple project template can be found in github (https://....)
70
+
71
+ ## Usage
72
+
73
+ create your injectable service class(es) to implement the business logic.
74
+
75
+ ```typescript
76
+ import { ioc_injectable } from '@lytical/ioc';
77
+
78
+ @ioc_injectable()
79
+ // src/services/example-svc.ts
80
+ export class example_svc {
81
+ async get_message() {
82
+ return 'Hello from example_svc!';
83
+ }
84
+
85
+ async get_data() {
86
+ return { message: await this.get_message() };
87
+ }
88
+ }
89
+ ```
90
+
91
+ create your middleware classes
92
+
93
+ ```typescript
94
+ // src/middleware/example-mw.ts
95
+ import type { Request, Response, NextFunction } from 'express';
96
+
97
+ import { ioc_inject } from '@lytical/ioc';
98
+ import { example_svc } from '../services/example-svc';
99
+
100
+ /**
101
+ * Example middleware class
102
+ * Use for middleware that requires dependency injection
103
+ */
104
+ export class example_middleware_class {
105
+ // inject your service(es) into the middleware class constructor
106
+ constructor(
107
+ @ioc_inject(example_svc) private readonly _example_svc: example_svc,
108
+ ) {}
109
+
110
+ // all middleware classes must implement a default() route handler
111
+ async default(rqs: Request, rsp: Response, nxt: NextFunction) {
112
+ console.debug('example middleware invoked');
113
+ rsp.locals.example_middleware_data = await this._example_svc.get_data();
114
+ // make sure to call nxt() to continue the request processing pipeline
115
+ nxt();
116
+ }
117
+ }
118
+ ```
119
+
120
+ create your route handler(s)
121
+
122
+ ```typescript
123
+ // src/routes/example.ts
124
+ import express, {
125
+ type Request,
126
+ type Response,
127
+ type NextFunction,
128
+ } from 'express';
129
+
130
+ import {
131
+ app_middleware_dependency,
132
+ app_route,
133
+ app_route_handler,
134
+ } from '@lytical/app';
135
+
136
+ import { ioc_inject } from '@lytical/ioc';
137
+ import { example_svc } from '../services/example-svc';
138
+ import { example_middleware_class } from '../middleware/example-mw';
139
+
140
+ /**
141
+ * Example route class
142
+ * Use for router class(es) for auto app.use() registration for routes; dependent middleware; and dependency injection
143
+ */
144
+ @app_route({ route: '/example' })
145
+ export class example_route_class {
146
+ // inject your service(es) into the router class constructor
147
+ constructor(
148
+ @ioc_inject(example_svc) private readonly _example_svc: example_svc,
149
+ ) {}
150
+
151
+ // implement your handler methods
152
+ @app_route_handler({
153
+ route: '/', // /example/
154
+ http_method: ['GET'],
155
+ })
156
+ async get_handler(rqs: Request, rsp: Response, nxt: NextFunction) {
157
+ rsp.json({ message: await this._example_svc.get_message() }).end();
158
+ }
159
+
160
+ @app_route_handler({
161
+ http_method: ['POST'],
162
+ route: '/', // /example/
163
+ dependency: [
164
+ // use only the middleware needed
165
+ express.json(),
166
+ app_middleware_dependency(example_middleware_class),
167
+ ],
168
+ })
169
+ post_handler(rqs: Request, rsp: Response, nxt: NextFunction) {
170
+ rsp.json({ body: rqs.body, locals: rsp.locals }).end();
171
+ }
172
+ }
173
+ ```
174
+
175
+ now just import app and invoke `start()`
176
+
177
+ ```typescript
178
+ // src/index.ts
179
+ import app from '@lytical/app';
180
+
181
+ app.start();
182
+ ```
183
+
184
+ `app` emits a few life cycle events
185
+
186
+ ```typescript
187
+ // src/index.ts
188
+ import app, { app_evt } from './lib/app';
189
+
190
+ // app events occur in the following order:
191
+ // 1. create_server
192
+ // 2. server_starting
193
+ // 3. server_listening
194
+ // 4. server_started
195
+
196
+ app.once(app_evt.create_server, (cfg) => {
197
+ // modify (cfg) as needed, or remove this listener if not needed.
198
+ // for example, create a https server instead of http,
199
+ // and push async operations to fetch keys, to (cfg.wait_for).
200
+ // add middleware to (cfg.express), that applies to all routes, etc.
201
+ console.log(`the root route is (${cfg.root_route})`);
202
+ });
203
+
204
+ app.once(app_evt.server_starting, (cfg) => {
205
+ // modify (cfg) as needed, or remove this listener if not needed.
206
+ // add middleware to this application after auto registered routes are added.
207
+ // for example error handling middleware, etc.
208
+ // push async operations to fetch settings from a database, to (cfg.wait_for).
209
+ // this is the last to register dependencies in the ioc collection before the server starts.
210
+ console.log(`the hostname is (${cfg.hostname})`);
211
+ });
212
+
213
+ app.once(app_evt.server_listening, () => {
214
+ // remove this listener if not needed.
215
+ // use it to perform operations after the server starts listening.
216
+ // the ioc container is ready at this point.
217
+ });
218
+
219
+ app.once(app_evt.server_started, () => {
220
+ // remove this listener if not needed.
221
+ // use it to perform operations after the server has started.
222
+ });
223
+
224
+ app.start();
225
+ ```
226
+
227
+ ## Documentation
228
+
229
+ todo: working on this right now...
230
+
231
+ Stay tuned! I have more packages to come.`
232
+
233
+ _lytical(r) is a registered trademark of lytical, inc. all rights are reserved._
package/app.test.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=app.test.d.ts.map
package/app.test.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /* @preserve
3
+ (c) 2025 lytical, inc. all rights are reserved.
4
+ lytical(r) is a registered trademark of lytical, inc.
5
+ please refer to your license agreement on the use of this file.
6
+ */var __awaiter=this&&this.__awaiter||function(e,t,i,n){return new(i||(i=Promise))(function(a,r){function fulfilled(e){try{step(n.next(e))}catch(e){r(e)}}function rejected(e){try{step(n.throw(e))}catch(e){r(e)}}function step(e){var t;e.done?a(e.value):(t=e.value,t instanceof i?t:new i(function(e){e(t)})).then(fulfilled,rejected)}step((n=n.apply(e,t||[])).next())})},__importDefault=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(exports,"__esModule",{value:!0});const chai_1=require("chai"),mocha_1=require("mocha"),index_1=__importDefault(require("./index"));(0,mocha_1.describe)("an app",()=>{it("can be started",()=>__awaiter(void 0,void 0,void 0,function*(){(0,chai_1.expect)(index_1.default).exist}))});
package/index.d.ts ADDED
@@ -0,0 +1,134 @@
1
+ import { EventEmitter } from 'node:stream';
2
+ import { type Request, type RequestHandler, type Response, type NextFunction } from 'express';
3
+ import type { app_listening_cfg_t, app_server_cfg_t } from './types';
4
+ /** events emitted by the app */
5
+ export declare enum app_evt {
6
+ /**
7
+ * use to create or modify the server before it is started
8
+ *
9
+ * for example, create a https server instead of http,
10
+ * and push async operations to fetch keys, to (cfg.wait_for).
11
+ * add middleware to (cfg.express), that applies to all routes, etc.
12
+ */
13
+ create_server = "lyt-create-server",
14
+ /**
15
+ * use to modify the server listening configuration before it is started
16
+ *
17
+ * add middleware to this (cfg.express) after auto registered routes are added.
18
+ * for example error handling middleware, etc.
19
+ * push async operations to fetch settings from a database, to (cfg.wait_for).
20
+ * this is the last to register dependencies in the ioc collection before the server starts.
21
+ */
22
+ server_starting = "lyt-server-starting",
23
+ /**
24
+ * emitted when the server is listening
25
+ *
26
+ * use it to perform operations after the server starts listening.
27
+ * the ioc container is ready at this point.
28
+ */
29
+ server_listening = "lyt-server-listening",
30
+ /**
31
+ * emitted when the server has started
32
+ *
33
+ * use it to perform operations after the server has started.
34
+ */
35
+ server_started = "lyt-server-started"
36
+ }
37
+ /**
38
+ * app class
39
+ * @description
40
+ * the main app class
41
+ * @emits app_evt.create_server use to create or modify the server before it is started
42
+ * @emits app_evt.server_starting use to modify the server listening configuration before it is started
43
+ * @emits app_evt.server_listening emitted when the server is listening
44
+ * @emits app_evt.server_started emitted when the server has started
45
+ */
46
+ export declare class app extends EventEmitter {
47
+ once(event: app_evt.create_server, listener: (cfg: app_server_cfg_t) => void): this;
48
+ once(event: app_evt.server_listening, listener: () => void): this;
49
+ once(event: app_evt.server_starting, listener: (cfg: app_listening_cfg_t) => void): this;
50
+ once(event: app_evt.server_started, listener: () => void): this;
51
+ /**
52
+ * start the app
53
+ * @description
54
+ * starts the express app server
55
+ * app events occur in the following order:
56
+ * 1. create_server
57
+ * 2. server_starting
58
+ * 3. server_listening
59
+ * 4. server_started
60
+ */
61
+ start(): Promise<void>;
62
+ }
63
+ type cstor_t<_t_ = any> = new (...args: any[]) => _t_;
64
+ /**
65
+ * helper to create a route handler dependency from a middleware class constructor
66
+ * @param {app_route_middleware_t} cstor middleware class constructor
67
+ * @param {unknown[]} arg optional arguments to append to the middleware constructor
68
+ * @returns {app_route_handler_dependency_t} route handler dependency
69
+ */
70
+ export declare function app_middleware_dependency(cstor: cstor_t<app_route_middleware_t>, ...arg: unknown[]): app_route_handler_dependency_t;
71
+ /**
72
+ * app_route class decorator
73
+ * @description
74
+ * decorator to define a route class
75
+ * support for dependency injection in the constructor
76
+ * @param {app_route_info_t} route information
77
+ */
78
+ export declare function app_route({ route, arg }: app_route_info_t): (cstr: cstor_t) => cstor_t<any>;
79
+ /**
80
+ * app_route_handler method decorator
81
+ * @param {app_route_handler_info_t} arg route handler information
82
+ */
83
+ export declare function app_route_handler(arg: app_route_handler_info_t): (cstr: any, method_nm: string, pd: PropertyDescriptor) => PropertyDescriptor;
84
+ /**
85
+ * app_route_info_t
86
+ * @description
87
+ * route information for the app_route class decorator
88
+ */
89
+ export type app_route_info_t = {
90
+ /** the route path or pattern */
91
+ route: string | RegExp;
92
+ /** optional arguments to append to the route class constructor */
93
+ arg?: unknown[];
94
+ };
95
+ /**
96
+ * app_route_handler_dependency_t
97
+ * @description
98
+ * route handler dependency type
99
+ * can be a RequestHandler or a middleware class constructor with optional arguments
100
+ */
101
+ export type app_route_handler_dependency_t = RequestHandler | {
102
+ /** middleware class constructor */
103
+ middleware: cstor_t<app_route_middleware_t>;
104
+ /** optional arguments to append to the middleware constructor */
105
+ arg?: unknown[];
106
+ };
107
+ /**
108
+ * app_route_handler_info_t
109
+ * @description
110
+ * route handler information for the app_route_handler method decorator
111
+ */
112
+ export type app_route_handler_info_t = {
113
+ /** route handler dependencies */
114
+ dependency?: app_route_handler_dependency_t | app_route_handler_dependency_t[];
115
+ /** http method or methods */
116
+ http_method?: string | string[];
117
+ /** the route path or pattern */
118
+ route: string | RegExp;
119
+ };
120
+ /**
121
+ * app_route_middleware_t
122
+ * @description
123
+ * route middleware class type
124
+ * the class must have a default method that is a RequestHandler
125
+ * this method can be used as a middleware in the app_route_handler_info_t dependency property
126
+ * this method can also have dependencies injected
127
+ */
128
+ export interface app_route_middleware_t {
129
+ /** the default method of the middleware class */
130
+ default(rqs: Request, rsp: Response, nxt: NextFunction): void | Promise<void>;
131
+ }
132
+ declare const _default: app;
133
+ export default _default;
134
+ //# sourceMappingURL=index.d.ts.map
package/index.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /* @preserve
3
+ (c) 2025 lytical, inc. all rights are reserved.
4
+ lytical(r) is a registered trademark of lytical, inc.
5
+ please refer to your license agreement on the use of this file.
6
+ */var __createBinding=this&&this.__createBinding||(Object.create?function(e,t,r,o){void 0===o&&(o=r);var n=Object.getOwnPropertyDescriptor(t,r);n&&!("get"in n?!t.__esModule:n.writable||n.configurable)||(n={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,o,n)}:function(e,t,r,o){void 0===o&&(o=r),e[o]=t[r]}),__setModuleDefault=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),__importStar=this&&this.__importStar||function(){var ownKeys=function(e){return ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[t.length]=r);return t},ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r=ownKeys(e),o=0;o<r.length;o++)"default"!==r[o]&&__createBinding(t,e,r[o]);return __setModuleDefault(t,e),t}}(),__awaiter=this&&this.__awaiter||function(e,t,r,o){return new(r||(r=Promise))(function(n,s){function fulfilled(e){try{step(o.next(e))}catch(e){s(e)}}function rejected(e){try{step(o.throw(e))}catch(e){s(e)}}function step(e){var t;e.done?n(e.value):(t=e.value,t instanceof r?t:new r(function(e){e(t)})).then(fulfilled,rejected)}step((o=o.apply(e,t||[])).next())})},__asyncValues=this&&this.__asyncValues||function(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t,r=e[Symbol.asyncIterator];return r?r.call(e):(e="function"==typeof __values?__values(e):e[Symbol.iterator](),t={},verb("next"),verb("throw"),verb("return"),t[Symbol.asyncIterator]=function(){return this},t);function verb(r){t[r]=e[r]&&function(t){return new Promise(function(o,n){(function(e,t,r,o){Promise.resolve(o).then(function(t){e({value:t,done:r})},t)})(o,n,(t=e[r](t)).done,t.value)})}}},__importDefault=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.app=exports.app_evt=void 0,exports.app_middleware_dependency=app_middleware_dependency,exports.app_route=app_route,exports.app_route_handler=app_route_handler;const node_http_1=require("node:http"),node_stream_1=require("node:stream"),promises_1=require("node:fs/promises"),node_path_1=require("node:path"),express_1=__importDefault(require("express")),find_root_1=__importDefault(require("find-root")),ioc_1=require("@lytical/ioc"),collection_1=__importDefault(require("@lytical/ioc/collection"));var app_evt;!function(e){e.create_server="lyt-create-server",e.server_starting="lyt-server-starting",e.server_listening="lyt-server-listening",e.server_started="lyt-server-started"}(app_evt||(exports.app_evt=app_evt={}));const _app=(0,express_1.default)(),_root_route=express_1.default.Router({mergeParams:!0});class app extends node_stream_1.EventEmitter{once(e,t){return super.once(e,t)}start(){return __awaiter(this,void 0,void 0,function*(){var e,t;const r={express:_app,root_route:"/api",wait_for:[]};r.express.use((e,t,r)=>{t.set("X-Powered-By","powered by lytical(r) enterprise solutions, and express"),t.set("X-Lyt-Version","1.0.0"),r()}),console.log("[@lytical/ts-express] creating http server..."),this.emit(app_evt.create_server,r),r.wait_for.length&&(yield Promise.all(r.wait_for)),_app.use(null!==(e=r.root_route)&&void 0!==e?e:"/api",_root_route);const o=null!==(t=r.server)&&void 0!==t?t:(0,node_http_1.createServer)(r.express);yield _register_routes();const n={express:r.express,hostname:process.env.HOSTNAME||"localhost",port:process.env.PORT?parseInt(process.env.PORT,10):3e3,server:o,wait_for:[]};this.emit(app_evt.server_starting,n),n.wait_for.length&&(yield Promise.all(n.wait_for)),yield collection_1.default.create_container(),o.listen(n.port,n.hostname,n.backlog,()=>{this.emit(app_evt.server_listening),console.log(`[@lytical/ts-express] server started on port ${n.port}; hostname ${n.hostname}`)}),this.emit(app_evt.server_started)})}}function _register_routes(){return __awaiter(this,void 0,void 0,function*(){var e,t,r,o,n;const{main:s}=null!==(n=yield Promise.resolve(`${(0,node_path_1.join)((0,find_root_1.default)(__dirname),"package.json")}`).then(e=>__importStar(require(e))))&&void 0!==n?n:{};if(s){const n=yield(0,promises_1.glob)(s),c=process.cwd();try{for(var i,a=!0,_=__asyncValues(n);!(e=(i=yield _.next()).done);a=!0){o=i.value,a=!1;const e=o;console.log(`[@lytical/ts-express] registering routes in module (${e})...`),yield Promise.resolve(`${(0,node_path_1.join)(c,e)}`).then(e=>__importStar(require(e)))}}catch(e){t={error:e}}finally{try{a||e||!(r=_.return)||(yield r.call(_))}finally{if(t)throw t.error}}}})}exports.app=app;const route_handler_method=Symbol("lyt-app-api-route-handler-method");function app_middleware_dependency(e,...t){return{middleware:e,arg:t}}function app_route({route:e,arg:t}){const r=e;return o=>{var n;const s=express_1.default.Router({mergeParams:!0}),i=null!==(n=o.prototype[route_handler_method])&&void 0!==n?n:{};for(const e of Object.keys(i)){const{route:n,dependency:a,http_method:_}=i[e];if(a.length||_.length>1){const i=express_1.default.Router({mergeParams:!0}),c=[];for(let e of a){if("function"==typeof e){i.use(e),c.push(e.name||"anonymous-middleware");continue}const{middleware:t,arg:r}=e;i.use((e,o,n)=>(0,ioc_1.ioc_create_instance)(t,...null!=r?r:[]).default(e,o,n)),c.push(t.name||"anonymous-middleware")}for(const r of _)i[r.toLowerCase()]?i[r.toLowerCase()](n,(r,n,s)=>{const i=(0,ioc_1.ioc_create_instance)(o,...null!=t?t:[]);(0,ioc_1.ioc_invoke_method)(i[e],i,r,n,s)}):i.use(n,(n,s,i)=>{if(r.toUpperCase()!==n.method)return i();const a=(0,ioc_1.ioc_create_instance)(o,...null!=t?t:[]);(0,ioc_1.ioc_invoke_method)(a[e],a,n,s,i)});console.debug(`[@lytical/ts-express] registered (${_}:${r}${n}) route handler (${o.name}.${e}) with dependencies (${c})`),s.use(i);continue}const[c]=_;c?(s[c.toLowerCase()]?s[c.toLowerCase()](n,(r,n,s)=>{const i=(0,ioc_1.ioc_create_instance)(o,...null!=t?t:[]);(0,ioc_1.ioc_invoke_method)(i[e],i,r,n,s)}):s.use(n,(r,n,s)=>{if(c.toUpperCase()!==r.method)return s();const i=(0,ioc_1.ioc_create_instance)(o,...null!=t?t:[]);(0,ioc_1.ioc_invoke_method)(i[e],i,r,n,s)}),console.debug(`[@lytical/ts-express] registered (${c}:${r}${n}) route handler (${o.name}.${e})`)):(s.use(n,(r,n,s)=>{const i=(0,ioc_1.ioc_create_instance)(o,...null!=t?t:[]);(0,ioc_1.ioc_invoke_method)(i[e],i,r,n,s)}),console.debug(`[@lytical/ts-express] registered (ALL-METHODS:${r}${n}) route handler (${o.name}.${e})`))}return _root_route.use(e,s),o}}function app_route_handler(e){return(t,r,o)=>{var n;switch(e.dependency?Array.isArray(e.dependency)||(e.dependency=[e.dependency]):e.dependency=[],typeof e.http_method){case"undefined":e.http_method=[];break;case"string":e.http_method=[e.http_method]}const s=null!==(n=t[route_handler_method])&&void 0!==n?n:{};return s[r]=e,t[route_handler_method]=s,o}}exports.default=new app;
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@lytical/app",
3
+ "version": "1.0.0",
4
+ "description": "a typescript api server library built for your express project, with dependency injection support and auto router registration",
5
+ "main": "index.js",
6
+ "private": false,
7
+ "scripts": {
8
+ "build": "tsc --build",
9
+ "publish": "npm run clean&&npm run build&&gulp post_build&&cd ./dist&&npm publish --access public",
10
+ "clean": "rimraf ./dist",
11
+ "rebuild": "npm run clean&&npm install&&npm run build",
12
+ "test": "npm run clean&&npm run build&&mocha --recursive ./dist/**/*.test.js"
13
+ },
14
+ "keywords": [
15
+ "ioc",
16
+ "express",
17
+ "app",
18
+ "server",
19
+ "dependency-injection",
20
+ "auto-routing",
21
+ "lytical",
22
+ "node",
23
+ "typescript"
24
+ ],
25
+ "author": {
26
+ "email": "barry.hayles@lytical.com",
27
+ "name": "Barry Hayles",
28
+ "url": "https://www.lytical.com"
29
+ },
30
+ "repository": {
31
+ "type": "github",
32
+ "url": "git+https://github.com/lytical/app.git"
33
+ },
34
+ "license": "ISC",
35
+ "peerDependencies": {
36
+ "@lytical/ioc": "^1.0.0",
37
+ "express": "^5.2.1"
38
+ },
39
+ "devDependencies": {
40
+ "@types/chai": "^5.2.3",
41
+ "@types/express": "^5.0.6",
42
+ "@types/find-root": "^1.1.4",
43
+ "@types/mocha": "^10.0.10",
44
+ "@types/node": "^25.0.9",
45
+ "chai": "^6.2.2",
46
+ "gulp": "^5.0.1",
47
+ "gulp-clean": "^0.4.0",
48
+ "gulp-uglify-es": "^3.0.0",
49
+ "mocha": "^11.7.5",
50
+ "pump": "^3.0.3",
51
+ "rimraf": "^6.1.2",
52
+ "typescript": "^5.9.3"
53
+ },
54
+ "dependencies": {
55
+ "find-root": "^1.1.0"
56
+ }
57
+ }
package/types.d.ts ADDED
@@ -0,0 +1,94 @@
1
+ /* @preserve
2
+ (c) 2025 lytical, inc. all rights are reserved.
3
+ lytical(r) is a registered trademark of lytical, inc.
4
+ please refer to your license agreement on the use of this file.
5
+ */
6
+
7
+ import type { Server } from 'node:net';
8
+ import type { Application } from 'express';
9
+
10
+ /**
11
+ * server configuration type
12
+ * @description
13
+ * the configuration used when creating or modifying the server before it is started.
14
+ */
15
+ export type app_server_cfg_t = {
16
+ /**
17
+ * the express application instance
18
+ * @description
19
+ * the express application instance that will be used to create the server
20
+ * add any middleware to this application before auto registered routes are added.
21
+ */
22
+ express: Application;
23
+
24
+ /**
25
+ * the root route
26
+ * @description
27
+ * override and provide the root route to be used. if not provided, the default '/api' route will be used.
28
+ */
29
+ root_route: string;
30
+
31
+ /**
32
+ * the server instance
33
+ * @description
34
+ * provide the server instance to be used. if not provided, a default http server will be created.
35
+ */
36
+ server?: Server;
37
+
38
+ /**
39
+ * wait_for
40
+ * @description
41
+ * can be used to delay until some asynchronous operation is complete.
42
+ */
43
+ wait_for: Promise<any>[];
44
+ };
45
+
46
+ /**
47
+ * listening configuration type
48
+ * @description
49
+ * the configuration used when starting the server listening.
50
+ */
51
+ export type app_listening_cfg_t = {
52
+ /**
53
+ * the maximum length of the queue of pending connections
54
+ * @description
55
+ * provide the maximum length of the queue of pending connections. the default is 511 (node.js default).
56
+ */
57
+ backlog?: number;
58
+
59
+ /**
60
+ * the express application instance
61
+ * @description
62
+ * add any middleware to this application after auto registered routes are added.
63
+ */
64
+ express: Application;
65
+
66
+ /**
67
+ * the hostname to listen on
68
+ * @description
69
+ * provide the hostname to listen on. if not provided, the server will listen on all available interfaces.
70
+ */
71
+ hostname?: string;
72
+
73
+ /**
74
+ * the port to listen on
75
+ * @description
76
+ * provide the port to listen on. if not provided, the server will listen on port process.env.PORT or 3000.
77
+ */
78
+ port?: number;
79
+
80
+ /**
81
+ * the server instance
82
+ * @description
83
+ * the server instance that will be used.
84
+ * use to add listeners before the server is started.
85
+ */
86
+ server: Server;
87
+
88
+ /**
89
+ * wait_for
90
+ * @description
91
+ * can be used to delay until some asynchronous operation is complete.
92
+ * */
93
+ wait_for: Promise<any>[];
94
+ };