@fluojs/platform-express 1.0.2 → 1.0.4
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.ko.md +2 -2
- package/README.md +2 -2
- package/dist/adapter.d.ts +1 -2
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +20 -20
- package/package.json +4 -4
package/README.ko.md
CHANGED
|
@@ -90,7 +90,7 @@ const adapter = createExpressAdapter(
|
|
|
90
90
|
- **버저닝 parity**: Express Router가 최초 path match를 하더라도 header/media-type/custom version 선택은 계속 dispatcher가 최종 결정합니다.
|
|
91
91
|
- **Middleware rewrite parity**: App middleware가 method/path를 rewrite하면 native handoff는 무효화되고 rewrite된 요청을 기준으로 다시 매칭합니다.
|
|
92
92
|
- **응답 serialization parity**: String response는 기본적으로 `text/plain`, object/array는 JSON, binary payload는 `application/octet-stream`으로 serialize되며 `set-cookie` 값은 병합됩니다.
|
|
93
|
-
- **Startup과 shutdown**: 어댑터는 HTTP/HTTPS startup, retry option에 따른 `EADDRINUSE` 재시도, close 시 socket drain, shutdown timeout 이후 force-close를 지원하며, `shutdownTimeoutMs`가 `0`이면 즉시 force-close합니다.
|
|
93
|
+
- **Startup과 shutdown**: 어댑터는 HTTP/HTTPS startup, retry option에 따른 `EADDRINUSE` 재시도, close 시 socket drain, 동시에 들어온 `close()` 호출의 단일 in-flight close lifecycle 재사용, shutdown timeout 이후 force-close를 지원하며, `shutdownTimeoutMs`가 `0`이면 즉시 force-close합니다.
|
|
94
94
|
|
|
95
95
|
## 공개 API 개요
|
|
96
96
|
|
|
@@ -101,7 +101,7 @@ const adapter = createExpressAdapter(
|
|
|
101
101
|
- `ExpressHttpApplicationAdapter`: 핵심 어댑터 구현 클래스입니다.
|
|
102
102
|
- Option type: `ExpressAdapterOptions`, `BootstrapExpressApplicationOptions`, `RunExpressApplicationOptions`, `CorsInput`, `ExpressApplicationSignal`.
|
|
103
103
|
|
|
104
|
-
`createExpressAdapter(options, multipartOptions?)`는 `host`, `https`, `maxBodySize`, `port`, `rawBody`, `retryDelayMs`, `retryLimit`, `shutdownTimeoutMs`를 지원합니다. `ExpressHttpApplicationAdapter`를 직접 생성하는 경우에도 factory와 같은 numeric validation이 적용됩니다. `bootstrapExpressApplication(...)`과 `runExpressApplication(...)`은 `cors`, `globalPrefix`, `globalPrefixExclude`, `
|
|
104
|
+
`createExpressAdapter(options, multipartOptions?)`는 `host`, `https`, `maxBodySize`, `port`, `rawBody`, `retryDelayMs`, `retryLimit`, `shutdownTimeoutMs`를 지원합니다. `ExpressHttpApplicationAdapter`를 직접 생성하는 경우에도 factory와 같은 numeric validation이 적용됩니다. `bootstrapExpressApplication(...)`과 `runExpressApplication(...)`은 `cors`, `globalPrefix`, `globalPrefixExclude`, `middleware`, `multipart`, `securityHeaders`, `forceExitTimeoutMs`, `shutdownSignals`도 받으며, startup/shutdown diagnostics를 위해 framework console logger를 내부에서 선택합니다.
|
|
105
105
|
|
|
106
106
|
## 관련 패키지
|
|
107
107
|
|
package/README.md
CHANGED
|
@@ -90,7 +90,7 @@ To avoid changing documented fluo semantics, overlapping same-shape param routes
|
|
|
90
90
|
- **Versioning parity**: Header/media-type/custom version selection remains dispatcher-owned even when Express Router handles the initial path match.
|
|
91
91
|
- **Middleware rewrite parity**: App middleware that rewrites method or path invalidates native handoff and rematches the rewritten request.
|
|
92
92
|
- **Response serialization parity**: String responses default to `text/plain`, objects/arrays serialize as JSON, binary payloads default to `application/octet-stream`, and `set-cookie` values are merged.
|
|
93
|
-
- **Startup and shutdown**: The adapter supports HTTP/HTTPS startup, retries `EADDRINUSE` according to retry options, drains sockets on close, and can force-close connections after shutdown timeout, including immediate force-close when `shutdownTimeoutMs` is `0`.
|
|
93
|
+
- **Startup and shutdown**: The adapter supports HTTP/HTTPS startup, retries `EADDRINUSE` according to retry options, drains sockets on close, reuses one in-flight close lifecycle for concurrent `close()` calls, and can force-close connections after shutdown timeout, including immediate force-close when `shutdownTimeoutMs` is `0`.
|
|
94
94
|
|
|
95
95
|
## Public API Overview
|
|
96
96
|
|
|
@@ -101,7 +101,7 @@ To avoid changing documented fluo semantics, overlapping same-shape param routes
|
|
|
101
101
|
- `ExpressHttpApplicationAdapter`: The core adapter implementation class.
|
|
102
102
|
- Option types: `ExpressAdapterOptions`, `BootstrapExpressApplicationOptions`, `RunExpressApplicationOptions`, `CorsInput`, `ExpressApplicationSignal`.
|
|
103
103
|
|
|
104
|
-
`createExpressAdapter(options, multipartOptions?)` supports `host`, `https`, `maxBodySize`, `port`, `rawBody`, `retryDelayMs`, `retryLimit`, and `shutdownTimeoutMs`. Direct `ExpressHttpApplicationAdapter` construction applies the same numeric validation as the factory. `bootstrapExpressApplication(...)` and `runExpressApplication(...)` also accept `cors`, `globalPrefix`, `globalPrefixExclude`, `
|
|
104
|
+
`createExpressAdapter(options, multipartOptions?)` supports `host`, `https`, `maxBodySize`, `port`, `rawBody`, `retryDelayMs`, `retryLimit`, and `shutdownTimeoutMs`. Direct `ExpressHttpApplicationAdapter` construction applies the same numeric validation as the factory. `bootstrapExpressApplication(...)` and `runExpressApplication(...)` also accept `cors`, `globalPrefix`, `globalPrefixExclude`, `middleware`, `multipart`, `securityHeaders`, `forceExitTimeoutMs`, and `shutdownSignals`, and select the framework console logger internally for startup and shutdown diagnostics.
|
|
105
105
|
|
|
106
106
|
## Related Packages
|
|
107
107
|
|
package/dist/adapter.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ServerOptions as HttpsServerOptions } from 'node:https';
|
|
2
2
|
import { type CorsOptions, type Dispatcher, type HttpApplicationAdapter, type MiddlewareLike, type SecurityHeadersOptions } from '@fluojs/http';
|
|
3
|
-
import type { Application,
|
|
3
|
+
import type { Application, CreateApplicationOptions, ModuleType, MultipartOptions, UploadedFile } from '@fluojs/runtime';
|
|
4
4
|
declare module '@fluojs/http' {
|
|
5
5
|
interface FrameworkRequest {
|
|
6
6
|
files?: UploadedFile[];
|
|
@@ -37,7 +37,6 @@ export interface BootstrapExpressApplicationOptions extends Omit<CreateApplicati
|
|
|
37
37
|
globalPrefixExclude?: readonly string[];
|
|
38
38
|
host?: string;
|
|
39
39
|
https?: HttpsServerOptions;
|
|
40
|
-
logger?: ApplicationLogger;
|
|
41
40
|
maxBodySize?: number;
|
|
42
41
|
middleware?: MiddlewareLike[];
|
|
43
42
|
multipart?: MultipartOptions;
|
package/dist/adapter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,aAAa,IAAI,kBAAkB,EACzC,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/adapter.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { createServer as createHttpServer } from 'node:http';
|
|
2
2
|
import { createServer as createHttpsServer } from 'node:https';
|
|
3
3
|
import { Readable } from 'node:stream';
|
|
4
|
-
import
|
|
5
|
-
import { BadRequestException, createServerBackedHttpAdapterRealtimeCapability, createErrorResponse, HttpException, InternalServerErrorException, PayloadTooLargeException } from '@fluojs/http';
|
|
4
|
+
import { BadRequestException, createErrorResponse, createServerBackedHttpAdapterRealtimeCapability, HttpException, InternalServerErrorException, PayloadTooLargeException } from '@fluojs/http';
|
|
6
5
|
import { attachFrameworkRequestNativeRouteHandoff, bindRawRequestNativeRouteHandoff, consumeRawRequestNativeRouteHandoff, isRoutePathNormalizationSensitive } from '@fluojs/http/internal';
|
|
7
|
-
import {
|
|
6
|
+
import { bootstrapHttpAdapterApplication, createConsoleApplicationLogger, runHttpAdapterApplication } from '@fluojs/runtime/internal/http-adapter';
|
|
7
|
+
import { dispatchWithRequestResponseFactory } from '@fluojs/runtime/internal/request-response-factory';
|
|
8
8
|
import { cloneRequestHeaders, createDeferredFrameworkRequestShell, createMemoizedAsyncValue, createRequestSignal, normalizePrimaryContentType, parseQueryParamsFromSearch, resolveAbsoluteRequestUrl, resolveRequestIdFromHeaders, snapshotSimpleQueryRecord, splitRawRequestUrl } from '@fluojs/runtime/internal-node';
|
|
9
|
+
import { createNodeShutdownSignalRegistration, defaultNodeShutdownSignals } from '@fluojs/runtime/node';
|
|
9
10
|
import { parseMultipart } from '@fluojs/runtime/web';
|
|
10
|
-
import
|
|
11
|
-
import { dispatchWithRequestResponseFactory } from '@fluojs/runtime/internal/request-response-factory';
|
|
11
|
+
import express from 'express';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Describes the express adapter options contract.
|
|
@@ -90,23 +90,21 @@ export class ExpressHttpApplicationAdapter {
|
|
|
90
90
|
await this.listenWithRetry();
|
|
91
91
|
}
|
|
92
92
|
async close() {
|
|
93
|
-
if (
|
|
94
|
-
this.
|
|
93
|
+
if (this.closeInFlight) {
|
|
94
|
+
await waitForCloseWithTimeout(this.closeInFlight, this.shutdownTimeoutMs);
|
|
95
95
|
return;
|
|
96
96
|
}
|
|
97
|
-
if (!this.
|
|
98
|
-
|
|
99
|
-
const closeInFlight = closePromise.finally(() => {
|
|
100
|
-
this.closeInFlight = undefined;
|
|
101
|
-
this.dispatcher = undefined;
|
|
102
|
-
});
|
|
103
|
-
this.closeInFlight = closeInFlight;
|
|
104
|
-
void closeInFlight.catch(() => {});
|
|
105
|
-
}
|
|
106
|
-
const closeInFlight = this.closeInFlight;
|
|
107
|
-
if (!closeInFlight) {
|
|
97
|
+
if (!this.server.listening) {
|
|
98
|
+
this.dispatcher = undefined;
|
|
108
99
|
return;
|
|
109
100
|
}
|
|
101
|
+
const closePromise = closeServerWithDrain(this.server, this.sockets, this.shutdownTimeoutMs);
|
|
102
|
+
const closeInFlight = closePromise.finally(() => {
|
|
103
|
+
this.closeInFlight = undefined;
|
|
104
|
+
this.dispatcher = undefined;
|
|
105
|
+
});
|
|
106
|
+
this.closeInFlight = closeInFlight;
|
|
107
|
+
void closeInFlight.catch(() => {});
|
|
110
108
|
await waitForCloseWithTimeout(closeInFlight, this.shutdownTimeoutMs);
|
|
111
109
|
}
|
|
112
110
|
async listenWithRetry() {
|
|
@@ -300,7 +298,8 @@ export function createExpressAdapter(options = {}, multipartOptions) {
|
|
|
300
298
|
* @returns The bootstrap express application result.
|
|
301
299
|
*/
|
|
302
300
|
export async function bootstrapExpressApplication(rootModule, options) {
|
|
303
|
-
|
|
301
|
+
const logger = createConsoleApplicationLogger();
|
|
302
|
+
return bootstrapHttpAdapterApplication(rootModule, options, createExpressAdapter(options, options.multipart), logger);
|
|
304
303
|
}
|
|
305
304
|
|
|
306
305
|
/**
|
|
@@ -311,11 +310,12 @@ export async function bootstrapExpressApplication(rootModule, options) {
|
|
|
311
310
|
* @returns The run express application result.
|
|
312
311
|
*/
|
|
313
312
|
export async function runExpressApplication(rootModule, options) {
|
|
313
|
+
const logger = createConsoleApplicationLogger();
|
|
314
314
|
const adapter = createExpressAdapter(options, options.multipart);
|
|
315
315
|
return runHttpAdapterApplication(rootModule, {
|
|
316
316
|
...options,
|
|
317
317
|
shutdownRegistration: createNodeShutdownSignalRegistration(options.shutdownSignals ?? defaultNodeShutdownSignals())
|
|
318
|
-
}, adapter);
|
|
318
|
+
}, adapter, logger);
|
|
319
319
|
}
|
|
320
320
|
function createFrameworkResponse(response) {
|
|
321
321
|
return {
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"platform",
|
|
9
9
|
"server"
|
|
10
10
|
],
|
|
11
|
-
"version": "1.0.
|
|
11
|
+
"version": "1.0.4",
|
|
12
12
|
"private": false,
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"repository": {
|
|
@@ -36,13 +36,13 @@
|
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"express": "^5.1.0",
|
|
39
|
-
"@fluojs/http": "^1.
|
|
40
|
-
"@fluojs/runtime": "^1.1.
|
|
39
|
+
"@fluojs/http": "^1.1.0",
|
|
40
|
+
"@fluojs/runtime": "^1.1.5"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/express": "^5.0.3",
|
|
44
44
|
"vitest": "^3.2.4",
|
|
45
|
-
"@fluojs/di": "^1.0.
|
|
45
|
+
"@fluojs/di": "^1.0.3"
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|
|
48
48
|
"prebuild": "node ../../tooling/scripts/clean-dist.mjs",
|