@xfcfam/xf-server-http 0.1.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/LICENSE +21 -0
- package/README.md +240 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -0
- package/dist/src/api/A.d.ts +18 -0
- package/dist/src/api/A.d.ts.map +1 -0
- package/dist/src/api/A.js +18 -0
- package/dist/src/api/A.js.map +1 -0
- package/dist/src/api/general/GraphQLService.d.ts +48 -0
- package/dist/src/api/general/GraphQLService.d.ts.map +1 -0
- package/dist/src/api/general/GraphQLService.js +43 -0
- package/dist/src/api/general/GraphQLService.js.map +1 -0
- package/dist/src/api/general/ObjectRestService.d.ts +196 -0
- package/dist/src/api/general/ObjectRestService.d.ts.map +1 -0
- package/dist/src/api/general/ObjectRestService.js +289 -0
- package/dist/src/api/general/ObjectRestService.js.map +1 -0
- package/dist/src/api/general/RestService.d.ts +62 -0
- package/dist/src/api/general/RestService.d.ts.map +1 -0
- package/dist/src/api/general/RestService.js +75 -0
- package/dist/src/api/general/RestService.js.map +1 -0
- package/dist/src/api/general/WebSocketService.d.ts +42 -0
- package/dist/src/api/general/WebSocketService.d.ts.map +1 -0
- package/dist/src/api/general/WebSocketService.js +45 -0
- package/dist/src/api/general/WebSocketService.js.map +1 -0
- package/dist/src/api/utils/FileResponseUtils.d.ts +66 -0
- package/dist/src/api/utils/FileResponseUtils.d.ts.map +1 -0
- package/dist/src/api/utils/FileResponseUtils.js +82 -0
- package/dist/src/api/utils/FileResponseUtils.js.map +1 -0
- package/dist/src/api/utils/HttpStatusUtils.d.ts +36 -0
- package/dist/src/api/utils/HttpStatusUtils.d.ts.map +1 -0
- package/dist/src/api/utils/HttpStatusUtils.js +40 -0
- package/dist/src/api/utils/HttpStatusUtils.js.map +1 -0
- package/dist/src/api/utils/ResponseUtils.d.ts +61 -0
- package/dist/src/api/utils/ResponseUtils.d.ts.map +1 -0
- package/dist/src/api/utils/ResponseUtils.js +81 -0
- package/dist/src/api/utils/ResponseUtils.js.map +1 -0
- package/dist/src/api/utils/SchemaValidatorUtils.d.ts +48 -0
- package/dist/src/api/utils/SchemaValidatorUtils.d.ts.map +1 -0
- package/dist/src/api/utils/SchemaValidatorUtils.js +52 -0
- package/dist/src/api/utils/SchemaValidatorUtils.js.map +1 -0
- package/dist/src/api/utils/SseUtils.d.ts +57 -0
- package/dist/src/api/utils/SseUtils.d.ts.map +1 -0
- package/dist/src/api/utils/SseUtils.js +78 -0
- package/dist/src/api/utils/SseUtils.js.map +1 -0
- package/dist/src/business/B.d.ts +18 -0
- package/dist/src/business/B.d.ts.map +1 -0
- package/dist/src/business/B.js +18 -0
- package/dist/src/business/B.js.map +1 -0
- package/dist/src/business/general/HttpServerBusiness.d.ts +190 -0
- package/dist/src/business/general/HttpServerBusiness.d.ts.map +1 -0
- package/dist/src/business/general/HttpServerBusiness.js +364 -0
- package/dist/src/business/general/HttpServerBusiness.js.map +1 -0
- package/dist/src/business/transfers/BadRequestException.d.ts +13 -0
- package/dist/src/business/transfers/BadRequestException.d.ts.map +1 -0
- package/dist/src/business/transfers/BadRequestException.js +16 -0
- package/dist/src/business/transfers/BadRequestException.js.map +1 -0
- package/dist/src/business/transfers/ForbiddenException.d.ts +13 -0
- package/dist/src/business/transfers/ForbiddenException.d.ts.map +1 -0
- package/dist/src/business/transfers/ForbiddenException.js +16 -0
- package/dist/src/business/transfers/ForbiddenException.js.map +1 -0
- package/dist/src/business/transfers/GraphQLConfig.d.ts +25 -0
- package/dist/src/business/transfers/GraphQLConfig.d.ts.map +1 -0
- package/dist/src/business/transfers/GraphQLConfig.js +2 -0
- package/dist/src/business/transfers/GraphQLConfig.js.map +1 -0
- package/dist/src/business/transfers/HttpException.d.ts +23 -0
- package/dist/src/business/transfers/HttpException.d.ts.map +1 -0
- package/dist/src/business/transfers/HttpException.js +27 -0
- package/dist/src/business/transfers/HttpException.js.map +1 -0
- package/dist/src/business/transfers/HttpMethod.d.ts +7 -0
- package/dist/src/business/transfers/HttpMethod.d.ts.map +1 -0
- package/dist/src/business/transfers/HttpMethod.js +2 -0
- package/dist/src/business/transfers/HttpMethod.js.map +1 -0
- package/dist/src/business/transfers/HttpRequest.d.ts +35 -0
- package/dist/src/business/transfers/HttpRequest.d.ts.map +1 -0
- package/dist/src/business/transfers/HttpRequest.js +2 -0
- package/dist/src/business/transfers/HttpRequest.js.map +1 -0
- package/dist/src/business/transfers/HttpResponse.d.ts +28 -0
- package/dist/src/business/transfers/HttpResponse.d.ts.map +1 -0
- package/dist/src/business/transfers/HttpResponse.js +2 -0
- package/dist/src/business/transfers/HttpResponse.js.map +1 -0
- package/dist/src/business/transfers/InternalServerException.d.ts +13 -0
- package/dist/src/business/transfers/InternalServerException.d.ts.map +1 -0
- package/dist/src/business/transfers/InternalServerException.js +16 -0
- package/dist/src/business/transfers/InternalServerException.js.map +1 -0
- package/dist/src/business/transfers/MultipartPart.d.ts +38 -0
- package/dist/src/business/transfers/MultipartPart.d.ts.map +1 -0
- package/dist/src/business/transfers/MultipartPart.js +2 -0
- package/dist/src/business/transfers/MultipartPart.js.map +1 -0
- package/dist/src/business/transfers/NotFoundException.d.ts +13 -0
- package/dist/src/business/transfers/NotFoundException.d.ts.map +1 -0
- package/dist/src/business/transfers/NotFoundException.js +16 -0
- package/dist/src/business/transfers/NotFoundException.js.map +1 -0
- package/dist/src/business/transfers/Route.d.ts +25 -0
- package/dist/src/business/transfers/Route.d.ts.map +1 -0
- package/dist/src/business/transfers/Route.js +2 -0
- package/dist/src/business/transfers/Route.js.map +1 -0
- package/dist/src/business/transfers/UnauthorizedException.d.ts +13 -0
- package/dist/src/business/transfers/UnauthorizedException.d.ts.map +1 -0
- package/dist/src/business/transfers/UnauthorizedException.js +16 -0
- package/dist/src/business/transfers/UnauthorizedException.js.map +1 -0
- package/dist/src/business/transfers/WebSocketConnection.d.ts +40 -0
- package/dist/src/business/transfers/WebSocketConnection.d.ts.map +1 -0
- package/dist/src/business/transfers/WebSocketConnection.js +2 -0
- package/dist/src/business/transfers/WebSocketConnection.js.map +1 -0
- package/dist/src/repository/R.d.ts +18 -0
- package/dist/src/repository/R.d.ts.map +1 -0
- package/dist/src/repository/R.js +18 -0
- package/dist/src/repository/R.js.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { HttpResponse } from '../../business/transfers/HttpResponse.js';
|
|
2
|
+
/**
|
|
3
|
+
* A single Server-Sent Event. `data` is sent as-is when a string, or
|
|
4
|
+
* JSON-encoded when an object. The optional fields map to the SSE
|
|
5
|
+
* wire fields (`event:`, `id:`, `retry:`).
|
|
6
|
+
*/
|
|
7
|
+
export interface ServerSentEvent {
|
|
8
|
+
/** Event payload. Strings are sent verbatim; objects are JSON-encoded. */
|
|
9
|
+
readonly data: string | object;
|
|
10
|
+
/** Named event type (`event:` field). */
|
|
11
|
+
readonly event?: string;
|
|
12
|
+
/** Event id (`id:` field) — clients echo it as `Last-Event-ID` on reconnect. */
|
|
13
|
+
readonly id?: string;
|
|
14
|
+
/** Reconnection hint in milliseconds (`retry:` field). */
|
|
15
|
+
readonly retry?: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Interaction-Layer Utility — turn an async stream of events into a
|
|
19
|
+
* `text/event-stream` {@link HttpResponse}.
|
|
20
|
+
*
|
|
21
|
+
* SSE is plain HTTP (a long-lived `GET` whose body is a stream), so it
|
|
22
|
+
* needs no plugin and works on any `RestService`. This helper does the
|
|
23
|
+
* tedious part: setting the right headers and formatting each event per
|
|
24
|
+
* the SSE wire protocol (multi-line `data:`, `event:`, `id:`, `retry:`,
|
|
25
|
+
* blank-line terminator).
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* import { RestService, SseUtils } from '@xfcfam/xf-server-http'
|
|
30
|
+
*
|
|
31
|
+
* export class ClockService extends RestService {
|
|
32
|
+
* override async init() { B.server.get('/clock', this.wrap(this.clock)) }
|
|
33
|
+
*
|
|
34
|
+
* private async clock(): Promise<HttpResponse> {
|
|
35
|
+
* async function* ticks() {
|
|
36
|
+
* while (true) {
|
|
37
|
+
* yield { event: 'tick', data: { now: Date.now() } }
|
|
38
|
+
* await new Promise((r) => setTimeout(r, 1000))
|
|
39
|
+
* }
|
|
40
|
+
* }
|
|
41
|
+
* return SseUtils.stream(ticks())
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare class SseUtils {
|
|
47
|
+
private constructor();
|
|
48
|
+
/**
|
|
49
|
+
* Build a streaming `text/event-stream` response from an async
|
|
50
|
+
* iterable of events. The stream stays open until the source is
|
|
51
|
+
* exhausted or the client disconnects.
|
|
52
|
+
*/
|
|
53
|
+
static stream(source: AsyncIterable<ServerSentEvent>, headers?: Readonly<Record<string, string>>): HttpResponse<ReadableStream<Uint8Array>>;
|
|
54
|
+
/** Format a single event into its SSE wire representation. */
|
|
55
|
+
static format(event: ServerSentEvent): string;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=SseUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SseUtils.d.ts","sourceRoot":"","sources":["../../../../src/api/utils/SseUtils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0CAA0C,CAAA;AAE5E;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IAC9B,yCAAyC;IACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,gFAAgF;IAChF,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAA;IACpB,0DAA0D;IAC1D,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qBAAa,QAAQ;IACnB,OAAO;IAEP;;;;OAIG;IACH,MAAM,CAAC,MAAM,CACX,MAAM,EAAE,aAAa,CAAC,eAAe,CAAC,EACtC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACzC,YAAY,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IA0B3C,8DAA8D;IAC9D,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM;CAS9C"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interaction-Layer Utility — turn an async stream of events into a
|
|
3
|
+
* `text/event-stream` {@link HttpResponse}.
|
|
4
|
+
*
|
|
5
|
+
* SSE is plain HTTP (a long-lived `GET` whose body is a stream), so it
|
|
6
|
+
* needs no plugin and works on any `RestService`. This helper does the
|
|
7
|
+
* tedious part: setting the right headers and formatting each event per
|
|
8
|
+
* the SSE wire protocol (multi-line `data:`, `event:`, `id:`, `retry:`,
|
|
9
|
+
* blank-line terminator).
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { RestService, SseUtils } from '@xfcfam/xf-server-http'
|
|
14
|
+
*
|
|
15
|
+
* export class ClockService extends RestService {
|
|
16
|
+
* override async init() { B.server.get('/clock', this.wrap(this.clock)) }
|
|
17
|
+
*
|
|
18
|
+
* private async clock(): Promise<HttpResponse> {
|
|
19
|
+
* async function* ticks() {
|
|
20
|
+
* while (true) {
|
|
21
|
+
* yield { event: 'tick', data: { now: Date.now() } }
|
|
22
|
+
* await new Promise((r) => setTimeout(r, 1000))
|
|
23
|
+
* }
|
|
24
|
+
* }
|
|
25
|
+
* return SseUtils.stream(ticks())
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export class SseUtils {
|
|
31
|
+
constructor() { }
|
|
32
|
+
/**
|
|
33
|
+
* Build a streaming `text/event-stream` response from an async
|
|
34
|
+
* iterable of events. The stream stays open until the source is
|
|
35
|
+
* exhausted or the client disconnects.
|
|
36
|
+
*/
|
|
37
|
+
static stream(source, headers) {
|
|
38
|
+
const encoder = new TextEncoder();
|
|
39
|
+
const body = new ReadableStream({
|
|
40
|
+
async start(controller) {
|
|
41
|
+
try {
|
|
42
|
+
for await (const event of source) {
|
|
43
|
+
controller.enqueue(encoder.encode(SseUtils.format(event)));
|
|
44
|
+
}
|
|
45
|
+
controller.close();
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
controller.error(err);
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
return {
|
|
53
|
+
status: 200,
|
|
54
|
+
headers: {
|
|
55
|
+
'content-type': 'text/event-stream',
|
|
56
|
+
'cache-control': 'no-cache',
|
|
57
|
+
'connection': 'keep-alive',
|
|
58
|
+
...headers,
|
|
59
|
+
},
|
|
60
|
+
body,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** Format a single event into its SSE wire representation. */
|
|
64
|
+
static format(event) {
|
|
65
|
+
const lines = [];
|
|
66
|
+
if (event.event !== undefined)
|
|
67
|
+
lines.push(`event: ${event.event}`);
|
|
68
|
+
if (event.id !== undefined)
|
|
69
|
+
lines.push(`id: ${event.id}`);
|
|
70
|
+
if (event.retry !== undefined)
|
|
71
|
+
lines.push(`retry: ${event.retry}`);
|
|
72
|
+
const data = typeof event.data === 'string' ? event.data : JSON.stringify(event.data);
|
|
73
|
+
for (const line of data.split('\n'))
|
|
74
|
+
lines.push(`data: ${line}`);
|
|
75
|
+
return `${lines.join('\n')}\n\n`;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=SseUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SseUtils.js","sourceRoot":"","sources":["../../../../src/api/utils/SseUtils.ts"],"names":[],"mappings":"AAkBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,OAAO,QAAQ;IACnB,gBAAuB,CAAC;IAExB;;;;OAIG;IACH,MAAM,CAAC,MAAM,CACX,MAAsC,EACtC,OAA0C;QAE1C,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAA;QACjC,MAAM,IAAI,GAAG,IAAI,cAAc,CAAa;YAC1C,KAAK,CAAC,KAAK,CAAC,UAAU;gBACpB,IAAI,CAAC;oBACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;wBACjC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;oBAC5D,CAAC;oBACD,UAAU,CAAC,KAAK,EAAE,CAAA;gBACpB,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;gBACvB,CAAC;YACH,CAAC;SACF,CAAC,CAAA;QACF,OAAO;YACL,MAAM,EAAE,GAAG;YACX,OAAO,EAAE;gBACP,cAAc,EAAE,mBAAmB;gBACnC,eAAe,EAAE,UAAU;gBAC3B,YAAY,EAAE,YAAY;gBAC1B,GAAG,OAAO;aACX;YACD,IAAI;SACL,CAAA;IACH,CAAC;IAED,8DAA8D;IAC9D,MAAM,CAAC,MAAM,CAAC,KAAsB;QAClC,MAAM,KAAK,GAAa,EAAE,CAAA;QAC1B,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,UAAU,KAAK,CAAC,KAAK,EAAE,CAAC,CAAA;QAClE,IAAI,KAAK,CAAC,EAAE,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,OAAO,KAAK,CAAC,EAAE,EAAE,CAAC,CAAA;QACzD,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,UAAU,KAAK,CAAC,KAAK,EAAE,CAAC,CAAA;QAClE,MAAM,IAAI,GAAG,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACrF,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAA;QAChE,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAA;IAClC,CAAC;CACF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Business Layer Injection — placeholder.
|
|
3
|
+
*
|
|
4
|
+
* `B` is the canonical injection of the Business Layer. `@xfcfam/xf-server`
|
|
5
|
+
* is a library that contributes Generalizations and Transfer objects to
|
|
6
|
+
* the Interaction Layer ( `ObjectRestService`,
|
|
7
|
+
* `HttpServerBusiness`); it does not own any Logical of this layer, so
|
|
8
|
+
* its own `B` declares no static slots. The class is kept structurally
|
|
9
|
+
* complete (private constructor + empty `init` / `terminate`) so the
|
|
10
|
+
* artefact passes XF validation. It is NOT exported from the package —
|
|
11
|
+
* consumers import `B` from their own artefact.
|
|
12
|
+
*/
|
|
13
|
+
export declare class B {
|
|
14
|
+
private constructor();
|
|
15
|
+
static init(): Promise<void>;
|
|
16
|
+
static terminate(): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=B.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"B.d.ts","sourceRoot":"","sources":["../../../src/business/B.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,qBAAa,CAAC;IACZ,OAAO;WACM,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;WACrB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CACxC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Business Layer Injection — placeholder.
|
|
3
|
+
*
|
|
4
|
+
* `B` is the canonical injection of the Business Layer. `@xfcfam/xf-server`
|
|
5
|
+
* is a library that contributes Generalizations and Transfer objects to
|
|
6
|
+
* the Interaction Layer ( `ObjectRestService`,
|
|
7
|
+
* `HttpServerBusiness`); it does not own any Logical of this layer, so
|
|
8
|
+
* its own `B` declares no static slots. The class is kept structurally
|
|
9
|
+
* complete (private constructor + empty `init` / `terminate`) so the
|
|
10
|
+
* artefact passes XF validation. It is NOT exported from the package —
|
|
11
|
+
* consumers import `B` from their own artefact.
|
|
12
|
+
*/
|
|
13
|
+
export class B {
|
|
14
|
+
constructor() { }
|
|
15
|
+
static async init() { }
|
|
16
|
+
static async terminate() { }
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=B.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"B.js","sourceRoot":"","sources":["../../../src/business/B.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,CAAC;IACZ,gBAAuB,CAAC;IACxB,MAAM,CAAC,KAAK,CAAC,IAAI,KAAmB,CAAC;IACrC,MAAM,CAAC,KAAK,CAAC,SAAS,KAAmB,CAAC;CAC3C"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { ServerBusiness, type ServerState } from '@xfcfam/xf-server';
|
|
2
|
+
import { type FastifyInstance } from 'fastify';
|
|
3
|
+
import type { HttpRequest } from '../transfers/HttpRequest.js';
|
|
4
|
+
import type { HttpResponse } from '../transfers/HttpResponse.js';
|
|
5
|
+
import type { HttpMethod } from '../transfers/HttpMethod.js';
|
|
6
|
+
import type { HttpAddress, HttpHandler } from '../transfers/Route.js';
|
|
7
|
+
import type { WebSocketHandler } from '../transfers/WebSocketConnection.js';
|
|
8
|
+
import type { GraphQLConfig } from '../transfers/GraphQLConfig.js';
|
|
9
|
+
/** Internal record of a WebSocket endpoint pushed before `listen()`. */
|
|
10
|
+
interface WsRoute {
|
|
11
|
+
readonly path: string;
|
|
12
|
+
readonly handler: WebSocketHandler;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Multipart upload configuration. Forwarded verbatim to
|
|
16
|
+
* `@fastify/multipart` (consult its docs for the full list). The most
|
|
17
|
+
* common knobs:
|
|
18
|
+
*
|
|
19
|
+
* - `maxFileSize`: per-file size limit in bytes (Fastify default 1 MiB).
|
|
20
|
+
* - `maxFiles`: maximum number of file parts per request.
|
|
21
|
+
* - `maxFields`: maximum number of non-file fields.
|
|
22
|
+
* - `maxFieldsSize`: total size limit for non-file fields.
|
|
23
|
+
*/
|
|
24
|
+
export interface MultipartConfig {
|
|
25
|
+
readonly maxFileSize?: number;
|
|
26
|
+
readonly maxFiles?: number;
|
|
27
|
+
readonly maxFields?: number;
|
|
28
|
+
readonly maxFieldsSize?: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Configuration accepted by {@link HttpServerBusiness}'s constructor.
|
|
32
|
+
*/
|
|
33
|
+
export interface ServerOptions {
|
|
34
|
+
/** TCP port to bind. */
|
|
35
|
+
readonly port: number;
|
|
36
|
+
/** Host to bind. Default `'0.0.0.0'`. */
|
|
37
|
+
readonly host?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Opt-in `multipart/form-data` support. Pass `true` for defaults or
|
|
40
|
+
* a config object to tune limits.
|
|
41
|
+
*
|
|
42
|
+
* When enabled, the server activates multipart handling at `listen()`
|
|
43
|
+
* time and, for any request whose `Content-Type` is
|
|
44
|
+
* `multipart/form-data`, populates `req.body` with a
|
|
45
|
+
* `MultipartPart[]`. All underlying machinery is shipped as part
|
|
46
|
+
* of xf-server-http — the consumer does not install or import any
|
|
47
|
+
* extra package.
|
|
48
|
+
*/
|
|
49
|
+
readonly multipart?: boolean | MultipartConfig;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Concrete server state: the abstract route registry plus the Fastify
|
|
53
|
+
* instance and the bind options.
|
|
54
|
+
*/
|
|
55
|
+
interface HttpServerState extends ServerState<HttpAddress, HttpRequest, HttpResponse> {
|
|
56
|
+
readonly options: ServerOptions;
|
|
57
|
+
/** The running Fastify instance; `undefined` before `listen()` and after `close()`. */
|
|
58
|
+
fastify: FastifyInstance | undefined;
|
|
59
|
+
/** WebSocket endpoints pushed via `ws()` before `listen()`. */
|
|
60
|
+
readonly wsRoutes: WsRoute[];
|
|
61
|
+
/** GraphQL endpoint pushed via `graphql()`, if any. */
|
|
62
|
+
graphql: GraphQLConfig | undefined;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Business-Layer Generalization for the artefact-level HTTP server
|
|
66
|
+
* orchestrator — the Fastify implementation of the transport-agnostic
|
|
67
|
+
* {@link ServerBusiness} contract from `@xfcfam/xf-server`.
|
|
68
|
+
*
|
|
69
|
+
* It is **technology-aware** (Fastify, HTTP) by design: the Business
|
|
70
|
+
* Layer in XF is the correct home for infrastructure concerns that are
|
|
71
|
+
* not domain rules — the HTTP server is infrastructure, not domain
|
|
72
|
+
* logic. The route registry and the request pipeline come from the
|
|
73
|
+
* core; this class supplies the HTTP address scheme (`{ method, path }`),
|
|
74
|
+
* the Fastify lifecycle (`listen` / `close`), body collection
|
|
75
|
+
* (including multipart) and the error → HTTP-status mapping.
|
|
76
|
+
*
|
|
77
|
+
* **Registration model — push, not pull.** Interaction Services register
|
|
78
|
+
* their routes by calling `B.server.get(path, handler)` (or `post`,
|
|
79
|
+
* `put`, `patch`, `del`, `call`) from within their own `init()`. The
|
|
80
|
+
* server MUST be created and available on `B` before `A.init()` runs;
|
|
81
|
+
* `listen()` is called by the start-point AFTER all services have
|
|
82
|
+
* registered.
|
|
83
|
+
*
|
|
84
|
+
* **Handler contract.** Handlers are `HttpHandler` functions
|
|
85
|
+
* (`(req: HttpRequest) => Promise<HttpResponse> | HttpResponse`). The
|
|
86
|
+
* server calls them with an `HttpRequest` whose `body` is the raw
|
|
87
|
+
* bytes/stream (or a `MultipartPart[]` for multipart requests).
|
|
88
|
+
* Serialisation (object → bytes) and parsing (bytes → object) are the
|
|
89
|
+
* Interaction Layer's responsibility — see `ObjectRestService.object()`.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* // business/logic/AppServerBusiness.ts
|
|
94
|
+
* import { HttpServerBusiness, type HttpRequest } from '@xfcfam/xf-server-http'
|
|
95
|
+
*
|
|
96
|
+
* export class AppServerBusiness extends HttpServerBusiness {
|
|
97
|
+
* constructor() {
|
|
98
|
+
* super({ port: Number.parseInt(process.env['PORT'] ?? '3000', 10) })
|
|
99
|
+
* }
|
|
100
|
+
*
|
|
101
|
+
* override async onRequest(req: HttpRequest): Promise<HttpRequest> {
|
|
102
|
+
* console.log(`[server] → ${req.method} ${req.path}`)
|
|
103
|
+
* return req
|
|
104
|
+
* }
|
|
105
|
+
* }
|
|
106
|
+
*
|
|
107
|
+
* // business/B.ts
|
|
108
|
+
* export class B {
|
|
109
|
+
* private constructor() {}
|
|
110
|
+
* static readonly server = new AppServerBusiness()
|
|
111
|
+
* static async init() { await B.server.init() }
|
|
112
|
+
* static async terminate() { await B.server.terminate() }
|
|
113
|
+
* }
|
|
114
|
+
*
|
|
115
|
+
* // main.ts (start-point): once the XF element has bootstrapped the
|
|
116
|
+
* // layers R → B → A and the services have pushed their routes, start
|
|
117
|
+
* // the transport explicitly:
|
|
118
|
+
* await B.server.listen() // start Fastify after all routes are in
|
|
119
|
+
* // ...and on shutdown, before the XF element tears the layers down:
|
|
120
|
+
* await B.server.close()
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
export declare abstract class HttpServerBusiness extends ServerBusiness<HttpAddress, HttpRequest, HttpResponse, HttpServerState> {
|
|
124
|
+
constructor(options: ServerOptions);
|
|
125
|
+
/** Register a GET endpoint. */
|
|
126
|
+
get(path: string, handler: HttpHandler): void;
|
|
127
|
+
/** Register a POST endpoint. */
|
|
128
|
+
post(path: string, handler: HttpHandler): void;
|
|
129
|
+
/** Register a PUT endpoint. */
|
|
130
|
+
put(path: string, handler: HttpHandler): void;
|
|
131
|
+
/** Register a PATCH endpoint. */
|
|
132
|
+
patch(path: string, handler: HttpHandler): void;
|
|
133
|
+
/** Register a DELETE endpoint. */
|
|
134
|
+
del(path: string, handler: HttpHandler): void;
|
|
135
|
+
/**
|
|
136
|
+
* Register an endpoint for an arbitrary HTTP method. Used for
|
|
137
|
+
* `HEAD`, `OPTIONS`, or any verb not covered by the convenience
|
|
138
|
+
* helpers.
|
|
139
|
+
*/
|
|
140
|
+
call(method: HttpMethod, path: string, handler: HttpHandler): void;
|
|
141
|
+
/**
|
|
142
|
+
* Register a WebSocket endpoint. The handler receives a
|
|
143
|
+
* {@link WebSocketConnection} once the client upgrade completes. The
|
|
144
|
+
* WebSocket plugin runs on the same Fastify instance and port as the
|
|
145
|
+
* REST routes; like every registration, call this before `listen()`.
|
|
146
|
+
*/
|
|
147
|
+
ws(path: string, handler: WebSocketHandler): void;
|
|
148
|
+
/**
|
|
149
|
+
* Register a GraphQL endpoint (schema + resolvers). The GraphQL
|
|
150
|
+
* engine (Mercurius) is mounted on the shared Fastify instance at
|
|
151
|
+
* `config.path` (default `/graphql`). At most one GraphQL endpoint per
|
|
152
|
+
* server; a later call replaces the earlier config.
|
|
153
|
+
*/
|
|
154
|
+
graphql(config: GraphQLConfig): void;
|
|
155
|
+
/**
|
|
156
|
+
* Start accepting requests. Creates the Fastify instance, registers
|
|
157
|
+
* multipart support if configured, mounts every route that has been
|
|
158
|
+
* pushed so far, and begins listening.
|
|
159
|
+
*
|
|
160
|
+
* Call this from the start-point AFTER the Interaction layer has
|
|
161
|
+
* registered all routes — no new routes should be pushed after this
|
|
162
|
+
* point.
|
|
163
|
+
*/
|
|
164
|
+
listen(): Promise<void>;
|
|
165
|
+
/**
|
|
166
|
+
* Stop accepting requests and release the Fastify instance. Waits
|
|
167
|
+
* for in-flight requests to complete before resolving.
|
|
168
|
+
*/
|
|
169
|
+
close(): Promise<void>;
|
|
170
|
+
/**
|
|
171
|
+
* Get the underlying Fastify instance. Throws if `listen()` hasn't
|
|
172
|
+
* run. Exposed so protocol extensions (WebSocket, GraphQL) can
|
|
173
|
+
* register their plugins on the same instance.
|
|
174
|
+
*/
|
|
175
|
+
protected fastifyInstance(): FastifyInstance;
|
|
176
|
+
private adapter;
|
|
177
|
+
private static request;
|
|
178
|
+
private static collectMultipart;
|
|
179
|
+
private static collectNodeStream;
|
|
180
|
+
private static registerMultipart;
|
|
181
|
+
private static registerWebSocket;
|
|
182
|
+
private static adaptSocket;
|
|
183
|
+
private static toFrame;
|
|
184
|
+
private static registerGraphQL;
|
|
185
|
+
private static sendResponse;
|
|
186
|
+
private static errorToResponse;
|
|
187
|
+
private static isReadableStream;
|
|
188
|
+
}
|
|
189
|
+
export {};
|
|
190
|
+
//# sourceMappingURL=HttpServerBusiness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HttpServerBusiness.d.ts","sourceRoot":"","sources":["../../../../src/business/general/HttpServerBusiness.ts"],"names":[],"mappings":"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"}
|