@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.
Files changed (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +240 -0
  3. package/dist/index.d.ts +63 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +55 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/src/api/A.d.ts +18 -0
  8. package/dist/src/api/A.d.ts.map +1 -0
  9. package/dist/src/api/A.js +18 -0
  10. package/dist/src/api/A.js.map +1 -0
  11. package/dist/src/api/general/GraphQLService.d.ts +48 -0
  12. package/dist/src/api/general/GraphQLService.d.ts.map +1 -0
  13. package/dist/src/api/general/GraphQLService.js +43 -0
  14. package/dist/src/api/general/GraphQLService.js.map +1 -0
  15. package/dist/src/api/general/ObjectRestService.d.ts +196 -0
  16. package/dist/src/api/general/ObjectRestService.d.ts.map +1 -0
  17. package/dist/src/api/general/ObjectRestService.js +289 -0
  18. package/dist/src/api/general/ObjectRestService.js.map +1 -0
  19. package/dist/src/api/general/RestService.d.ts +62 -0
  20. package/dist/src/api/general/RestService.d.ts.map +1 -0
  21. package/dist/src/api/general/RestService.js +75 -0
  22. package/dist/src/api/general/RestService.js.map +1 -0
  23. package/dist/src/api/general/WebSocketService.d.ts +42 -0
  24. package/dist/src/api/general/WebSocketService.d.ts.map +1 -0
  25. package/dist/src/api/general/WebSocketService.js +45 -0
  26. package/dist/src/api/general/WebSocketService.js.map +1 -0
  27. package/dist/src/api/utils/FileResponseUtils.d.ts +66 -0
  28. package/dist/src/api/utils/FileResponseUtils.d.ts.map +1 -0
  29. package/dist/src/api/utils/FileResponseUtils.js +82 -0
  30. package/dist/src/api/utils/FileResponseUtils.js.map +1 -0
  31. package/dist/src/api/utils/HttpStatusUtils.d.ts +36 -0
  32. package/dist/src/api/utils/HttpStatusUtils.d.ts.map +1 -0
  33. package/dist/src/api/utils/HttpStatusUtils.js +40 -0
  34. package/dist/src/api/utils/HttpStatusUtils.js.map +1 -0
  35. package/dist/src/api/utils/ResponseUtils.d.ts +61 -0
  36. package/dist/src/api/utils/ResponseUtils.d.ts.map +1 -0
  37. package/dist/src/api/utils/ResponseUtils.js +81 -0
  38. package/dist/src/api/utils/ResponseUtils.js.map +1 -0
  39. package/dist/src/api/utils/SchemaValidatorUtils.d.ts +48 -0
  40. package/dist/src/api/utils/SchemaValidatorUtils.d.ts.map +1 -0
  41. package/dist/src/api/utils/SchemaValidatorUtils.js +52 -0
  42. package/dist/src/api/utils/SchemaValidatorUtils.js.map +1 -0
  43. package/dist/src/api/utils/SseUtils.d.ts +57 -0
  44. package/dist/src/api/utils/SseUtils.d.ts.map +1 -0
  45. package/dist/src/api/utils/SseUtils.js +78 -0
  46. package/dist/src/api/utils/SseUtils.js.map +1 -0
  47. package/dist/src/business/B.d.ts +18 -0
  48. package/dist/src/business/B.d.ts.map +1 -0
  49. package/dist/src/business/B.js +18 -0
  50. package/dist/src/business/B.js.map +1 -0
  51. package/dist/src/business/general/HttpServerBusiness.d.ts +190 -0
  52. package/dist/src/business/general/HttpServerBusiness.d.ts.map +1 -0
  53. package/dist/src/business/general/HttpServerBusiness.js +364 -0
  54. package/dist/src/business/general/HttpServerBusiness.js.map +1 -0
  55. package/dist/src/business/transfers/BadRequestException.d.ts +13 -0
  56. package/dist/src/business/transfers/BadRequestException.d.ts.map +1 -0
  57. package/dist/src/business/transfers/BadRequestException.js +16 -0
  58. package/dist/src/business/transfers/BadRequestException.js.map +1 -0
  59. package/dist/src/business/transfers/ForbiddenException.d.ts +13 -0
  60. package/dist/src/business/transfers/ForbiddenException.d.ts.map +1 -0
  61. package/dist/src/business/transfers/ForbiddenException.js +16 -0
  62. package/dist/src/business/transfers/ForbiddenException.js.map +1 -0
  63. package/dist/src/business/transfers/GraphQLConfig.d.ts +25 -0
  64. package/dist/src/business/transfers/GraphQLConfig.d.ts.map +1 -0
  65. package/dist/src/business/transfers/GraphQLConfig.js +2 -0
  66. package/dist/src/business/transfers/GraphQLConfig.js.map +1 -0
  67. package/dist/src/business/transfers/HttpException.d.ts +23 -0
  68. package/dist/src/business/transfers/HttpException.d.ts.map +1 -0
  69. package/dist/src/business/transfers/HttpException.js +27 -0
  70. package/dist/src/business/transfers/HttpException.js.map +1 -0
  71. package/dist/src/business/transfers/HttpMethod.d.ts +7 -0
  72. package/dist/src/business/transfers/HttpMethod.d.ts.map +1 -0
  73. package/dist/src/business/transfers/HttpMethod.js +2 -0
  74. package/dist/src/business/transfers/HttpMethod.js.map +1 -0
  75. package/dist/src/business/transfers/HttpRequest.d.ts +35 -0
  76. package/dist/src/business/transfers/HttpRequest.d.ts.map +1 -0
  77. package/dist/src/business/transfers/HttpRequest.js +2 -0
  78. package/dist/src/business/transfers/HttpRequest.js.map +1 -0
  79. package/dist/src/business/transfers/HttpResponse.d.ts +28 -0
  80. package/dist/src/business/transfers/HttpResponse.d.ts.map +1 -0
  81. package/dist/src/business/transfers/HttpResponse.js +2 -0
  82. package/dist/src/business/transfers/HttpResponse.js.map +1 -0
  83. package/dist/src/business/transfers/InternalServerException.d.ts +13 -0
  84. package/dist/src/business/transfers/InternalServerException.d.ts.map +1 -0
  85. package/dist/src/business/transfers/InternalServerException.js +16 -0
  86. package/dist/src/business/transfers/InternalServerException.js.map +1 -0
  87. package/dist/src/business/transfers/MultipartPart.d.ts +38 -0
  88. package/dist/src/business/transfers/MultipartPart.d.ts.map +1 -0
  89. package/dist/src/business/transfers/MultipartPart.js +2 -0
  90. package/dist/src/business/transfers/MultipartPart.js.map +1 -0
  91. package/dist/src/business/transfers/NotFoundException.d.ts +13 -0
  92. package/dist/src/business/transfers/NotFoundException.d.ts.map +1 -0
  93. package/dist/src/business/transfers/NotFoundException.js +16 -0
  94. package/dist/src/business/transfers/NotFoundException.js.map +1 -0
  95. package/dist/src/business/transfers/Route.d.ts +25 -0
  96. package/dist/src/business/transfers/Route.d.ts.map +1 -0
  97. package/dist/src/business/transfers/Route.js +2 -0
  98. package/dist/src/business/transfers/Route.js.map +1 -0
  99. package/dist/src/business/transfers/UnauthorizedException.d.ts +13 -0
  100. package/dist/src/business/transfers/UnauthorizedException.d.ts.map +1 -0
  101. package/dist/src/business/transfers/UnauthorizedException.js +16 -0
  102. package/dist/src/business/transfers/UnauthorizedException.js.map +1 -0
  103. package/dist/src/business/transfers/WebSocketConnection.d.ts +40 -0
  104. package/dist/src/business/transfers/WebSocketConnection.d.ts.map +1 -0
  105. package/dist/src/business/transfers/WebSocketConnection.js +2 -0
  106. package/dist/src/business/transfers/WebSocketConnection.js.map +1 -0
  107. package/dist/src/repository/R.d.ts +18 -0
  108. package/dist/src/repository/R.d.ts.map +1 -0
  109. package/dist/src/repository/R.js +18 -0
  110. package/dist/src/repository/R.js.map +1 -0
  111. package/package.json +62 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Israel Sanjurjo and the XF contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,240 @@
1
+ # `@xfcfam/xf-server-http`
2
+
3
+ HTTP transport for the **XF Architecture Model** — the [Fastify](https://fastify.dev)
4
+ implementation of the transport-agnostic
5
+ [`@xfcfam/xf-server`](../xf-server) contract. One server, one port,
6
+ four entry-point shapes: **REST**, **WebSocket**, **SSE**, and **GraphQL**.
7
+
8
+ The package spans two layers, by design:
9
+
10
+ - **`HttpServerBusiness`** (Business Layer) owns the transport lifecycle
11
+ (Fastify) and the route registry. Starting a server is infrastructure,
12
+ not a protocol detail — in XF that belongs to the Business Layer. It
13
+ lives on `B` (e.g. `B.server`).
14
+ - **`RestService` / `ObjectRestService` / `WebSocketService` /
15
+ `GraphQLService`** (Interaction Layer) are the entry points. Each
16
+ registers itself on `B.server` from its own `init()` (the push model).
17
+
18
+ Sister of `@xfcfam/xf-rest` (outbound HTTP — your app calling someone):
19
+ `xf-server-http` is **inbound HTTP** — someone calling your app.
20
+
21
+ ## Install
22
+
23
+ ```bash
24
+ pnpm add @xfcfam/xf @xfcfam/xf-server @xfcfam/xf-server-http
25
+ ```
26
+
27
+ Fastify, `@fastify/multipart`, `@fastify/websocket`, `mercurius` and the
28
+ rest are bundled as direct dependencies and **lazy-loaded** — you pay for
29
+ multipart / WebSocket / GraphQL only if you use them. The consumer never
30
+ installs or imports the underlying engines.
31
+
32
+ ## What ships here
33
+
34
+ | Component | Layer · type | Purpose |
35
+ | --- | --- | --- |
36
+ | `HttpServerBusiness` | Business · Generalization | Server orchestrator. Owns the Fastify lifecycle + route registry. Routes pushed via `B.server.get/post/…`, `B.server.ws(...)`, `B.server.graphql(...)`. Start-point calls `listen()` / `close()`. |
37
+ | `RestService` | Interaction · Generalization | Raw-body endpoints (streams / bytes). `wrap(handler)` for the per-service pipeline. |
38
+ | `ObjectRestService` | Interaction · Generalization | Auto parse / serialise by `Content-Type` via `object(handler)`. JSON built-in; XML/CSV/YAML pluggable; developer-chosen date handling (`reviveDates`, `formatDate`). |
39
+ | `WebSocketService` | Interaction · Generalization | Bidirectional channels. Registers connection handlers via `B.server.ws(path, …)`. |
40
+ | `GraphQLService` | Interaction · Generalization | GraphQL endpoint (Mercurius). Supplies schema + resolvers via `B.server.graphql(...)`. |
41
+ | `SseUtils` | Interaction · Utility | Build a `text/event-stream` response from an async event source. |
42
+ | `HttpRequest`, `HttpResponse`, `HttpAddress`, `HttpHandler`, `MultipartPart`, `WebSocketConnection`, `GraphQLConfig` | Business · Transfer | The data crossing the wire. |
43
+ | `HttpException` + 5 typed subclasses | Business · Transfer | Throw inside a handler; the server maps it to the right HTTP status. |
44
+ | `HttpStatusUtils`, `SchemaValidatorUtils`, `FileResponseUtils`, `ResponseUtils` | Interaction · Utility | Status constants, duck-typed validation, file/stream helpers, body-shape classifiers. |
45
+
46
+ ## Quick start (object REST)
47
+
48
+ ```typescript
49
+ import {
50
+ ObjectRestService, HttpStatusUtils, NotFoundException, BadRequestException,
51
+ type HttpRequest, type HttpResponse,
52
+ } from '@xfcfam/xf-server-http'
53
+ import { B } from '../../../business/B.js'
54
+
55
+ export class UsersRestService extends ObjectRestService {
56
+ override async init(): Promise<void> {
57
+ B.server.get('/users', this.object(this.list))
58
+ B.server.get('/users/:id', this.object(this.getOne))
59
+ B.server.post('/users', this.object(this.create))
60
+ B.server.del('/users/:id', this.object(this.remove))
61
+ }
62
+
63
+ private async getOne(req: HttpRequest): Promise<HttpResponse> {
64
+ const user = await B.user.findById(req.params['id']!)
65
+ if (user === null) throw new NotFoundException(`User ${req.params['id']}`)
66
+ return { status: HttpStatusUtils.OK, body: user }
67
+ }
68
+ // create / list / remove …
69
+ }
70
+ ```
71
+
72
+ Route helpers on `B.server`: `get`, `post`, `put`, `patch`, `del`, and
73
+ `call(method, path, handler)` for any other verb.
74
+
75
+ ## Server orchestration
76
+
77
+ The server is a **Business** component (`HttpServerBusiness`) declared on
78
+ `B`. Concrete subclasses set the port and override the global hooks:
79
+
80
+ ```typescript
81
+ import { HttpServerBusiness, ResponseUtils, type HttpRequest, type HttpResponse } from '@xfcfam/xf-server-http'
82
+
83
+ export class AppServerBusiness extends HttpServerBusiness {
84
+ constructor() { super({ port: Number.parseInt(process.env['PORT'] ?? '3000', 10) }) }
85
+
86
+ override async onRequest(req: HttpRequest): Promise<HttpRequest> {
87
+ console.log(`${req.method} ${req.path}`); return req
88
+ }
89
+ override async onResponse(_req: HttpRequest, res: HttpResponse): Promise<HttpResponse> {
90
+ if (!ResponseUtils.isObject(res.body)) return res // streams/files pass through
91
+ return { ...res, body: { code: '0', description: 'OK', data: res.body } }
92
+ }
93
+ }
94
+ ```
95
+
96
+ ### Lifecycle and initialisation order
97
+
98
+ `HttpServerBusiness.init()` is a **no-op** — it does not start listening.
99
+ Services register their routes during `A.init()` (after `B.init()`); the
100
+ start-point opens the socket **explicitly** once every route is in:
101
+
102
+ ```typescript
103
+ // main.ts — start-point
104
+ await XF.init() // R → B → A; services push routes on B.server
105
+ await B.server.listen() // start Fastify after all routes are in
106
+ // …on shutdown:
107
+ await B.server.close() // drain in-flight requests
108
+ await XF.terminate() // A → B → R
109
+ ```
110
+
111
+ Pushing a route after `listen()` raises an error (Fastify freezes its
112
+ routing table once listening) — hence the **push-then-start** ordering.
113
+
114
+ ## WebSocket
115
+
116
+ A bidirectional channel on the same Fastify instance and port. Extend
117
+ `WebSocketService` and register a connection handler:
118
+
119
+ ```typescript
120
+ import { WebSocketService, type WebSocketConnection } from '@xfcfam/xf-server-http'
121
+ import { B } from '../../../business/B.js'
122
+
123
+ export class ChatService extends WebSocketService {
124
+ override async init(): Promise<void> {
125
+ B.server.ws('/chat', this.accept(this.onConnection))
126
+ }
127
+ private onConnection(conn: WebSocketConnection): void {
128
+ conn.send('welcome')
129
+ conn.onMessage((data) => conn.send(`echo: ${String(data)}`))
130
+ conn.onClose(() => {})
131
+ }
132
+ }
133
+ ```
134
+
135
+ ## Server-Sent Events
136
+
137
+ SSE is plain HTTP (a long-lived `GET` whose body is a stream), so it is
138
+ just a `RestService` route — no plugin. `SseUtils` formats the events:
139
+
140
+ ```typescript
141
+ import { RestService, SseUtils, type HttpResponse, type ServerSentEvent } from '@xfcfam/xf-server-http'
142
+
143
+ export class ClockService extends RestService {
144
+ override async init() { B.server.get('/clock', this.wrap(this.clock)) }
145
+ private async clock(): Promise<HttpResponse> {
146
+ async function* ticks(): AsyncGenerator<ServerSentEvent> {
147
+ for (let n = 0; ; n++) {
148
+ yield { event: 'tick', id: String(n), data: { n, at: new Date().toISOString() } }
149
+ await new Promise((r) => setTimeout(r, 1000))
150
+ }
151
+ }
152
+ return SseUtils.stream(ticks())
153
+ }
154
+ }
155
+ ```
156
+
157
+ ## GraphQL
158
+
159
+ A GraphQL API (Mercurius) on the shared instance at `/graphql`. Supply
160
+ schema + resolvers; the resolvers delegate to Business like REST handlers:
161
+
162
+ ```typescript
163
+ import { GraphQLService, type GraphQLConfig } from '@xfcfam/xf-server-http'
164
+ import { B } from '../../../business/B.js'
165
+
166
+ export class ApiGraphQLService extends GraphQLService {
167
+ override async init() { B.server.graphql(this.config()) }
168
+ protected override config(): GraphQLConfig {
169
+ return {
170
+ schema: `type User { id: ID! name: String! } type Query { users: [User!]! }`,
171
+ resolvers: { Query: { users: () => B.user.list() } },
172
+ graphiql: true,
173
+ }
174
+ }
175
+ }
176
+ ```
177
+
178
+ ## Date handling (object REST)
179
+
180
+ `ObjectRestService` lets the developer decide how dates cross the wire,
181
+ both directions, with no extra dependency.
182
+
183
+ - **Serialising** — a `Date` becomes ISO-8601 by default. Pass
184
+ `formatDate` to choose any format; applied to every `Date` in the body
185
+ (nested objects and arrays included):
186
+ ```typescript
187
+ super({ formatDate: (d) => d.toISOString().slice(0, 10) }) // YYYY-MM-DD
188
+ ```
189
+ - **Parsing** — set `reviveDates: true` so the JSON parser turns ISO date
190
+ strings back into real `Date` objects. The reviver is also exposed:
191
+ `JSON.parse(text, ObjectRestService.dateReviver)`.
192
+
193
+ ## Multipart uploads (opt-in)
194
+
195
+ Enable on the server with one option — nothing else to install:
196
+
197
+ ```typescript
198
+ super({ port: 3000, multipart: { maxFileSize: 10 * 1024 * 1024, maxFiles: 5 } })
199
+ ```
200
+
201
+ Handlers then see `req.body` as `MultipartPart[]`. The parser is
202
+ lazy-loaded at `listen()` time (only paid for if you opt in).
203
+
204
+ ## Pipeline order
205
+
206
+ Per request, top to bottom:
207
+
208
+ 1. **`HttpServerBusiness.onRequest`** — global pre-processing.
209
+ 2. **`ObjectRestService` parse** — `object(handler)` auto-parses the body.
210
+ 3. **`RestService.onRequest`** — per-service pre-processing.
211
+ 4. **The matched route handler**.
212
+ 5. **`RestService.onResponse`** — per-service post-processing (semantic body).
213
+ 6. **`HttpServerBusiness.onResponse`** — global post-processing (envelopes).
214
+ 7. **`ObjectRestService` serialise** — object → bytes, last, honouring `formatDate`.
215
+
216
+ `onResponse` runs **before** serialisation so envelope policies inspect
217
+ the original payload, not an already-encoded `Uint8Array`. `ResponseUtils`
218
+ exposes four disjoint body classifiers — `isStream`, `isBinary`,
219
+ `isTextual`, `isObject` — for "object responses only" policies.
220
+
221
+ ### Error chain
222
+
223
+ When step 3–5 throws: `RestService.onError` → `HttpServerBusiness.onError`
224
+ → default (an `HttpException` maps to its `status`/`body`; otherwise
225
+ `500`).
226
+
227
+ ## Full example
228
+
229
+ See [`examples/03-rest-server`](../../examples/03-rest-server) for a
230
+ complete artefact: `HttpServerBusiness` on `B`; REST, SSE, WebSocket and
231
+ GraphQL services pushing to the one server; multipart uploads; streaming
232
+ downloads; service- and server-level interceptors; graceful shutdown.
233
+
234
+ ```bash
235
+ pnpm --filter @xfcfam-examples/03-rest-server start
236
+ ```
237
+
238
+ ## License
239
+
240
+ MIT.
@@ -0,0 +1,63 @@
1
+ /**
2
+ * `@xfcfam/xf-server-http` — HTTP transport for the XF Architecture
3
+ * Model (CFAM). The Fastify implementation of the `@xfcfam/xf-server`
4
+ * contract.
5
+ *
6
+ * Exposes:
7
+ *
8
+ * - **{@link HttpServerBusiness}** — Business-Layer orchestrator. Owns
9
+ * the Fastify lifecycle and the route registry. Concrete subclasses
10
+ * live in the Business Layer; services push routes to it from their
11
+ * own `init()` via `B.server.get(path, handler)`.
12
+ *
13
+ * - **{@link RestService}** — Interaction Generalization for raw-body
14
+ * endpoints (streams or bytes). Provides `wrap(handler)`.
15
+ *
16
+ * - **{@link ObjectRestService}** — Same protocol, adds automatic
17
+ * request parsing and response serialisation by `Content-Type` via
18
+ * `object(handler)`. JSON built-in; XML/CSV/YAML pluggable;
19
+ * developer-chosen date handling.
20
+ *
21
+ * - **Transfers**: {@link HttpRequest}, {@link HttpResponse},
22
+ * {@link HttpAddress}, {@link HttpHandler}, {@link HttpMethod},
23
+ * {@link MultipartPart}.
24
+ *
25
+ * - **Exceptions**: {@link HttpException} (base) +
26
+ * `BadRequestException`, `UnauthorizedException`,
27
+ * `ForbiddenException`, `NotFoundException`,
28
+ * `InternalServerException`.
29
+ *
30
+ * - **Utilities**: {@link HttpStatusUtils}, {@link SchemaValidatorUtils},
31
+ * {@link FileResponseUtils}, {@link ResponseUtils}.
32
+ *
33
+ * See https://xfcfam.org for the full XF specification.
34
+ */
35
+ export { HttpServerBusiness } from './src/business/general/HttpServerBusiness.js';
36
+ export type { ServerOptions, MultipartConfig } from './src/business/general/HttpServerBusiness.js';
37
+ export { RestService } from './src/api/general/RestService.js';
38
+ export { ObjectRestService } from './src/api/general/ObjectRestService.js';
39
+ export type { ObjectRestOptions, BodyParser, BodySerializer, } from './src/api/general/ObjectRestService.js';
40
+ export { WebSocketService } from './src/api/general/WebSocketService.js';
41
+ export { GraphQLService } from './src/api/general/GraphQLService.js';
42
+ export type { HttpMethod } from './src/business/transfers/HttpMethod.js';
43
+ export type { HttpRequest } from './src/business/transfers/HttpRequest.js';
44
+ export type { HttpResponse } from './src/business/transfers/HttpResponse.js';
45
+ export type { HttpAddress, HttpHandler } from './src/business/transfers/Route.js';
46
+ export type { MultipartPart } from './src/business/transfers/MultipartPart.js';
47
+ export type { WebSocketConnection, WebSocketHandler } from './src/business/transfers/WebSocketConnection.js';
48
+ export type { GraphQLConfig } from './src/business/transfers/GraphQLConfig.js';
49
+ export { HttpException } from './src/business/transfers/HttpException.js';
50
+ export { BadRequestException } from './src/business/transfers/BadRequestException.js';
51
+ export { UnauthorizedException } from './src/business/transfers/UnauthorizedException.js';
52
+ export { ForbiddenException } from './src/business/transfers/ForbiddenException.js';
53
+ export { NotFoundException } from './src/business/transfers/NotFoundException.js';
54
+ export { InternalServerException } from './src/business/transfers/InternalServerException.js';
55
+ export { HttpStatusUtils } from './src/api/utils/HttpStatusUtils.js';
56
+ export { SchemaValidatorUtils } from './src/api/utils/SchemaValidatorUtils.js';
57
+ export type { Schema, SchemaParseResult } from './src/api/utils/SchemaValidatorUtils.js';
58
+ export { FileResponseUtils } from './src/api/utils/FileResponseUtils.js';
59
+ export type { FileBody } from './src/api/utils/FileResponseUtils.js';
60
+ export { ResponseUtils } from './src/api/utils/ResponseUtils.js';
61
+ export { SseUtils } from './src/api/utils/SseUtils.js';
62
+ export type { ServerSentEvent } from './src/api/utils/SseUtils.js';
63
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAGH,OAAO,EAAE,kBAAkB,EAAE,MAAM,8CAA8C,CAAA;AACjF,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,8CAA8C,CAAA;AAGlG,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAA;AAC1E,YAAY,EACV,iBAAiB,EACjB,UAAU,EACV,cAAc,GACf,MAAM,wCAAwC,CAAA;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAA;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAA;AAGpE,YAAY,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAA;AACxE,YAAY,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAA;AAC1E,YAAY,EAAE,YAAY,EAAE,MAAM,0CAA0C,CAAA;AAC5E,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAA;AACjF,YAAY,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAA;AAC9E,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,iDAAiD,CAAA;AAC5G,YAAY,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAA;AAG9E,OAAO,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAA;AACzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iDAAiD,CAAA;AACrF,OAAO,EAAE,qBAAqB,EAAE,MAAM,mDAAmD,CAAA;AACzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAA;AACnF,OAAO,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAA;AACjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,qDAAqD,CAAA;AAG7F,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAA;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAA;AAC9E,YAAY,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAA;AACxF,OAAO,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAA;AACxE,YAAY,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAA;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAA;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAA;AACtD,YAAY,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,55 @@
1
+ /**
2
+ * `@xfcfam/xf-server-http` — HTTP transport for the XF Architecture
3
+ * Model (CFAM). The Fastify implementation of the `@xfcfam/xf-server`
4
+ * contract.
5
+ *
6
+ * Exposes:
7
+ *
8
+ * - **{@link HttpServerBusiness}** — Business-Layer orchestrator. Owns
9
+ * the Fastify lifecycle and the route registry. Concrete subclasses
10
+ * live in the Business Layer; services push routes to it from their
11
+ * own `init()` via `B.server.get(path, handler)`.
12
+ *
13
+ * - **{@link RestService}** — Interaction Generalization for raw-body
14
+ * endpoints (streams or bytes). Provides `wrap(handler)`.
15
+ *
16
+ * - **{@link ObjectRestService}** — Same protocol, adds automatic
17
+ * request parsing and response serialisation by `Content-Type` via
18
+ * `object(handler)`. JSON built-in; XML/CSV/YAML pluggable;
19
+ * developer-chosen date handling.
20
+ *
21
+ * - **Transfers**: {@link HttpRequest}, {@link HttpResponse},
22
+ * {@link HttpAddress}, {@link HttpHandler}, {@link HttpMethod},
23
+ * {@link MultipartPart}.
24
+ *
25
+ * - **Exceptions**: {@link HttpException} (base) +
26
+ * `BadRequestException`, `UnauthorizedException`,
27
+ * `ForbiddenException`, `NotFoundException`,
28
+ * `InternalServerException`.
29
+ *
30
+ * - **Utilities**: {@link HttpStatusUtils}, {@link SchemaValidatorUtils},
31
+ * {@link FileResponseUtils}, {@link ResponseUtils}.
32
+ *
33
+ * See https://xfcfam.org for the full XF specification.
34
+ */
35
+ // ── Business Generalization ───────────────────────────────
36
+ export { HttpServerBusiness } from './src/business/general/HttpServerBusiness.js';
37
+ // ── Interaction Generalizations ───────────────────────────
38
+ export { RestService } from './src/api/general/RestService.js';
39
+ export { ObjectRestService } from './src/api/general/ObjectRestService.js';
40
+ export { WebSocketService } from './src/api/general/WebSocketService.js';
41
+ export { GraphQLService } from './src/api/general/GraphQLService.js';
42
+ // ── Exceptions ────────────────────────────────────────────
43
+ export { HttpException } from './src/business/transfers/HttpException.js';
44
+ export { BadRequestException } from './src/business/transfers/BadRequestException.js';
45
+ export { UnauthorizedException } from './src/business/transfers/UnauthorizedException.js';
46
+ export { ForbiddenException } from './src/business/transfers/ForbiddenException.js';
47
+ export { NotFoundException } from './src/business/transfers/NotFoundException.js';
48
+ export { InternalServerException } from './src/business/transfers/InternalServerException.js';
49
+ // ── Utilities ─────────────────────────────────────────────
50
+ export { HttpStatusUtils } from './src/api/utils/HttpStatusUtils.js';
51
+ export { SchemaValidatorUtils } from './src/api/utils/SchemaValidatorUtils.js';
52
+ export { FileResponseUtils } from './src/api/utils/FileResponseUtils.js';
53
+ export { ResponseUtils } from './src/api/utils/ResponseUtils.js';
54
+ export { SseUtils } from './src/api/utils/SseUtils.js';
55
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,6DAA6D;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,8CAA8C,CAAA;AAGjF,6DAA6D;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAA;AAM1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAA;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAA;AAWpE,6DAA6D;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAA;AACzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iDAAiD,CAAA;AACrF,OAAO,EAAE,qBAAqB,EAAE,MAAM,mDAAmD,CAAA;AACzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAA;AACnF,OAAO,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAA;AACjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,qDAAqD,CAAA;AAE7F,6DAA6D;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAA;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAA;AAE9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAA;AAExE,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAA;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAA"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Interaction Layer Injection — placeholder.
3
+ *
4
+ * `A` is the canonical injection of the Interaction 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 `A` 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 `A` from their own artefact.
12
+ */
13
+ export declare class A {
14
+ private constructor();
15
+ static init(): Promise<void>;
16
+ static terminate(): Promise<void>;
17
+ }
18
+ //# sourceMappingURL=A.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"A.d.ts","sourceRoot":"","sources":["../../../src/api/A.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
+ * Interaction Layer Injection — placeholder.
3
+ *
4
+ * `A` is the canonical injection of the Interaction 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 `A` 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 `A` from their own artefact.
12
+ */
13
+ export class A {
14
+ constructor() { }
15
+ static async init() { }
16
+ static async terminate() { }
17
+ }
18
+ //# sourceMappingURL=A.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"A.js","sourceRoot":"","sources":["../../../src/api/A.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,48 @@
1
+ import { StatelessService } from '@xfcfam/xf';
2
+ import type { GraphQLConfig } from '../../business/transfers/GraphQLConfig.js';
3
+ /**
4
+ * Interaction-Layer Generalization for a GraphQL entry point.
5
+ *
6
+ * GraphQL rides on HTTP (a single `POST /graphql`), but its dispatch
7
+ * model — one endpoint, many operations resolved by a schema — differs
8
+ * from REST routing, so it has its own base. A `GraphQLService`
9
+ * supplies the schema and resolvers and registers them on the server;
10
+ * the server mounts the GraphQL engine (Mercurius) on the same Fastify
11
+ * instance and port as the REST routes.
12
+ *
13
+ * Concrete subclasses override {@link config} and register from
14
+ * `init()` with `B.server.graphql(this.config())`.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import { GraphQLService, type GraphQLConfig } from '@xfcfam/xf-server-http'
19
+ * import { B } from '../../business/B.js'
20
+ *
21
+ * export class ApiGraphQLService extends GraphQLService {
22
+ * override async init(): Promise<void> {
23
+ * B.server.graphql(this.config())
24
+ * }
25
+ *
26
+ * protected override config(): GraphQLConfig {
27
+ * return {
28
+ * schema: `type Query { hello(name: String): String }`,
29
+ * resolvers: {
30
+ * Query: { hello: (_: unknown, a: { name?: string }) => `Hi ${a.name ?? 'world'}` },
31
+ * },
32
+ * graphiql: true,
33
+ * }
34
+ * }
35
+ * }
36
+ * ```
37
+ */
38
+ export declare abstract class GraphQLService extends StatelessService {
39
+ init(): Promise<void>;
40
+ terminate(): Promise<void>;
41
+ /**
42
+ * The GraphQL endpoint configuration (schema + resolvers + options).
43
+ * Override to supply the API; subclasses pass the result to
44
+ * `B.server.graphql(...)` in `init()`.
45
+ */
46
+ protected abstract config(): GraphQLConfig;
47
+ }
48
+ //# sourceMappingURL=GraphQLService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GraphQLService.d.ts","sourceRoot":"","sources":["../../../../src/api/general/GraphQLService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAA;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,8BAAsB,cAAe,SAAQ,gBAAgB;IAC5C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAEzC;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,MAAM,IAAI,aAAa;CAC3C"}
@@ -0,0 +1,43 @@
1
+ import { StatelessService } from '@xfcfam/xf';
2
+ /**
3
+ * Interaction-Layer Generalization for a GraphQL entry point.
4
+ *
5
+ * GraphQL rides on HTTP (a single `POST /graphql`), but its dispatch
6
+ * model — one endpoint, many operations resolved by a schema — differs
7
+ * from REST routing, so it has its own base. A `GraphQLService`
8
+ * supplies the schema and resolvers and registers them on the server;
9
+ * the server mounts the GraphQL engine (Mercurius) on the same Fastify
10
+ * instance and port as the REST routes.
11
+ *
12
+ * Concrete subclasses override {@link config} and register from
13
+ * `init()` with `B.server.graphql(this.config())`.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { GraphQLService, type GraphQLConfig } from '@xfcfam/xf-server-http'
18
+ * import { B } from '../../business/B.js'
19
+ *
20
+ * export class ApiGraphQLService extends GraphQLService {
21
+ * override async init(): Promise<void> {
22
+ * B.server.graphql(this.config())
23
+ * }
24
+ *
25
+ * protected override config(): GraphQLConfig {
26
+ * return {
27
+ * schema: `type Query { hello(name: String): String }`,
28
+ * resolvers: {
29
+ * Query: { hello: (_: unknown, a: { name?: string }) => `Hi ${a.name ?? 'world'}` },
30
+ * },
31
+ * graphiql: true,
32
+ * }
33
+ * }
34
+ * }
35
+ * ```
36
+ */
37
+ export class GraphQLService extends StatelessService {
38
+ async init() {
39
+ // Subclasses override and call B.server.graphql(this.config()) inside.
40
+ }
41
+ async terminate() { }
42
+ }
43
+ //# sourceMappingURL=GraphQLService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GraphQLService.js","sourceRoot":"","sources":["../../../../src/api/general/GraphQLService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAG7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,OAAgB,cAAe,SAAQ,gBAAgB;IAClD,KAAK,CAAC,IAAI;QACjB,uEAAuE;IACzE,CAAC;IAEQ,KAAK,CAAC,SAAS,KAAmB,CAAC;CAQ7C"}