fluxion-ts 0.0.11 → 0.1.1

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 CHANGED
@@ -12,10 +12,12 @@
12
12
 
13
13
  Fluxion is a filesystem-routing dynamic server for Node.js.
14
14
 
15
- - Use `.mjs` files directly as route handlers
16
- - Run handlers inside worker runtime isolation
17
- - Inject any npm module into handler `context` via `modules`
18
- - If a handler returns a value, Fluxion auto-responds with `200 + JSON`
15
+ - Route files from a dynamic directory
16
+ - Load API handlers by extension, default: `.ts`
17
+ - Serve other files as static resources
18
+ - Run the business server in worker processes
19
+ - Expose runtime status from the primary process through meta APIs
20
+ - Automatically serialize handler return values as JSON
19
21
 
20
22
  ## Install
21
23
 
@@ -25,8 +27,6 @@ npm install fluxion
25
27
 
26
28
  ## Quick Start
27
29
 
28
- ### 1) Start the server
29
-
30
30
  Create `server.mjs`:
31
31
 
32
32
  ```js
@@ -39,15 +39,13 @@ fluxion({
39
39
  });
40
40
  ```
41
41
 
42
- ### 2) Create a route handler
43
-
44
- Create `dynamicDirectory/hello.mjs`:
42
+ Create `dynamicDirectory/hello.ts`:
45
43
 
46
- ```js
47
- export default function handler(_req, _res, context) {
44
+ ```ts
45
+ export default async function handler(req) {
48
46
  return {
49
47
  message: 'hello fluxion',
50
- workerId: context.worker.id,
48
+ path: req.url.pathname,
51
49
  };
52
50
  }
53
51
  ```
@@ -58,135 +56,333 @@ Run:
58
56
  node server.mjs
59
57
  ```
60
58
 
61
- Test:
59
+ Request:
62
60
 
63
61
  ```bash
64
- curl http://127.0.0.1:3000/hello
62
+ curl http://127.0.0.1:3000/hello.ts
65
63
  ```
66
64
 
67
- You will get a JSON response with status `200`.
65
+ Response:
68
66
 
69
- ## Routing Rules
67
+ ```json
68
+ {"message":"hello fluxion","path":"/hello.ts"}
69
+ ```
70
70
 
71
- - `dynamicDirectory/index.mjs` -> `/`
72
- - `dynamicDirectory/user.mjs` -> `/user`
73
- - `dynamicDirectory/user/index.mjs` -> `/user`
74
- - Non-`.mjs` files are served as static files (`GET/HEAD`)
75
- - Directories/files starting with `_` are private and not routable
71
+ ## Development Entry
76
72
 
77
- ## Handler Styles
73
+ In this repository, `pnpm dev` runs `src/index.ts` directly and starts Fluxion unless `NODE_ENV=production`.
78
74
 
79
- ### Function export
75
+ Default development options:
80
76
 
81
- ```js
82
- export default function handler(req, res, context) {
77
+ ```ts
78
+ fluxion({
79
+ dir: process.env.DYNAMIC_DIRECTORY ?? 'dynamicDirectory',
80
+ host: process.env.HOST ?? 'localhost',
81
+ port: process.env.PORT ? Number.parseInt(process.env.PORT, 10) : 3000,
82
+ reloadDelay: process.env.RELOAD_DELAY ? Number.parseInt(process.env.RELOAD_DELAY, 10) : undefined,
83
+ workerOptions: {
84
+ maxWorkerCount: 1,
85
+ },
86
+ });
87
+ ```
88
+
89
+ Example:
90
+
91
+ ```bash
92
+ pnpm dev
93
+ curl http://localhost:3000/test.ts
94
+ ```
95
+
96
+ ## Routing
97
+
98
+ Fluxion registers every file under `dir` recursively.
99
+
100
+ With default options:
101
+
102
+ - Files ending with `.ts` are API handlers.
103
+ - Files with other extensions are static resources.
104
+ - Request paths match file paths relative to `dir`.
105
+ - File extensions are part of the route path.
106
+
107
+ Examples:
108
+
109
+ | File | Route | Type |
110
+ | --- | --- | --- |
111
+ | `dynamicDirectory/test.ts` | `/test.ts` | API handler |
112
+ | `dynamicDirectory/user/profile.ts` | `/user/profile.ts` | API handler |
113
+ | `dynamicDirectory/index.html` | `/index.html` | Static file |
114
+ | `dynamicDirectory/assets/app.js` | `/assets/app.js` | Static file |
115
+
116
+ A request to `/hello` does not match `hello.ts`; request `/hello.ts` or change `apiExts`/routing behavior in code.
117
+
118
+ ## API Handlers
119
+
120
+ An API file must export a function by one of these forms:
121
+
122
+ ```ts
123
+ export default async function handler(req, rawReq, rawRes) {
83
124
  return { ok: true };
84
125
  }
85
126
  ```
86
127
 
87
- ### Object export (with modules)
128
+ ```ts
129
+ export async function handler(req, rawReq, rawRes) {
130
+ return { ok: true };
131
+ }
132
+ ```
88
133
 
89
- ```js
90
- export default {
91
- modules: [
92
- {
93
- module: 'node:crypto',
94
- injectKey: 'crypto',
95
- factory: (cryptoModule) => cryptoModule,
96
- },
97
- ],
98
- handler(_req, _res, context) {
99
- return {
100
- hash: context.crypto.createHash('sha1').update('abc').digest('hex'),
101
- };
102
- },
103
- };
134
+ Common local style:
135
+
136
+ ```ts
137
+ import { defineFluxionHandler } from '@/index.js';
138
+
139
+ export default defineFluxionHandler(async (req) => {
140
+ return req.url.pathname + '成功';
141
+ });
104
142
  ```
105
143
 
106
- ## Automatic JSON Response
144
+ ### Handler Arguments
107
145
 
108
- If a handler return value is not `undefined` and you do not manually call `res.end()`, Fluxion will automatically:
146
+ ```ts
147
+ handler(normalizedRequest, rawRequest, rawResponse)
148
+ ```
149
+
150
+ `normalizedRequest` contains:
151
+
152
+ ```ts
153
+ {
154
+ method: string;
155
+ ip: string;
156
+ url: URL;
157
+ query: Record<string, string | string[]>;
158
+ body: Record<string, any>;
159
+ headers: IncomingHttpHeaders;
160
+ cookie: Record<string, string>;
161
+ }
162
+ ```
109
163
 
110
- - set status to `200`
111
- - set `content-type` to `application/json; charset=utf-8` (if missing)
112
- - serialize the return value with `JSON.stringify(...)`
164
+ `rawRequest` and `rawResponse` are Node.js HTTP objects.
113
165
 
114
- Recommended pattern per handler:
166
+ ## Response Behavior
115
167
 
116
- 1. Return data directly (recommended)
117
- 2. Or fully control `res` manually (streaming, file download, etc.)
168
+ If the handler returns a value, Fluxion responds with JSON:
118
169
 
119
- ## Module Injection (Recommended)
170
+ ```ts
171
+ export default async function handler() {
172
+ return { ok: true };
173
+ }
174
+ ```
120
175
 
121
- Fluxion does not bundle database drivers. Install app dependencies yourself.
176
+ Response:
122
177
 
123
- For example, to use MySQL in handlers:
178
+ ```http
179
+ HTTP/1.1 200 OK
180
+ Content-Type: application/json; charset=utf-8
124
181
 
125
- ```bash
126
- npm install mysql2
182
+ {"ok":true}
127
183
  ```
128
184
 
129
- ```js
130
- export default {
131
- modules: [
132
- {
133
- module: 'mysql2/promise',
134
- injectKey: 'mydb',
135
- options: {
136
- host: '127.0.0.1',
137
- user: 'root',
138
- password: '***',
139
- database: 'demo',
140
- },
141
- factory: (mysql2, options) => mysql2.createPool(options),
142
- },
143
- ],
144
- async handler(_req, _res, context) {
145
- const [rows] = await context.mydb.query('select 1 as ok');
146
- return rows;
147
- },
148
- };
185
+ You can also write to `rawResponse` manually:
186
+
187
+ ```ts
188
+ export default async function handler(_req, _rawReq, res) {
189
+ res.statusCode = 201;
190
+ res.setHeader('Content-Type', 'text/plain; charset=utf-8');
191
+ res.end('created');
192
+ }
193
+ ```
194
+
195
+ When `res` has already ended, Fluxion will not send another JSON response.
196
+
197
+ ## Request Body
198
+
199
+ Fluxion parses request bodies before calling the handler, except for `GET` and `HEAD`.
200
+
201
+ Supported parsing:
202
+
203
+ - JSON content types: object values are assigned directly; primitive values become `{ value }`; invalid JSON becomes `{ raw }`.
204
+ - `application/x-www-form-urlencoded`: parsed into key/value fields.
205
+ - Textual content types: stored as `{ raw }`.
206
+ - Other binary bodies are read for size checking/log preview but `body` remains `{}`.
207
+
208
+ Requests larger than `maxRequestBytes` return `413`.
209
+
210
+ ## Static Files
211
+
212
+ Non-API files are served as static resources.
213
+
214
+ Supported methods:
215
+
216
+ - `GET`
217
+ - `HEAD`
218
+
219
+ Other methods return `405` with:
220
+
221
+ ```http
222
+ Allow: GET, HEAD
149
223
  ```
150
224
 
151
- ### `modules` fields
225
+ Known content types include `.html`, `.css`, `.js`, `.json`, `.png`, `.jpg`, `.jpeg`, `.svg`, `.txt`, `.webp`, `.ico`, and `.map`. Unknown extensions use `application/octet-stream`.
152
226
 
153
- - `module`: module id used by dynamic `import()`
154
- - `injectKey`: target key in `context[injectKey]`
155
- - `options`: custom config passed into `factory`
156
- - `factory`: `(importedModule, options, runtime) => injectedValue`
227
+ ## File Watching
157
228
 
158
- `factory` runs inside the worker and is restored from source text. Keep it self-contained (do not depend on outer closures).
229
+ Workers watch the dynamic directory recursively.
159
230
 
160
- Each worker keeps its own module instances. On worker shutdown, Fluxion will attempt `dispose/close/end/destroy` if present.
231
+ On file changes:
161
232
 
162
- ## Common Options
233
+ - existing files are re-registered;
234
+ - deleted files are removed from the router;
235
+ - updates are debounced by `reloadDelay`, default `300ms`.
163
236
 
164
- Main `fluxion({...})` options:
237
+ ## Cluster Runtime
165
238
 
166
- - `dir`: dynamic directory (handler root)
167
- - `host`: listen host
168
- - `port`: listen port
169
- - `metaPort`: primary meta API port (defaults to `port + 1`)
170
- - `maxRequestBytes`: max request body size (returns 413 when exceeded)
171
- - `logger`: `one-line` / `json-line` / custom function
239
+ Fluxion uses Node.js `cluster`:
240
+
241
+ - The primary process starts meta APIs and manages worker state.
242
+ - Worker processes watch the dynamic directory and serve business traffic.
243
+ - `workerOptions.maxWorkerCount` controls worker count. Default is capped by CPU count.
172
244
 
173
245
  ## Meta APIs
174
246
 
175
- Meta APIs are served by the primary process on `metaPort`:
247
+ Meta APIs are served by the primary process on `metaPort`.
176
248
 
177
- - `GET /_fluxion/healthz`
178
- - `GET /_fluxion/workers` (worker status + cpu/memory stats)
249
+ Default:
179
250
 
180
- ## Important
251
+ ```ts
252
+ metaPort = port + 1
253
+ ```
181
254
 
182
- Legacy handler-level `db` declarations are removed:
255
+ Endpoints:
183
256
 
184
- ```js
185
- export default {
186
- // db: ['main'] // no longer supported
187
- modules: [],
188
- handler() {},
189
- };
257
+ ```http
258
+ GET /_fluxion/healthz
259
+ GET /_fluxion/workers
260
+ ```
261
+
262
+ Example:
263
+
264
+ ```bash
265
+ curl http://127.0.0.1:3001/_fluxion/healthz
266
+ curl http://127.0.0.1:3001/_fluxion/workers
267
+ ```
268
+
269
+ If a meta API path is requested on the business port, Fluxion returns `404` and points to the meta port.
270
+
271
+ ## Options
272
+
273
+ ```ts
274
+ interface FluxionOptions {
275
+ dir: string;
276
+ host: string;
277
+ port: number;
278
+ reloadDelay?: number;
279
+ metaPort?: number;
280
+ injections?: InjectionConfig[];
281
+ moduleDir?: string;
282
+ workerOptions?: Partial<WorkerOptions>;
283
+ maxRequestBytes?: number;
284
+ logger?: 'one-line' | 'json-line' | InjectionConfig;
285
+ apiExts?: string[];
286
+ routerExclude?: string[];
287
+ }
288
+ ```
289
+
290
+ ### `dir`
291
+
292
+ Dynamic directory root. Created automatically if missing.
293
+
294
+ ### `host`
295
+
296
+ Host passed to `server.listen`.
297
+
298
+ ### `port`
299
+
300
+ Business server port.
301
+
302
+ ### `metaPort`
303
+
304
+ Primary meta API port. Defaults to `port + 1` and must be different from `port`.
305
+
306
+ ### `reloadDelay`
307
+
308
+ Debounce delay for file re-registration. Defaults to `300` and must be at least `50`.
309
+
310
+ ### `apiExts`
311
+
312
+ Extensions registered as API handlers. Defaults to:
313
+
314
+ ```ts
315
+ ['.ts']
316
+ ```
317
+
318
+ Example:
319
+
320
+ ```ts
321
+ fluxion({
322
+ dir: './dynamicDirectory',
323
+ host: '127.0.0.1',
324
+ port: 3000,
325
+ apiExts: ['.ts', '.mjs'],
326
+ });
327
+ ```
328
+
329
+ ### `routerExclude`
330
+
331
+ Extensions excluded from both API and static registration.
332
+
333
+ Example:
334
+
335
+ ```ts
336
+ routerExclude: ['.map']
337
+ ```
338
+
339
+ ### `maxRequestBytes`
340
+
341
+ Maximum accepted request body size. Defaults to `8_000_000`.
342
+
343
+ ### `logger`
344
+
345
+ Built-in modes:
346
+
347
+ - `one-line`
348
+ - `json-line`
349
+
350
+ A custom logger can be loaded through an injection config object whose module exports a function.
351
+
352
+ ### `injections`
353
+
354
+ Worker startup injections. Each item is loaded with `require(modulePath)` and called as a factory. The resulting instances are stored on:
355
+
356
+ ```ts
357
+ globalThis[Symbol.for('fluxion.injection')]
358
+ ```
359
+
360
+ ### `workerOptions`
361
+
362
+ Runtime tuning options:
363
+
364
+ ```ts
365
+ interface WorkerOptions {
366
+ maxWorkerCount: number;
367
+ requestTimeoutMs: number;
368
+ maxInflight: number;
369
+ memorySoftLimitMb: number;
370
+ memoryHardLimitMb: number;
371
+ memorySampleIntervalMs: number;
372
+ maxOldGenerationSizeMb: number;
373
+ maxYoungGenerationSizeMb: number;
374
+ stackSizeMb: number;
375
+ maxResponseBytes: number;
376
+ }
377
+ ```
378
+
379
+ Current implementation uses `maxWorkerCount` for process count and reports CPU/memory telemetry from workers.
380
+
381
+ ## Build and Test
382
+
383
+ ```bash
384
+ pnpm build
385
+ pnpm test
386
+ pnpm lint
190
387
  ```
191
388
 
192
- Use `modules` for dependency injection.