@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,364 @@
|
|
|
1
|
+
import { NotInitializedException } from '@xfcfam/xf';
|
|
2
|
+
import { ServerBusiness } from '@xfcfam/xf-server';
|
|
3
|
+
import fastify from 'fastify';
|
|
4
|
+
import { HttpException } from '../transfers/HttpException.js';
|
|
5
|
+
/**
|
|
6
|
+
* Business-Layer Generalization for the artefact-level HTTP server
|
|
7
|
+
* orchestrator — the Fastify implementation of the transport-agnostic
|
|
8
|
+
* {@link ServerBusiness} contract from `@xfcfam/xf-server`.
|
|
9
|
+
*
|
|
10
|
+
* It is **technology-aware** (Fastify, HTTP) by design: the Business
|
|
11
|
+
* Layer in XF is the correct home for infrastructure concerns that are
|
|
12
|
+
* not domain rules — the HTTP server is infrastructure, not domain
|
|
13
|
+
* logic. The route registry and the request pipeline come from the
|
|
14
|
+
* core; this class supplies the HTTP address scheme (`{ method, path }`),
|
|
15
|
+
* the Fastify lifecycle (`listen` / `close`), body collection
|
|
16
|
+
* (including multipart) and the error → HTTP-status mapping.
|
|
17
|
+
*
|
|
18
|
+
* **Registration model — push, not pull.** Interaction Services register
|
|
19
|
+
* their routes by calling `B.server.get(path, handler)` (or `post`,
|
|
20
|
+
* `put`, `patch`, `del`, `call`) from within their own `init()`. The
|
|
21
|
+
* server MUST be created and available on `B` before `A.init()` runs;
|
|
22
|
+
* `listen()` is called by the start-point AFTER all services have
|
|
23
|
+
* registered.
|
|
24
|
+
*
|
|
25
|
+
* **Handler contract.** Handlers are `HttpHandler` functions
|
|
26
|
+
* (`(req: HttpRequest) => Promise<HttpResponse> | HttpResponse`). The
|
|
27
|
+
* server calls them with an `HttpRequest` whose `body` is the raw
|
|
28
|
+
* bytes/stream (or a `MultipartPart[]` for multipart requests).
|
|
29
|
+
* Serialisation (object → bytes) and parsing (bytes → object) are the
|
|
30
|
+
* Interaction Layer's responsibility — see `ObjectRestService.object()`.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* // business/logic/AppServerBusiness.ts
|
|
35
|
+
* import { HttpServerBusiness, type HttpRequest } from '@xfcfam/xf-server-http'
|
|
36
|
+
*
|
|
37
|
+
* export class AppServerBusiness extends HttpServerBusiness {
|
|
38
|
+
* constructor() {
|
|
39
|
+
* super({ port: Number.parseInt(process.env['PORT'] ?? '3000', 10) })
|
|
40
|
+
* }
|
|
41
|
+
*
|
|
42
|
+
* override async onRequest(req: HttpRequest): Promise<HttpRequest> {
|
|
43
|
+
* console.log(`[server] → ${req.method} ${req.path}`)
|
|
44
|
+
* return req
|
|
45
|
+
* }
|
|
46
|
+
* }
|
|
47
|
+
*
|
|
48
|
+
* // business/B.ts
|
|
49
|
+
* export class B {
|
|
50
|
+
* private constructor() {}
|
|
51
|
+
* static readonly server = new AppServerBusiness()
|
|
52
|
+
* static async init() { await B.server.init() }
|
|
53
|
+
* static async terminate() { await B.server.terminate() }
|
|
54
|
+
* }
|
|
55
|
+
*
|
|
56
|
+
* // main.ts (start-point): once the XF element has bootstrapped the
|
|
57
|
+
* // layers R → B → A and the services have pushed their routes, start
|
|
58
|
+
* // the transport explicitly:
|
|
59
|
+
* await B.server.listen() // start Fastify after all routes are in
|
|
60
|
+
* // ...and on shutdown, before the XF element tears the layers down:
|
|
61
|
+
* await B.server.close()
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export class HttpServerBusiness extends ServerBusiness {
|
|
65
|
+
constructor(options) {
|
|
66
|
+
super({ options, fastify: undefined, routes: [], wsRoutes: [], graphql: undefined });
|
|
67
|
+
}
|
|
68
|
+
// ─── Route registration (push) ────────────────────────────
|
|
69
|
+
/** Register a GET endpoint. */
|
|
70
|
+
get(path, handler) {
|
|
71
|
+
this.call('GET', path, handler);
|
|
72
|
+
}
|
|
73
|
+
/** Register a POST endpoint. */
|
|
74
|
+
post(path, handler) {
|
|
75
|
+
this.call('POST', path, handler);
|
|
76
|
+
}
|
|
77
|
+
/** Register a PUT endpoint. */
|
|
78
|
+
put(path, handler) {
|
|
79
|
+
this.call('PUT', path, handler);
|
|
80
|
+
}
|
|
81
|
+
/** Register a PATCH endpoint. */
|
|
82
|
+
patch(path, handler) {
|
|
83
|
+
this.call('PATCH', path, handler);
|
|
84
|
+
}
|
|
85
|
+
/** Register a DELETE endpoint. */
|
|
86
|
+
del(path, handler) {
|
|
87
|
+
this.call('DELETE', path, handler);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Register an endpoint for an arbitrary HTTP method. Used for
|
|
91
|
+
* `HEAD`, `OPTIONS`, or any verb not covered by the convenience
|
|
92
|
+
* helpers.
|
|
93
|
+
*/
|
|
94
|
+
call(method, path, handler) {
|
|
95
|
+
this.register({ method, path }, handler);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Register a WebSocket endpoint. The handler receives a
|
|
99
|
+
* {@link WebSocketConnection} once the client upgrade completes. The
|
|
100
|
+
* WebSocket plugin runs on the same Fastify instance and port as the
|
|
101
|
+
* REST routes; like every registration, call this before `listen()`.
|
|
102
|
+
*/
|
|
103
|
+
ws(path, handler) {
|
|
104
|
+
this.state.wsRoutes.push({ path, handler });
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Register a GraphQL endpoint (schema + resolvers). The GraphQL
|
|
108
|
+
* engine (Mercurius) is mounted on the shared Fastify instance at
|
|
109
|
+
* `config.path` (default `/graphql`). At most one GraphQL endpoint per
|
|
110
|
+
* server; a later call replaces the earlier config.
|
|
111
|
+
*/
|
|
112
|
+
graphql(config) {
|
|
113
|
+
this.state.graphql = config;
|
|
114
|
+
}
|
|
115
|
+
// ─── Lifecycle ────────────────────────────────────────────
|
|
116
|
+
/**
|
|
117
|
+
* Start accepting requests. Creates the Fastify instance, registers
|
|
118
|
+
* multipart support if configured, mounts every route that has been
|
|
119
|
+
* pushed so far, and begins listening.
|
|
120
|
+
*
|
|
121
|
+
* Call this from the start-point AFTER the Interaction layer has
|
|
122
|
+
* registered all routes — no new routes should be pushed after this
|
|
123
|
+
* point.
|
|
124
|
+
*/
|
|
125
|
+
async listen() {
|
|
126
|
+
const instance = fastify({ logger: false });
|
|
127
|
+
this.state.fastify = instance;
|
|
128
|
+
if (this.state.options.multipart !== undefined && this.state.options.multipart !== false) {
|
|
129
|
+
await HttpServerBusiness.registerMultipart(instance, this.state.options.multipart);
|
|
130
|
+
}
|
|
131
|
+
// WebSocket plugin must be registered before its routes are defined.
|
|
132
|
+
if (this.state.wsRoutes.length > 0) {
|
|
133
|
+
await HttpServerBusiness.registerWebSocket(instance, this.state.wsRoutes);
|
|
134
|
+
}
|
|
135
|
+
for (const route of this.routes) {
|
|
136
|
+
instance.route({
|
|
137
|
+
method: route.address.method,
|
|
138
|
+
url: route.address.path,
|
|
139
|
+
handler: this.adapter(route.address.method, route.address.path, route.handler),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
if (this.state.graphql !== undefined) {
|
|
143
|
+
await HttpServerBusiness.registerGraphQL(instance, this.state.graphql);
|
|
144
|
+
}
|
|
145
|
+
await instance.listen({
|
|
146
|
+
port: this.state.options.port,
|
|
147
|
+
host: this.state.options.host ?? '0.0.0.0',
|
|
148
|
+
});
|
|
149
|
+
await this.onStarted();
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Stop accepting requests and release the Fastify instance. Waits
|
|
153
|
+
* for in-flight requests to complete before resolving.
|
|
154
|
+
*/
|
|
155
|
+
async close() {
|
|
156
|
+
if (this.state.fastify !== undefined) {
|
|
157
|
+
await this.state.fastify.close();
|
|
158
|
+
this.state.fastify = undefined;
|
|
159
|
+
}
|
|
160
|
+
await this.onStopped();
|
|
161
|
+
}
|
|
162
|
+
// ─── Protected accessor ───────────────────────────────────
|
|
163
|
+
/**
|
|
164
|
+
* Get the underlying Fastify instance. Throws if `listen()` hasn't
|
|
165
|
+
* run. Exposed so protocol extensions (WebSocket, GraphQL) can
|
|
166
|
+
* register their plugins on the same instance.
|
|
167
|
+
*/
|
|
168
|
+
fastifyInstance() {
|
|
169
|
+
if (this.state.fastify === undefined) {
|
|
170
|
+
throw new NotInitializedException('HttpServerBusiness: listen() has not been called.');
|
|
171
|
+
}
|
|
172
|
+
return this.state.fastify;
|
|
173
|
+
}
|
|
174
|
+
// ─── Internals ─────────────────────────────────────────────
|
|
175
|
+
adapter(method, path, handler) {
|
|
176
|
+
return async (fastifyReq, fastifyReply) => {
|
|
177
|
+
const req = await HttpServerBusiness.request(fastifyReq, method, path);
|
|
178
|
+
const res = await this.dispatch(req, handler, HttpServerBusiness.errorToResponse);
|
|
179
|
+
await HttpServerBusiness.sendResponse(fastifyReply, res);
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
static async request(fr, method, path) {
|
|
183
|
+
let body = fr.body;
|
|
184
|
+
// If @fastify/multipart is active and this is a multipart request,
|
|
185
|
+
// collect the parts into our MultipartPart[] shape so handlers
|
|
186
|
+
// see a uniform body regardless of the underlying engine.
|
|
187
|
+
const contentType = String(fr.headers['content-type'] ?? '').toLowerCase();
|
|
188
|
+
if (contentType.startsWith('multipart/') && typeof fr.parts === 'function') {
|
|
189
|
+
body = await HttpServerBusiness.collectMultipart(fr);
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
method,
|
|
193
|
+
path,
|
|
194
|
+
params: fr.params,
|
|
195
|
+
query: fr.query,
|
|
196
|
+
headers: fr.headers,
|
|
197
|
+
body,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
static async collectMultipart(fr) {
|
|
201
|
+
const out = [];
|
|
202
|
+
for await (const raw of fr.parts()) {
|
|
203
|
+
const p = raw;
|
|
204
|
+
if (p.type === 'file') {
|
|
205
|
+
const bytes = await HttpServerBusiness.collectNodeStream(p.file);
|
|
206
|
+
const part = {
|
|
207
|
+
field: p.fieldname,
|
|
208
|
+
mimeType: p.mimetype ?? 'application/octet-stream',
|
|
209
|
+
body: bytes,
|
|
210
|
+
...(p.filename !== undefined ? { filename: p.filename } : {}),
|
|
211
|
+
size: bytes.byteLength,
|
|
212
|
+
};
|
|
213
|
+
out.push(part);
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
const value = String(p.value ?? '');
|
|
217
|
+
out.push({
|
|
218
|
+
field: p.fieldname,
|
|
219
|
+
mimeType: 'text/plain',
|
|
220
|
+
body: new TextEncoder().encode(value),
|
|
221
|
+
size: value.length,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return out;
|
|
226
|
+
}
|
|
227
|
+
static async collectNodeStream(stream) {
|
|
228
|
+
const chunks = [];
|
|
229
|
+
for await (const chunk of stream) {
|
|
230
|
+
chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk);
|
|
231
|
+
}
|
|
232
|
+
const total = chunks.reduce((acc, c) => acc + c.byteLength, 0);
|
|
233
|
+
const out = new Uint8Array(total);
|
|
234
|
+
let offset = 0;
|
|
235
|
+
for (const c of chunks) {
|
|
236
|
+
out.set(c, offset);
|
|
237
|
+
offset += c.byteLength;
|
|
238
|
+
}
|
|
239
|
+
return out;
|
|
240
|
+
}
|
|
241
|
+
static async registerMultipart(instance, config) {
|
|
242
|
+
// `@fastify/multipart` is a direct dependency of xf-server-http (the
|
|
243
|
+
// package is encapsulated end-to-end). We load it lazily — only
|
|
244
|
+
// when the user opts in via `multipart: true | {...}` — to keep
|
|
245
|
+
// the cold-start of multipart-free services minimal.
|
|
246
|
+
const mod = await import('@fastify/multipart');
|
|
247
|
+
const plugin = mod.default ?? mod;
|
|
248
|
+
const opts = config === true ? {} : {
|
|
249
|
+
limits: {
|
|
250
|
+
...(config.maxFileSize !== undefined ? { fileSize: config.maxFileSize } : {}),
|
|
251
|
+
...(config.maxFiles !== undefined ? { files: config.maxFiles } : {}),
|
|
252
|
+
...(config.maxFields !== undefined ? { fields: config.maxFields } : {}),
|
|
253
|
+
...(config.maxFieldsSize !== undefined ? { fieldSize: config.maxFieldsSize } : {}),
|
|
254
|
+
},
|
|
255
|
+
};
|
|
256
|
+
await instance.register(plugin, opts);
|
|
257
|
+
}
|
|
258
|
+
static async registerWebSocket(instance, routes) {
|
|
259
|
+
// `@fastify/websocket` is a direct dependency of xf-server-http,
|
|
260
|
+
// lazy-loaded only when WebSocket endpoints are declared. The
|
|
261
|
+
// dynamic specifier is resolved at runtime; the plugin's Fastify
|
|
262
|
+
// type augmentation is applied through a loose local shape.
|
|
263
|
+
const spec = '@fastify/websocket';
|
|
264
|
+
const mod = await import(spec);
|
|
265
|
+
const plugin = mod.default ?? mod;
|
|
266
|
+
const app = instance;
|
|
267
|
+
await app.register(plugin);
|
|
268
|
+
for (const route of routes) {
|
|
269
|
+
app.get(route.path, { websocket: true }, (socket, req) => {
|
|
270
|
+
void route.handler(HttpServerBusiness.adaptSocket(socket, req, route.path));
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
static adaptSocket(socket, req, path) {
|
|
275
|
+
const s = socket;
|
|
276
|
+
const r = req;
|
|
277
|
+
return {
|
|
278
|
+
path,
|
|
279
|
+
params: (r.params ?? {}),
|
|
280
|
+
query: (r.query ?? {}),
|
|
281
|
+
headers: (r.headers ?? {}),
|
|
282
|
+
send: (data) => s.send(data),
|
|
283
|
+
close: (code, reason) => s.close(code, reason),
|
|
284
|
+
onMessage: (listener) => s.on('message', (data) => listener(HttpServerBusiness.toFrame(data))),
|
|
285
|
+
onClose: (listener) => s.on('close', (code, reason) => listener(Number(code ?? 0), String(reason ?? ''))),
|
|
286
|
+
onError: (listener) => s.on('error', (err) => listener(err instanceof Error ? err : new Error(String(err)))),
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
static toFrame(data) {
|
|
290
|
+
if (typeof data === 'string')
|
|
291
|
+
return data;
|
|
292
|
+
if (data instanceof Uint8Array)
|
|
293
|
+
return data;
|
|
294
|
+
if (data instanceof ArrayBuffer)
|
|
295
|
+
return new Uint8Array(data);
|
|
296
|
+
if (Array.isArray(data)) {
|
|
297
|
+
const parts = data;
|
|
298
|
+
const total = parts.reduce((n, c) => n + c.byteLength, 0);
|
|
299
|
+
const out = new Uint8Array(total);
|
|
300
|
+
let offset = 0;
|
|
301
|
+
for (const c of parts) {
|
|
302
|
+
out.set(c, offset);
|
|
303
|
+
offset += c.byteLength;
|
|
304
|
+
}
|
|
305
|
+
return out;
|
|
306
|
+
}
|
|
307
|
+
return String(data);
|
|
308
|
+
}
|
|
309
|
+
static async registerGraphQL(instance, config) {
|
|
310
|
+
// `mercurius` is a direct dependency of xf-server-http, lazy-loaded
|
|
311
|
+
// only when a GraphQL endpoint is declared.
|
|
312
|
+
const spec = 'mercurius';
|
|
313
|
+
const mod = await import(spec);
|
|
314
|
+
const plugin = mod.default ?? mod;
|
|
315
|
+
const app = instance;
|
|
316
|
+
await app.register(plugin, {
|
|
317
|
+
schema: config.schema,
|
|
318
|
+
resolvers: config.resolvers,
|
|
319
|
+
graphiql: config.graphiql ?? false,
|
|
320
|
+
path: config.path ?? '/graphql',
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
static async sendResponse(reply, res) {
|
|
324
|
+
reply.status(res.status);
|
|
325
|
+
if (res.headers !== undefined) {
|
|
326
|
+
for (const [k, v] of Object.entries(res.headers))
|
|
327
|
+
reply.header(k, v);
|
|
328
|
+
}
|
|
329
|
+
const body = res.body;
|
|
330
|
+
if (body === null || body === undefined) {
|
|
331
|
+
await reply.send();
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
if (HttpServerBusiness.isReadableStream(body)) {
|
|
335
|
+
// Web ReadableStream → Node Readable for Fastify.
|
|
336
|
+
const { Readable } = await import('node:stream');
|
|
337
|
+
await reply.send(Readable.fromWeb(body));
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
if (body instanceof Uint8Array) {
|
|
341
|
+
await reply.send(Buffer.from(body.buffer, body.byteOffset, body.byteLength));
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
if (typeof body === 'string') {
|
|
345
|
+
await reply.send(body);
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
// Anything else: pass through (Fastify will JSON-encode objects).
|
|
349
|
+
await reply.send(body);
|
|
350
|
+
}
|
|
351
|
+
static errorToResponse(err) {
|
|
352
|
+
if (err instanceof HttpException) {
|
|
353
|
+
return { status: err.status, body: err.body };
|
|
354
|
+
}
|
|
355
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
356
|
+
return { status: 500, body: { message: 'Internal server error', detail: message } };
|
|
357
|
+
}
|
|
358
|
+
static isReadableStream(value) {
|
|
359
|
+
return typeof value === 'object'
|
|
360
|
+
&& value !== null
|
|
361
|
+
&& typeof value.getReader === 'function';
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
//# sourceMappingURL=HttpServerBusiness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HttpServerBusiness.js","sourceRoot":"","sources":["../../../../src/business/general/HttpServerBusiness.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { HttpException } from './HttpException.js';
|
|
2
|
+
/**
|
|
3
|
+
* Interaction-layer Exception — HTTP 400.
|
|
4
|
+
*
|
|
5
|
+
* Client error — the request is malformed (missing fields, invalid types, validation failure).
|
|
6
|
+
*
|
|
7
|
+
* Use `throw new BadRequestException('message')` inside a handler; the
|
|
8
|
+
* server pipeline translates it into a 400 response automatically.
|
|
9
|
+
*/
|
|
10
|
+
export declare class BadRequestException extends HttpException {
|
|
11
|
+
constructor(message: string, body?: unknown);
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=BadRequestException.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BadRequestException.d.ts","sourceRoot":"","sources":["../../../../src/business/transfers/BadRequestException.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElD;;;;;;;GAOG;AACH,qBAAa,mBAAoB,SAAQ,aAAa;gBACxC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO;CAI5C"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { HttpException } from './HttpException.js';
|
|
2
|
+
/**
|
|
3
|
+
* Interaction-layer Exception — HTTP 400.
|
|
4
|
+
*
|
|
5
|
+
* Client error — the request is malformed (missing fields, invalid types, validation failure).
|
|
6
|
+
*
|
|
7
|
+
* Use `throw new BadRequestException('message')` inside a handler; the
|
|
8
|
+
* server pipeline translates it into a 400 response automatically.
|
|
9
|
+
*/
|
|
10
|
+
export class BadRequestException extends HttpException {
|
|
11
|
+
constructor(message, body) {
|
|
12
|
+
super(400, message, body);
|
|
13
|
+
this.name = 'BadRequestException';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=BadRequestException.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BadRequestException.js","sourceRoot":"","sources":["../../../../src/business/transfers/BadRequestException.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElD;;;;;;;GAOG;AACH,MAAM,OAAO,mBAAoB,SAAQ,aAAa;IACpD,YAAY,OAAe,EAAE,IAAc;QACzC,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;QACzB,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAA;IACnC,CAAC;CACF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { HttpException } from './HttpException.js';
|
|
2
|
+
/**
|
|
3
|
+
* Interaction-layer Exception — HTTP 403.
|
|
4
|
+
*
|
|
5
|
+
* Authentication succeeded but the principal is not allowed to perform the action.
|
|
6
|
+
*
|
|
7
|
+
* Use `throw new ForbiddenException('message')` inside a handler; the
|
|
8
|
+
* server pipeline translates it into a 403 response automatically.
|
|
9
|
+
*/
|
|
10
|
+
export declare class ForbiddenException extends HttpException {
|
|
11
|
+
constructor(message: string, body?: unknown);
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=ForbiddenException.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ForbiddenException.d.ts","sourceRoot":"","sources":["../../../../src/business/transfers/ForbiddenException.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElD;;;;;;;GAOG;AACH,qBAAa,kBAAmB,SAAQ,aAAa;gBACvC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO;CAI5C"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { HttpException } from './HttpException.js';
|
|
2
|
+
/**
|
|
3
|
+
* Interaction-layer Exception — HTTP 403.
|
|
4
|
+
*
|
|
5
|
+
* Authentication succeeded but the principal is not allowed to perform the action.
|
|
6
|
+
*
|
|
7
|
+
* Use `throw new ForbiddenException('message')` inside a handler; the
|
|
8
|
+
* server pipeline translates it into a 403 response automatically.
|
|
9
|
+
*/
|
|
10
|
+
export class ForbiddenException extends HttpException {
|
|
11
|
+
constructor(message, body) {
|
|
12
|
+
super(403, message, body);
|
|
13
|
+
this.name = 'ForbiddenException';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=ForbiddenException.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ForbiddenException.js","sourceRoot":"","sources":["../../../../src/business/transfers/ForbiddenException.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElD;;;;;;;GAOG;AACH,MAAM,OAAO,kBAAmB,SAAQ,aAAa;IACnD,YAAY,OAAe,EAAE,IAAc;QACzC,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;QACzB,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAA;IAClC,CAAC;CACF"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Business-layer Transfer — a GraphQL endpoint registration.
|
|
3
|
+
*
|
|
4
|
+
* Carries everything the server needs to mount a GraphQL API on the
|
|
5
|
+
* shared Fastify instance (via Mercurius): the SDL schema, the resolver
|
|
6
|
+
* map, the mount path, and whether to serve the GraphiQL IDE.
|
|
7
|
+
*
|
|
8
|
+
* `GraphQLService` builds this and pushes it with
|
|
9
|
+
* `B.server.graphql(config)` from its `init()`.
|
|
10
|
+
*/
|
|
11
|
+
export interface GraphQLConfig {
|
|
12
|
+
/** GraphQL schema in SDL (Schema Definition Language) form. */
|
|
13
|
+
readonly schema: string;
|
|
14
|
+
/**
|
|
15
|
+
* Resolver map: `{ Query: {...}, Mutation: {...}, <Type>: {...} }`.
|
|
16
|
+
* Shape is engine-defined; kept opaque here to avoid a hard
|
|
17
|
+
* dependency on the GraphQL types at the contract level.
|
|
18
|
+
*/
|
|
19
|
+
readonly resolvers: Readonly<Record<string, unknown>>;
|
|
20
|
+
/** Mount path for the endpoint. Default `'/graphql'`. */
|
|
21
|
+
readonly path?: string;
|
|
22
|
+
/** Serve the GraphiQL IDE at the mount path. Default `false`. */
|
|
23
|
+
readonly graphiql?: boolean;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=GraphQLConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GraphQLConfig.d.ts","sourceRoot":"","sources":["../../../../src/business/transfers/GraphQLConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACrD,yDAAyD;IACzD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,iEAAiE;IACjE,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAC5B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GraphQLConfig.js","sourceRoot":"","sources":["../../../../src/business/transfers/GraphQLConfig.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ServerException } from '@xfcfam/xf-server';
|
|
2
|
+
/**
|
|
3
|
+
* Business-layer Exception — base class for typed HTTP errors raised
|
|
4
|
+
* inside a handler. The HTTP specialisation of the transport-agnostic
|
|
5
|
+
* {@link ServerException}: it adds the numeric HTTP `status` that the
|
|
6
|
+
* server maps onto the wire.
|
|
7
|
+
*
|
|
8
|
+
* The server pipeline catches every `HttpException`, reads its
|
|
9
|
+
* `status` and `body`, and writes the corresponding HTTP response.
|
|
10
|
+
* Subclasses for common cases (`BadRequestException`,
|
|
11
|
+
* `NotFoundException`, …) preset the status; custom domain errors can
|
|
12
|
+
* extend this class with any status and shape.
|
|
13
|
+
*
|
|
14
|
+
* Non-`HttpException` errors raised by a handler are routed to the
|
|
15
|
+
* `onError` hooks; if no hook produces a response, the server emits a
|
|
16
|
+
* generic `500 Internal Server Error`.
|
|
17
|
+
*/
|
|
18
|
+
export declare class HttpException extends ServerException {
|
|
19
|
+
/** HTTP status code to send to the client. */
|
|
20
|
+
readonly status: number;
|
|
21
|
+
constructor(status: number, message: string, body?: unknown);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=HttpException.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HttpException.d.ts","sourceRoot":"","sources":["../../../../src/business/transfers/HttpException.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAEnD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,aAAc,SAAQ,eAAe;IAChD,8CAA8C;IAC9C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;gBAEX,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO;CAK5D"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ServerException } from '@xfcfam/xf-server';
|
|
2
|
+
/**
|
|
3
|
+
* Business-layer Exception — base class for typed HTTP errors raised
|
|
4
|
+
* inside a handler. The HTTP specialisation of the transport-agnostic
|
|
5
|
+
* {@link ServerException}: it adds the numeric HTTP `status` that the
|
|
6
|
+
* server maps onto the wire.
|
|
7
|
+
*
|
|
8
|
+
* The server pipeline catches every `HttpException`, reads its
|
|
9
|
+
* `status` and `body`, and writes the corresponding HTTP response.
|
|
10
|
+
* Subclasses for common cases (`BadRequestException`,
|
|
11
|
+
* `NotFoundException`, …) preset the status; custom domain errors can
|
|
12
|
+
* extend this class with any status and shape.
|
|
13
|
+
*
|
|
14
|
+
* Non-`HttpException` errors raised by a handler are routed to the
|
|
15
|
+
* `onError` hooks; if no hook produces a response, the server emits a
|
|
16
|
+
* generic `500 Internal Server Error`.
|
|
17
|
+
*/
|
|
18
|
+
export class HttpException extends ServerException {
|
|
19
|
+
/** HTTP status code to send to the client. */
|
|
20
|
+
status;
|
|
21
|
+
constructor(status, message, body) {
|
|
22
|
+
super(message, body);
|
|
23
|
+
this.name = 'HttpException';
|
|
24
|
+
this.status = status;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=HttpException.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HttpException.js","sourceRoot":"","sources":["../../../../src/business/transfers/HttpException.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAEnD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,OAAO,aAAc,SAAQ,eAAe;IAChD,8CAA8C;IACrC,MAAM,CAAQ;IAEvB,YAAY,MAAc,EAAE,OAAe,EAAE,IAAc;QACzD,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;QACpB,IAAI,CAAC,IAAI,GAAG,eAAe,CAAA;QAC3B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACtB,CAAC;CACF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical HTTP methods supported by the server. The union is closed:
|
|
3
|
+
* exotic verbs (`CONNECT`, `TRACE`, `PROPFIND`, …) are intentionally
|
|
4
|
+
* out of scope for v0 and can be added in extension packages.
|
|
5
|
+
*/
|
|
6
|
+
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
|
|
7
|
+
//# sourceMappingURL=HttpMethod.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HttpMethod.d.ts","sourceRoot":"","sources":["../../../../src/business/transfers/HttpMethod.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAClB,KAAK,GACL,MAAM,GACN,KAAK,GACL,OAAO,GACP,QAAQ,GACR,MAAM,GACN,SAAS,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HttpMethod.js","sourceRoot":"","sources":["../../../../src/business/transfers/HttpMethod.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { HttpMethod } from './HttpMethod.js';
|
|
2
|
+
/**
|
|
3
|
+
* Interaction-layer Transfer — a single incoming HTTP request as seen
|
|
4
|
+
* by a `RestService` handler.
|
|
5
|
+
*
|
|
6
|
+
* `body` is parameterised so each handler can declare its expected
|
|
7
|
+
* shape. By default it is `unknown` — at the `RestService` level the
|
|
8
|
+
* body arrives as a raw stream or `Uint8Array`; the
|
|
9
|
+
* `ObjectRestService` subclass parses it according to the
|
|
10
|
+
* `Content-Type` and surfaces it as a typed object.
|
|
11
|
+
*
|
|
12
|
+
* Streaming uploads are first-class: when the underlying transport
|
|
13
|
+
* supplies the body as a `ReadableStream<Uint8Array>`, it is carried
|
|
14
|
+
* through here without buffering. The handler decides whether to
|
|
15
|
+
* consume it incrementally or to read it into memory.
|
|
16
|
+
*/
|
|
17
|
+
export interface HttpRequest<TBody = unknown> {
|
|
18
|
+
/** HTTP method. */
|
|
19
|
+
readonly method: HttpMethod;
|
|
20
|
+
/** Resolved path (after route matching). */
|
|
21
|
+
readonly path: string;
|
|
22
|
+
/** Route parameters extracted from the path (`/users/:id` → `{ id: '42' }`). */
|
|
23
|
+
readonly params: Readonly<Record<string, string>>;
|
|
24
|
+
/** Query-string parameters. */
|
|
25
|
+
readonly query: Readonly<Record<string, string | readonly string[]>>;
|
|
26
|
+
/** Lowercased header name → value (or array for repeated headers). */
|
|
27
|
+
readonly headers: Readonly<Record<string, string | readonly string[]>>;
|
|
28
|
+
/**
|
|
29
|
+
* Request body. May be `null`, a `Uint8Array`, a
|
|
30
|
+
* `ReadableStream<Uint8Array>` for incremental consumption, or any
|
|
31
|
+
* parsed value when an `ObjectRestService` has run its parsers.
|
|
32
|
+
*/
|
|
33
|
+
readonly body: TBody;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=HttpRequest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HttpRequest.d.ts","sourceRoot":"","sources":["../../../../src/business/transfers/HttpRequest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAEjD;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,WAAW,CAAC,KAAK,GAAG,OAAO;IAC1C,mBAAmB;IACnB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;IAC3B,4CAA4C;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,gFAAgF;IAChF,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACjD,+BAA+B;IAC/B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC,CAAC,CAAA;IACpE,sEAAsE;IACtE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC,CAAC,CAAA;IACtE;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAA;CACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HttpRequest.js","sourceRoot":"","sources":["../../../../src/business/transfers/HttpRequest.ts"],"names":[],"mappings":""}
|