@flancer32/teq-web 0.3.1 → 0.5.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.
Files changed (70) hide show
  1. package/CHANGELOG.md +26 -1
  2. package/README.md +236 -127
  3. package/ai/AGENTS.md +36 -0
  4. package/ai/abstractions.md +75 -0
  5. package/ai/examples/minimal-server.md +78 -0
  6. package/ai/overview.md +27 -0
  7. package/ai/rules.md +41 -0
  8. package/package.json +43 -28
  9. package/src/Back/Api/Handler.mjs +26 -0
  10. package/src/Back/{Defaults.js → Defaults.mjs} +6 -1
  11. package/src/Back/Dto/Info.mjs +66 -0
  12. package/src/Back/Dto/{Handler/Source.js → Source.mjs} +26 -23
  13. package/src/Back/Enum/Server/Type.mjs +13 -0
  14. package/src/Back/Enum/Stage.mjs +13 -0
  15. package/src/Back/Handler/Pre/Log.mjs +59 -0
  16. package/src/Back/Handler/Static/A/{Config.js → Config.mjs} +14 -3
  17. package/src/Back/Handler/Static/A/{Fallback.js → Fallback.mjs} +16 -4
  18. package/src/Back/Handler/Static/A/{FileService.js → FileService.mjs} +31 -14
  19. package/src/Back/Handler/Static/A/{Registry.js → Registry.mjs} +18 -6
  20. package/src/Back/Handler/Static/A/{Resolver.js → Resolver.mjs} +13 -2
  21. package/src/Back/Handler/Static.mjs +83 -0
  22. package/src/Back/Helper/Cast.mjs +116 -0
  23. package/src/Back/Helper/{Mime.js → Mime.mjs} +2 -0
  24. package/src/Back/Helper/Order/Kahn.mjs +69 -0
  25. package/src/Back/Helper/{Respond.js → Respond.mjs} +14 -3
  26. package/src/Back/Logger.mjs +57 -0
  27. package/src/Back/PipelineEngine.mjs +228 -0
  28. package/src/Back/Server/Config/{Tls.js → Tls.mjs} +35 -33
  29. package/src/Back/Server/Config.mjs +69 -0
  30. package/src/Back/{Server.js → Server.mjs} +35 -24
  31. package/types.d.ts +30 -0
  32. package/.github/workflows/npm-publish.yml +0 -48
  33. package/AGENTS.md +0 -101
  34. package/eslint.config.js +0 -37
  35. package/src/AGENTS.md +0 -108
  36. package/src/Back/Api/Handler.js +0 -26
  37. package/src/Back/Dispatcher.js +0 -115
  38. package/src/Back/Dto/Handler/Info.js +0 -68
  39. package/src/Back/Enum/Server/Type.js +0 -12
  40. package/src/Back/Enum/Stage.js +0 -10
  41. package/src/Back/Handler/Pre/Log.js +0 -45
  42. package/src/Back/Handler/Static.js +0 -63
  43. package/src/Back/Helper/Cast.js +0 -114
  44. package/src/Back/Helper/Order/Kahn.js +0 -66
  45. package/src/Back/Logger.js +0 -53
  46. package/src/Back/Server/Config.js +0 -69
  47. package/teqfw.json +0 -8
  48. package/test/accept/ExternalServer.test.mjs +0 -66
  49. package/test/accept/Server.test.mjs +0 -203
  50. package/test/certs/ca.pem +0 -19
  51. package/test/certs/cert.pem +0 -19
  52. package/test/certs/key.pem +0 -28
  53. package/test/dev/app/Plugin/Start.js +0 -40
  54. package/test/dev/app.mjs +0 -65
  55. package/test/dev/web/favicon.ico +0 -0
  56. package/test/dev/web/index.html +0 -11
  57. package/test/unit/AGENTS.md +0 -106
  58. package/test/unit/Back/Dispatcher.test.mjs +0 -150
  59. package/test/unit/Back/Dto/Handler/Source.test.mjs +0 -40
  60. package/test/unit/Back/Handler/Pre/Log.test.mjs +0 -22
  61. package/test/unit/Back/Handler/Static/A/Config.test.mjs +0 -52
  62. package/test/unit/Back/Handler/Static/A/Fallback.test.mjs +0 -60
  63. package/test/unit/Back/Handler/Static/A/FileService.test.mjs +0 -225
  64. package/test/unit/Back/Handler/Static/A/Registry.test.mjs +0 -83
  65. package/test/unit/Back/Handler/Static/A/Resolver.test.mjs +0 -73
  66. package/test/unit/Back/Handler/Static/Static.test.mjs +0 -235
  67. package/test/unit/Back/Helper/Order/Kahn.test.mjs +0 -59
  68. package/test/unit/Back/Helper/Respond.test.mjs +0 -83
  69. package/test/unit/Back/Server.test.mjs +0 -112
  70. package/test/unit/common.js +0 -22
@@ -1,35 +1,47 @@
1
+ // @ts-check
2
+
1
3
  /**
2
4
  * Web server implementation supporting HTTP/1 and HTTP/2 protocols.
3
- * Handles incoming requests and delegates them to the dispatcher.
4
- *
5
- * @property {function(): module:http.Server} getInstance - Returns the server instance.
6
- * @property {function(Fl32_Web_Back_Server_Config.Dto): Promise<void>} start - Starts the server with given configuration.
7
- * @property {function(): Promise<void>} stop - Stops the server.
5
+ * Handles incoming requests and delegates them to the Pipeline Engine.
8
6
  */
7
+ export const __deps__ = Object.freeze({
8
+ http: 'node_http',
9
+ http2: 'node_http2',
10
+ DEF: 'Fl32_Web_Back_Defaults$',
11
+ logger: 'Fl32_Web_Back_Logger$',
12
+ pipelineEngine: 'Fl32_Web_Back_PipelineEngine$',
13
+ SERVER_TYPE: 'Fl32_Web_Back_Enum_Server_Type$',
14
+ });
15
+
16
+ /**
17
+ * @typedef {object} Fl32_Web_Back_ServerConstructorParams
18
+ * @property {typeof import('node:http')} http
19
+ * @property {typeof import('node:http2')} http2
20
+ * @property {import('./Defaults.mjs').default} DEF
21
+ * @property {Fl32_Web_Back_Logger} logger
22
+ * @property {Fl32_Web_Back_PipelineEngine} pipelineEngine
23
+ * @property {Fl32_Web_Back_Enum_Server_Type} SERVER_TYPE
24
+ */
25
+
9
26
  export default class Fl32_Web_Back_Server {
10
27
  /* eslint-disable jsdoc/require-param-description,jsdoc/check-param-names */
11
28
  /**
12
- * @param {typeof import('node:http')} http
13
- * @param {typeof import('node:http2')} http2
14
- * @param {Fl32_Web_Back_Defaults} DEF
15
- * @param {Fl32_Web_Back_Logger} logger
16
- * @param {Fl32_Web_Back_Dispatcher} dispatcher
17
- * @param {typeof Fl32_Web_Back_Enum_Server_Type} SERVER_TYPE
29
+ * @param {Fl32_Web_Back_ServerConstructorParams} deps
18
30
  */
19
31
  constructor(
20
32
  {
21
- 'node:http': http,
22
- 'node:http2': http2,
23
- Fl32_Web_Back_Defaults$: DEF,
24
- Fl32_Web_Back_Logger$: logger,
25
- Fl32_Web_Back_Dispatcher$: dispatcher,
26
- Fl32_Web_Back_Enum_Server_Type$: SERVER_TYPE,
33
+ http,
34
+ http2,
35
+ DEF,
36
+ logger,
37
+ pipelineEngine,
38
+ SERVER_TYPE,
27
39
  }
28
40
  ) {
29
41
  /* eslint-enable jsdoc/require-param-description,jsdoc/check-param-names */
30
42
  // VARS
31
- const {createServer} = http;
32
- const {createServer: createServerH2, createSecureServer} = http2;
43
+ const { createServer } = http;
44
+ const { createServer: createServerH2, createSecureServer } = http2;
33
45
  /** @type {module:http.Server} */
34
46
  let _instance;
35
47
 
@@ -41,12 +53,11 @@ export default class Fl32_Web_Back_Server {
41
53
 
42
54
  /**
43
55
  * Starts the server with optional configuration.
44
- * @param {Fl32_Web_Back_Server_Config.Dto} [cfg] - Server configuration
56
+ * @param {Fl32_Web_Back_Server_Config} [cfg]
45
57
  * @returns {Promise<void>}
46
58
  */
47
59
  this.start = async function (cfg) {
48
- // order handlers in the dispatcher
49
- dispatcher.orderHandlers();
60
+ pipelineEngine.lockHandlers();
50
61
  // create server
51
62
  const port = cfg?.port ?? DEF.PORT;
52
63
  const type = cfg?.type ?? SERVER_TYPE.HTTP;
@@ -69,7 +80,7 @@ export default class Fl32_Web_Back_Server {
69
80
  throw new Error(`Server type '${type}' is not supported`);
70
81
  }
71
82
 
72
- _instance.on('request', dispatcher.onEventRequest);
83
+ _instance.on('request', pipelineEngine.handleRequest);
73
84
  _instance.listen(port);
74
85
  };
75
86
 
@@ -89,4 +100,4 @@ export default class Fl32_Web_Back_Server {
89
100
  }
90
101
  };
91
102
  }
92
- }
103
+ }
package/types.d.ts ADDED
@@ -0,0 +1,30 @@
1
+ declare global {
2
+ type Fl32_Web_Back_Api_Handler = import("./src/Back/Api/Handler.mjs").default;
3
+ type Fl32_Web_Back_Defaults = import("./src/Back/Defaults.mjs").default;
4
+ type Fl32_Web_Back_Dto_Info = import("./src/Back/Dto/Info.mjs").default;
5
+ type Fl32_Web_Back_Dto_Info$Factory = import("./src/Back/Dto/Info.mjs").Factory;
6
+ type Fl32_Web_Back_Dto_Source = import("./src/Back/Dto/Source.mjs").default;
7
+ type Fl32_Web_Back_Dto_Source$Factory = import("./src/Back/Dto/Source.mjs").Factory;
8
+ type Fl32_Web_Back_Enum_Server_Type = import("./src/Back/Enum/Server/Type.mjs").default;
9
+ type Fl32_Web_Back_Enum_Stage = import("./src/Back/Enum/Stage.mjs").default;
10
+ type Fl32_Web_Back_Handler_Pre_Log = import("./src/Back/Handler/Pre/Log.mjs").default;
11
+ type Fl32_Web_Back_Handler_Static = import("./src/Back/Handler/Static.mjs").default;
12
+ type Fl32_Web_Back_Handler_Static_A_Config = import("./src/Back/Handler/Static/A/Config.mjs").default;
13
+ type Fl32_Web_Back_Handler_Static_A_Fallback = import("./src/Back/Handler/Static/A/Fallback.mjs").default;
14
+ type Fl32_Web_Back_Handler_Static_A_FileService = import("./src/Back/Handler/Static/A/FileService.mjs").default;
15
+ type Fl32_Web_Back_Handler_Static_A_Registry = import("./src/Back/Handler/Static/A/Registry.mjs").default;
16
+ type Fl32_Web_Back_Handler_Static_A_Resolver = import("./src/Back/Handler/Static/A/Resolver.mjs").default;
17
+ type Fl32_Web_Back_Helper_Cast = import("./src/Back/Helper/Cast.mjs").default;
18
+ type Fl32_Web_Back_Helper_Mime = import("./src/Back/Helper/Mime.mjs").default;
19
+ type Fl32_Web_Back_Helper_Order_Kahn = import("./src/Back/Helper/Order/Kahn.mjs").default;
20
+ type Fl32_Web_Back_Helper_Respond = import("./src/Back/Helper/Respond.mjs").default;
21
+ type Fl32_Web_Back_Logger = import("./src/Back/Logger.mjs").default;
22
+ type Fl32_Web_Back_PipelineEngine = import("./src/Back/PipelineEngine.mjs").default;
23
+ type Fl32_Web_Back_Server = import("./src/Back/Server.mjs").default;
24
+ type Fl32_Web_Back_Server_Config = import("./src/Back/Server/Config.mjs").default;
25
+ type Fl32_Web_Back_Server_Config$Factory = import("./src/Back/Server/Config.mjs").Factory;
26
+ type Fl32_Web_Back_Server_Config_Tls = import("./src/Back/Server/Config/Tls.mjs").default;
27
+ type Fl32_Web_Back_Server_Config_Tls$Factory = import("./src/Back/Server/Config/Tls.mjs").Factory;
28
+ }
29
+
30
+ export {};
@@ -1,48 +0,0 @@
1
- name: npm publication
2
-
3
- on:
4
- workflow_dispatch:
5
- release:
6
- types: [created]
7
-
8
- jobs:
9
- build:
10
- runs-on: ubuntu-latest
11
- steps:
12
- # Checkout repository code
13
- - uses: actions/checkout@v4
14
-
15
- # Setup Node.js environment
16
- - uses: actions/setup-node@v4
17
- with:
18
- node-version: 20
19
-
20
- # Install dependencies using package-lock.json
21
- - run: npm ci
22
-
23
- # Run unit tests
24
- - run: npm run test:unit
25
-
26
- # Run acceptance tests
27
- - run: npm run test:accept
28
-
29
- publish-npm:
30
- needs: build
31
- runs-on: ubuntu-latest
32
- steps:
33
- # Checkout repository code again for a separate job
34
- - uses: actions/checkout@v4
35
-
36
- # Setup Node.js and configure npm registry
37
- - uses: actions/setup-node@v4
38
- with:
39
- node-version: 20
40
- registry-url: https://registry.npmjs.org/
41
-
42
- # Install dependencies again
43
- - run: npm ci
44
-
45
- # Publish package to npm registry with authentication token
46
- - run: npm publish --access public
47
- env:
48
- NODE_AUTH_TOKEN: ${{ secrets.npm_token }}
package/AGENTS.md DELETED
@@ -1,101 +0,0 @@
1
- # AGENTS.md
2
-
3
- ## Project: @flancer32/teq-web
4
-
5
- This project implements a request dispatcher plugin for Tequila Framework (TeqFW).
6
- The plugin provides a multi-stage handler system (`pre`, `process`, `post`) and integrates directly with Node.js servers (`http`, `http2`, `https`) without external dependencies.
7
-
8
- ---
9
-
10
- ## Project Structure
11
-
12
- | Directory | Description |
13
- |----------------------------|----------------------------------------------------------------------------|
14
- | `/src/Back/Api/Handler.js` | Interface for all request handlers. |
15
- | `/src/Back/Dispatcher.js` | Core dispatcher that orchestrates handler execution. |
16
- | `/src/Back/Handler/` | Built-in request handlers (`Pre_Log`, `Static`, `Source`, etc). |
17
- | `/src/Back/Helper/` | Internal helpers (`Mime`, `Respond`, `Order_Kahn`, etc). |
18
- | `/src/Back/Dto/` | DTO factories used to pass typed configuration and metadata. |
19
- | `/src/Back/Server.js` | Standalone HTTP(S) server implementation using built-in Node.js libraries. |
20
-
21
- ---
22
-
23
- ## Execution Agents
24
-
25
- ### Dispatcher
26
-
27
- - File: `Back/Dispatcher.js`
28
- - Role: Core runtime coordinator for HTTP requests.
29
- - Interface: uses `Fl32_Web_Back_Api_Handler` and topological ordering via `Order_Kahn`.
30
-
31
- ### Server
32
-
33
- - File: `Back/Server.js`
34
- - Role: HTTP/1.1, HTTP/2, or HTTPS web server.
35
- - Launches `Dispatcher.onEventRequest()` on each request.
36
-
37
- ### Handlers
38
-
39
- - Files: `Back/Handler/Pre_Log.js`, `.../Static.js`, `.../Source.js`
40
- - Role: Modular request processors, registered via `Dispatcher.addHandler()`.
41
- - Lifecycle: Initialized once, executed per request by dispatcher.
42
-
43
- ---
44
-
45
- ## Code Style
46
-
47
- - Language: Modern JavaScript (ES2022+).
48
- - No static imports (uses DI-based module resolution).
49
- - All comments and messages must be in English (strict rule).
50
- - File naming: PascalCase with dot-separated exports, e.g. `Fl32_Web_Back_Enum_Stage`.
51
-
52
- ---
53
-
54
- ## Testing
55
-
56
- - Unit tests must be provided for all runtime agents (Dispatcher, Handlers).
57
- - Test framework: `node:test`.
58
- - Mocks: registered via custom `buildTestContainer()` helper.
59
- - Location: colocated or `/test/` folder depending on iteration.
60
-
61
- ---
62
-
63
- ## Build & Execution
64
-
65
- - This project is a TeqFW plugin. It is not compiled or bundled.
66
- - Executed in-place by Tequila runtime.
67
- - Requires a DI container to resolve dependencies at runtime.
68
-
69
- ---
70
-
71
- ## Contribution Rules (for AI Agents)
72
-
73
- - When creating new Handlers, they **must** implement `Fl32_Web_Back_Api_Handler` and provide `getRegistrationInfo()`.
74
- - Handlers must be registered with `Dispatcher.addHandler()` and ordered with `orderHandlers()`.
75
- - All request-handling code **must** call `respond.isWritable(res)` before sending a response.
76
- - Do not modify existing dispatcher logic directly — create a new handler or helper instead.
77
-
78
- ---
79
-
80
- ## Conventions for AI Tools (Codex, etc.)
81
-
82
- - Start by inspecting `Dispatcher.js` and `Handler/` folder to locate runtime behavior.
83
- - DTOs are created via `*.create(data)` methods and used to validate configs.
84
- - Use `getRegistrationInfo().stage` to determine when a handler runs (`pre`, `process`, `post`).
85
- - Prefer composition over inheritance. Avoid using `extends`.
86
- - Respect topological order defined via `before`/`after`.
87
-
88
- ---
89
-
90
- ## CI/Automation
91
-
92
- - No CI defined yet. Future CI will:
93
- - Validate handler registration structure.
94
- - Enforce code style and comment policy.
95
- - Run full test suite before merge.
96
-
97
- ---
98
-
99
- ## License
100
-
101
- This project is licensed under the Apache-2.0 license.
package/eslint.config.js DELETED
@@ -1,37 +0,0 @@
1
- import js from '@eslint/js';
2
- import jsdoc from 'eslint-plugin-jsdoc';
3
- import {defineConfig} from 'eslint/config';
4
- import globals from 'globals';
5
-
6
- export default defineConfig([
7
- {
8
- files: ['**/*.js', '**/*.mjs'],
9
- plugins: {
10
- js,
11
- jsdoc,
12
- },
13
- extends: ['js/recommended'],
14
- languageOptions: {
15
- ecmaVersion: 'latest',
16
- sourceType: 'module',
17
- globals: {
18
- ...globals.browser,
19
- ...globals.node,
20
- myCustomGlobal: 'readonly',
21
- },
22
- },
23
- rules: {
24
- // Recommended ESLint rules
25
- 'no-unused-vars': 'warn',
26
- 'no-console': 'off',
27
- 'eqeqeq': 'error',
28
- 'curly': ['error', 'multi-line'],
29
- 'semi': ['error', 'always'],
30
- // Your JSDoc rules
31
- 'jsdoc/check-alignment': 'error',
32
- 'jsdoc/check-param-names': 'error',
33
- 'jsdoc/check-types': 'error',
34
- 'jsdoc/require-param-description': 'warn',
35
- },
36
- },
37
- ]);
package/src/AGENTS.md DELETED
@@ -1,108 +0,0 @@
1
- # AI Agents Configuration for Source Directory
2
-
3
- This document defines **long-term, project-agnostic** conventions that AI agents must follow when reading, creating, refactoring, or testing code under any `src/` directory. These guidelines are **permanent** and apply to **all** tasks in this area.
4
-
5
- ---
6
-
7
- ## 1. Directory & File Organization
8
-
9
- * **AZ-structuring**
10
-
11
- * **A-struct**: decompose a single “root” module into its private implementation parts under an `A/` subfolder.
12
-
13
- ```text
14
- src/Feature/Component.js
15
- src/Feature/Component/A/Part1.js
16
- src/Feature/Component/A/Part2.js
17
- ```
18
-
19
- Files under `A/` are private to their parent.
20
- * **Z-struct**: helper modules whose changes do not affect siblings live under a `Z/` subfolder.
21
-
22
- * **Visibility boundaries**: anything **outside** `A/` or `Z/` is public API.
23
-
24
- * **Role → Feature layering**
25
-
26
- * First level: by architectural layer (e.g. `Back/`, `Front/`, `Shared/`).
27
- * Second level: by business feature or component.
28
-
29
- * **Mirror in tests**
30
-
31
- * For every `src/.../X.js` there must be a matching `test/unit/.../X.test.mjs` with the same relative path and filename.
32
-
33
- ---
34
-
35
- ## 2. Class Naming (FQN)
36
-
37
- * Map file path to fully qualified class name (FQN). Example:
38
-
39
- ```text
40
- src/Back/Handler/Static/A/Config.js => class Back_Handler_Static_A_Config
41
- ```
42
-
43
- ---
44
-
45
- ## 3. Dependency Injection, `this` & Closures
46
-
47
- * **DI Container**
48
-
49
- * Inject all external services (file system, path, network, helpers, loggers, factories, enums) via a DI container.
50
- * **Private state via closure**
51
-
52
- * Do **not** assign injected dependencies to `this`.
53
- * Capture each in a `const` inside the constructor and expose only public methods.
54
-
55
- ```js
56
- class Example {
57
- constructor({helperService, logger}) {
58
- this.handle = (req, res) => {
59
- if (!helperService.isWritable(res)) return false;
60
- logger.info('Processing');
61
- return true;
62
- };
63
- }
64
- }
65
- ```
66
-
67
- ---
68
-
69
- ## 4. Comments & Annotations
70
-
71
- * **Language**: all comments and JSDoc must be in **English**.
72
- * **JSDoc**: use `@param {Type}` and `@returns {Type}` on every public method.
73
- * **Class annotation**: annotate all classes with a JSDoc `@class` tag and description.
74
-
75
- ---
76
-
77
- ## 5. Error Handling
78
-
79
- * **Module-level**
80
-
81
- * Do **not** catch all exceptions in each module.
82
- * Catch only **expected, domain-specific** errors when a meaningful fallback exists.
83
- * **Top-level handler**
84
-
85
- * Wrap the entire pipeline in a single `try/catch` at the entry point.
86
- * In that catch, use `logger.exception(error)` and return a safe default (`false`, `null`, or `[]`).
87
-
88
- ---
89
-
90
- ## 6. Testing Conventions
91
-
92
- Refer to the [AI Agent Unit Testing Instructions](../test/unit/AGENTS.md) for project-specific testing guidelines.
93
-
94
- ---
95
-
96
- ## 7. Ongoing Responsibilities
97
-
98
- AI agents must always:
99
-
100
- 1. **Enforce AZ-structuring** when adding or refactoring code.
101
- 2. **Preserve FQN mapping** between file paths and class names.
102
- 3. **Use DI + closures**—never attach injected services to `this`.
103
- 4. **Write English JSDoc** for every new or modified public API, including `@class` on all classes.
104
- 5. **Catch and log errors** at the top level; handle known cases locally.
105
- 6. **Generate or update unit tests** with full coverage for every behavior change (see unit testing guidelines).
106
- 7. **Maintain test-source mirror** so no source file exists without a corresponding test.
107
-
108
- These policies are **permanent** and must be validated on every code change.
@@ -1,26 +0,0 @@
1
- /**
2
- * Interface for web request handlers used by the dispatcher in this plugin.
3
- * Defines the structure and behavior of a handler.
4
- *
5
- * @interface
6
- */
7
- export default class Fl32_Web_Back_Api_Handler {
8
- /* eslint-disable no-unused-vars */
9
- /**
10
- * Handles the incoming web request.
11
- * @param {module:http.IncomingMessage|module:http2.Http2ServerRequest} req - The incoming HTTP request object.
12
- * @param {module:http.ServerResponse|module:http2.Http2ServerResponse} res - The HTTP response object.
13
- * @returns {Promise<boolean>} - Returns true if the request was handled, false otherwise.
14
- */
15
- async handle(req, res) {
16
- throw new Error('Method not implemented');
17
- }
18
-
19
- /**
20
- * Provides metadata for dispatcher registration.
21
- * @returns {Fl32_Web_Back_Dto_Handler_Info.Dto}
22
- */
23
- getRegistrationInfo() {
24
- throw new Error('Method not implemented');
25
- }
26
- }
@@ -1,115 +0,0 @@
1
- /**
2
- * Dispatcher for HTTP(S) requests with three-stage handler execution: pre, process, post.
3
- *
4
- * Handlers are registered via `addHandler()` and activated by `orderHandlers()`.
5
- * On each request, pre-handlers run first, then process-handlers (until one returns true),
6
- * and finally post-handlers are always executed.
7
- *
8
- * If no process handler responds, a 404 is sent. If one throws, a 500 is returned.
9
- */
10
- export default class Fl32_Web_Back_Dispatcher {
11
- /* eslint-disable jsdoc/require-param-description,jsdoc/check-param-names */
12
- /**
13
- * @param {Fl32_Web_Back_Logger} logger
14
- * @param {Fl32_Web_Back_Helper_Respond} respond
15
- * @param {Fl32_Web_Back_Helper_Order_Kahn} helpOrder
16
- * @param {typeof Fl32_Web_Back_Enum_Stage} STAGE
17
- */
18
- constructor(
19
- {
20
- Fl32_Web_Back_Logger$: logger,
21
- Fl32_Web_Back_Helper_Respond$: respond,
22
- Fl32_Web_Back_Helper_Order_Kahn$: helpOrder,
23
- Fl32_Web_Back_Enum_Stage$: STAGE,
24
- }
25
- ) {
26
- /* eslint-enable jsdoc/check-param-names */
27
- // VARS
28
- /** @type {Map<string, Fl32_Web_Back_Api_Handler>} */
29
- const _handlers = new Map();
30
-
31
- /** @type {Fl32_Web_Back_Api_Handler[]} */
32
- let _pre = [], _process = [], _post = [];
33
-
34
- // MAIN
35
-
36
- /**
37
- * Registers a handler. Requires a unique name and stage.
38
- *
39
- * @param {Fl32_Web_Back_Api_Handler} handler
40
- */
41
- this.addHandler = function (handler) {
42
- const info = handler.getRegistrationInfo();
43
- _handlers.set(info.name, handler);
44
- };
45
-
46
- /**
47
- * Executes registered handlers for one HTTP request.
48
- *
49
- * @param {module:http.IncomingMessage|module:http2.Http2ServerRequest} req
50
- * @param {module:http.ServerResponse|module:http2.Http2ServerResponse} res
51
- * @returns {Promise<void>}
52
- */
53
- this.onEventRequest = async function (req, res) {
54
- try {
55
- // Execute all pre-handlers (errors are isolated)
56
- for (const h of _pre) {
57
- try {
58
- await h.handle(req, res);
59
- } catch (e) {
60
- logger.exception(e);
61
- }
62
- }
63
-
64
- // Execute process-handlers (stop at first successful)
65
- let handled = false;
66
- for (const h of _process) {
67
- try {
68
- handled = await h.handle(req, res);
69
- if (handled) break;
70
- } catch (e) {
71
- logger.exception(e);
72
- respond.code500_InternalServerError({res, body: e?.message});
73
- break;
74
- }
75
- }
76
-
77
- // If not handled at all and no error occurred
78
- if (respond.isWritable(res)) {
79
- logger.error(`404 Not Found: ${req.url}`);
80
- respond.code404_NotFound({res});
81
- }
82
- } finally {
83
- // Always run all post-handlers (errors are isolated)
84
- for (const h of _post) {
85
- try {
86
- await h.handle(req, res);
87
- } catch (e) {
88
- logger.exception(e);
89
- }
90
- }
91
- }
92
- };
93
-
94
- /**
95
- * Sorts registered handlers by stage.
96
- */
97
- this.orderHandlers = function () {
98
- const pre = [], process = [], post = [];
99
-
100
- for (const handler of _handlers.values()) {
101
- const dto = handler.getRegistrationInfo();
102
- if (dto.stage === STAGE.PRE) {
103
- pre.push(handler);
104
- } else if (dto.stage === STAGE.PROCESS) {
105
- process.push(handler);
106
- } else if (dto.stage === STAGE.POST) post.push(handler);
107
- }
108
-
109
- _pre = helpOrder.sort(pre);
110
- _process = helpOrder.sort(process);
111
- _post = helpOrder.sort(post);
112
- };
113
- }
114
-
115
- }
@@ -1,68 +0,0 @@
1
- /**
2
- * Factory for dispatcher handler registration metadata.
3
- *
4
- * Produces validated DTOs for registering web request handlers.
5
- *
6
- * @see TeqFw_Core_Shared_Api_Factory
7
- */
8
- export default class Fl32_Web_Back_Dto_Handler_Info {
9
- /* eslint-disable jsdoc/require-param-description,jsdoc/check-param-names */
10
- /**
11
- * @param {Fl32_Web_Back_Helper_Cast} cast
12
- * @param {typeof Fl32_Web_Back_Enum_Stage} STAGE
13
- */
14
- constructor(
15
- {
16
- Fl32_Web_Back_Helper_Cast$: cast,
17
- Fl32_Web_Back_Enum_Stage$: STAGE,
18
- }
19
- ) {
20
- /* eslint-enable jsdoc/check-param-names */
21
- /**
22
- * Create a validated DTO for handler registration.
23
- *
24
- * @param {*} [data] - Optional raw object.
25
- * @returns {Dto}
26
- */
27
- this.create = function (data) {
28
- const res = (data && typeof data === 'object' && !Array.isArray(data))
29
- ? Object.assign(new Dto(), data)
30
- : new Dto();
31
- res.after = cast.array(data?.after, cast.string);
32
- res.before = cast.array(data?.before, cast.string);
33
- res.name = cast.string(data?.name);
34
- res.stage = cast.enum(data?.stage, STAGE, {lower: true});
35
- return res;
36
- };
37
- }
38
- }
39
-
40
- /**
41
- * @memberOf Fl32_Web_Back_Dto_Handler_Info
42
- */
43
- class Dto {
44
- /**
45
- * Handlers to run before this one.
46
- * @type {string[]}
47
- */
48
- after;
49
-
50
- /**
51
- * Handlers to run after this one.
52
- * @type {string[]}
53
- */
54
- before;
55
-
56
- /**
57
- * Unique handler name for ordering.
58
- * @type {string}
59
- */
60
- name;
61
-
62
- /**
63
- * Execution stage: 'pre', 'process', or 'post'.
64
- * @type {string}
65
- * @see Fl32_Web_Back_Enum_Stage
66
- */
67
- stage;
68
- }
@@ -1,12 +0,0 @@
1
- /**
2
- * Enum for server types used to configure built-in web server.
3
- * - 'http': HTTP/1.1
4
- * - 'http2': HTTP/2 without TLS (cleartext)
5
- * - 'https': HTTP/2 over TLS (via http2.createSecureServer)
6
- */
7
- const Fl32_Web_Back_Enum_Server_Type = {
8
- HTTP2: 'http2',
9
- HTTP: 'http',
10
- HTTPS: 'https'
11
- };
12
- export default Fl32_Web_Back_Enum_Server_Type;
@@ -1,10 +0,0 @@
1
- /**
2
- * Enum for web request processing stages in this plugin.
3
- * Used to define processing phases in the web dispatcher specific to this plugin.
4
- */
5
- const Fl32_Web_Back_Enum_Stage = {
6
- PRE: 'pre', // Pre-processing stage: initial request handling (e.g., logging, authentication)
7
- PROCESS: 'process', // Main processing stage: routing and core logic
8
- POST: 'post' // Post-processing stage: final actions (e.g., logging response, cleanup)
9
- };
10
- export default Fl32_Web_Back_Enum_Stage;