@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.
- package/CHANGELOG.md +26 -1
- package/README.md +236 -127
- package/ai/AGENTS.md +36 -0
- package/ai/abstractions.md +75 -0
- package/ai/examples/minimal-server.md +78 -0
- package/ai/overview.md +27 -0
- package/ai/rules.md +41 -0
- package/package.json +43 -28
- package/src/Back/Api/Handler.mjs +26 -0
- package/src/Back/{Defaults.js → Defaults.mjs} +6 -1
- package/src/Back/Dto/Info.mjs +66 -0
- package/src/Back/Dto/{Handler/Source.js → Source.mjs} +26 -23
- package/src/Back/Enum/Server/Type.mjs +13 -0
- package/src/Back/Enum/Stage.mjs +13 -0
- package/src/Back/Handler/Pre/Log.mjs +59 -0
- package/src/Back/Handler/Static/A/{Config.js → Config.mjs} +14 -3
- package/src/Back/Handler/Static/A/{Fallback.js → Fallback.mjs} +16 -4
- package/src/Back/Handler/Static/A/{FileService.js → FileService.mjs} +31 -14
- package/src/Back/Handler/Static/A/{Registry.js → Registry.mjs} +18 -6
- package/src/Back/Handler/Static/A/{Resolver.js → Resolver.mjs} +13 -2
- package/src/Back/Handler/Static.mjs +83 -0
- package/src/Back/Helper/Cast.mjs +116 -0
- package/src/Back/Helper/{Mime.js → Mime.mjs} +2 -0
- package/src/Back/Helper/Order/Kahn.mjs +69 -0
- package/src/Back/Helper/{Respond.js → Respond.mjs} +14 -3
- package/src/Back/Logger.mjs +57 -0
- package/src/Back/PipelineEngine.mjs +228 -0
- package/src/Back/Server/Config/{Tls.js → Tls.mjs} +35 -33
- package/src/Back/Server/Config.mjs +69 -0
- package/src/Back/{Server.js → Server.mjs} +35 -24
- package/types.d.ts +30 -0
- package/.github/workflows/npm-publish.yml +0 -48
- package/AGENTS.md +0 -101
- package/eslint.config.js +0 -37
- package/src/AGENTS.md +0 -108
- package/src/Back/Api/Handler.js +0 -26
- package/src/Back/Dispatcher.js +0 -115
- package/src/Back/Dto/Handler/Info.js +0 -68
- package/src/Back/Enum/Server/Type.js +0 -12
- package/src/Back/Enum/Stage.js +0 -10
- package/src/Back/Handler/Pre/Log.js +0 -45
- package/src/Back/Handler/Static.js +0 -63
- package/src/Back/Helper/Cast.js +0 -114
- package/src/Back/Helper/Order/Kahn.js +0 -66
- package/src/Back/Logger.js +0 -53
- package/src/Back/Server/Config.js +0 -69
- package/teqfw.json +0 -8
- package/test/accept/ExternalServer.test.mjs +0 -66
- package/test/accept/Server.test.mjs +0 -203
- package/test/certs/ca.pem +0 -19
- package/test/certs/cert.pem +0 -19
- package/test/certs/key.pem +0 -28
- package/test/dev/app/Plugin/Start.js +0 -40
- package/test/dev/app.mjs +0 -65
- package/test/dev/web/favicon.ico +0 -0
- package/test/dev/web/index.html +0 -11
- package/test/unit/AGENTS.md +0 -106
- package/test/unit/Back/Dispatcher.test.mjs +0 -150
- package/test/unit/Back/Dto/Handler/Source.test.mjs +0 -40
- package/test/unit/Back/Handler/Pre/Log.test.mjs +0 -22
- package/test/unit/Back/Handler/Static/A/Config.test.mjs +0 -52
- package/test/unit/Back/Handler/Static/A/Fallback.test.mjs +0 -60
- package/test/unit/Back/Handler/Static/A/FileService.test.mjs +0 -225
- package/test/unit/Back/Handler/Static/A/Registry.test.mjs +0 -83
- package/test/unit/Back/Handler/Static/A/Resolver.test.mjs +0 -73
- package/test/unit/Back/Handler/Static/Static.test.mjs +0 -235
- package/test/unit/Back/Helper/Order/Kahn.test.mjs +0 -59
- package/test/unit/Back/Helper/Respond.test.mjs +0 -83
- package/test/unit/Back/Server.test.mjs +0 -112
- 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
|
|
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 {
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
|
56
|
+
* @param {Fl32_Web_Back_Server_Config} [cfg]
|
|
45
57
|
* @returns {Promise<void>}
|
|
46
58
|
*/
|
|
47
59
|
this.start = async function (cfg) {
|
|
48
|
-
|
|
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',
|
|
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.
|
package/src/Back/Api/Handler.js
DELETED
|
@@ -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
|
-
}
|
package/src/Back/Dispatcher.js
DELETED
|
@@ -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;
|
package/src/Back/Enum/Stage.js
DELETED
|
@@ -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;
|