@silkweave/fastify 4.3.0 → 5.0.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/README.md +14 -0
- package/build/index.d.mts.map +1 -1
- package/build/index.mjs +101 -61
- package/build/index.mjs.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -62,6 +62,20 @@ curl 'http://localhost:8080/spaces/acme/users?offset=20&limit=10'
|
|
|
62
62
|
|
|
63
63
|
The input is merged from path + query + body (precedence: body → query → path) and validated per-source with the generated JSON Schema. The path placeholders, query params, and body each get their own OpenAPI parameters/requestBody, and validation failures return `400 { "error": "validation_error", "issues": [...] }`. A `:param` or `queryParams` entry that isn't in the input schema throws at startup.
|
|
64
64
|
|
|
65
|
+
## Resource Results (binary)
|
|
66
|
+
|
|
67
|
+
An action with a `binary()` output (see [`@silkweave/core`](https://www.npmjs.com/package/@silkweave/core)) - or any action returning a `resource()`, `File`/`Blob`, or bare bytes - responds with the **raw payload** instead of JSON:
|
|
68
|
+
|
|
69
|
+
- `Content-Type` from the resource's media type
|
|
70
|
+
- `Content-Disposition: inline; filename="..."` when the resource carries a `name`
|
|
71
|
+
- `Content-Description` when it carries a `description`
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
curl 'http://localhost:8080/screenshot?url=https://example.com' > shot.png
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The route's OpenAPI response documents the payload as `type: string, format: binary` under the declared media type.
|
|
78
|
+
|
|
65
79
|
## Streaming Actions
|
|
66
80
|
|
|
67
81
|
Actions defined with a `chunk` schema and an `async function*` `run` (see [`@silkweave/core`](https://www.npmjs.com/package/@silkweave/core)) are exposed on the same `POST /{action.name}` route, but the response shape depends on the request's `Accept` header:
|
package/build/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/adapter/fastify.ts"],"mappings":";;;;;;;UAqBiB,qBAAA,SAA8B,kBAAA,CAAmB,MAAA,EAAQ,iBAAA;EACxE,IAAA;EACA,IAAA;EACA,IAAA,GAAO,UAAA;;EAEP,IAAA,GAAO,oBAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/adapter/fastify.ts"],"mappings":";;;;;;;UAqBiB,qBAAA,SAA8B,kBAAA,CAAmB,MAAA,EAAQ,iBAAA;EACxE,IAAA;EACA,IAAA;EACA,IAAA,GAAO,UAAA;;EAEP,IAAA,GAAO,oBAAA;AAAA;AAAA,cAsTI,OAAA,EAAS,cAAA,CAAe,qBAAA"}
|
package/build/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { generateProtectedResourceMetadata, validateToken } from "@silkweave/auth";
|
|
2
|
-
import { SilkweaveError, actionMethod, buildLogLevels, isStreamingAction, methodHasBody, pathParamNames, resolveActionInput, runStreamingAction, validateActionRouting } from "@silkweave/core";
|
|
2
|
+
import { SilkweaveError, actionMethod, binarySchemaMeta, buildLogLevels, isBinarySchema, isStreamingAction, methodHasBody, pathParamNames, resolveActionInput, resourceBytes, runStreamingAction, toActionResource, validateActionRouting } from "@silkweave/core";
|
|
3
3
|
import { once } from "events";
|
|
4
4
|
import { fastify as fastify$1 } from "fastify";
|
|
5
5
|
import z from "zod/v4";
|
|
@@ -171,6 +171,37 @@ function splitInputSchema(action, method) {
|
|
|
171
171
|
body: hasBody && Object.keys(body.properties).length ? body : void 0
|
|
172
172
|
};
|
|
173
173
|
}
|
|
174
|
+
/** Strip characters that would break (or smuggle headers into) an HTTP header value. */
|
|
175
|
+
function headerSafe(value) {
|
|
176
|
+
return value.replace(/["\r\n]/g, " ").trim();
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Send a resource result as a raw HTTP body: bytes with `Content-Type` from
|
|
180
|
+
* the resource's media type, a `Content-Disposition` filename when the
|
|
181
|
+
* resource carries a name, and the description (if any) as
|
|
182
|
+
* `Content-Description` - over REST the binary itself IS the response, so the
|
|
183
|
+
* metadata rides in headers.
|
|
184
|
+
*/
|
|
185
|
+
function sendResource(reply, res) {
|
|
186
|
+
reply.header("Content-Type", res.mimeType);
|
|
187
|
+
if (res.name) reply.header("Content-Disposition", `inline; filename="${headerSafe(res.name)}"`);
|
|
188
|
+
if (res.description) reply.header("Content-Description", headerSafe(res.description));
|
|
189
|
+
return reply.send(Buffer.from(resourceBytes(res)));
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* OpenAPI response schema: binary actions document their payload as
|
|
193
|
+
* `type: string, format: binary` under the declared media type.
|
|
194
|
+
*/
|
|
195
|
+
function responseSchema(action) {
|
|
196
|
+
if (!isBinarySchema(action.output)) return { 200: { description: "Successful response" } };
|
|
197
|
+
return { 200: {
|
|
198
|
+
description: "Successful response",
|
|
199
|
+
content: { [binarySchemaMeta(action.output).mimeType ?? "application/octet-stream"]: { schema: {
|
|
200
|
+
type: "string",
|
|
201
|
+
format: "binary"
|
|
202
|
+
} } }
|
|
203
|
+
} };
|
|
204
|
+
}
|
|
174
205
|
/**
|
|
175
206
|
* Register the Scalar API-reference UI. It's an optional peer, so a missing
|
|
176
207
|
* module is skipped with a hint rather than crashing a headless deployment.
|
|
@@ -188,6 +219,73 @@ async function registerScalarDocs(instance) {
|
|
|
188
219
|
});
|
|
189
220
|
if (scalar) await instance.register(scalar.default, { routePrefix: "/" });
|
|
190
221
|
}
|
|
222
|
+
/** The instance-wide error handler: Silkweave/Zod/AJV failures map to legible statuses. */
|
|
223
|
+
function errorHandler(instance) {
|
|
224
|
+
return (error, _request, reply) => {
|
|
225
|
+
if (error instanceof SilkweaveError) return reply.status(error.statusCode).send({
|
|
226
|
+
error: error.code,
|
|
227
|
+
message: error.message
|
|
228
|
+
});
|
|
229
|
+
if (error instanceof z.ZodError) return reply.status(400).send({
|
|
230
|
+
error: "validation_error",
|
|
231
|
+
issues: error.issues
|
|
232
|
+
});
|
|
233
|
+
const validation = error.validation;
|
|
234
|
+
if (validation) return reply.status(400).send({
|
|
235
|
+
error: "validation_error",
|
|
236
|
+
issues: validation
|
|
237
|
+
});
|
|
238
|
+
instance.log.error(error);
|
|
239
|
+
return reply.status(500).send({
|
|
240
|
+
error: "internal",
|
|
241
|
+
message: "Internal server error"
|
|
242
|
+
});
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
/** Register one action as a Fastify route (validation, streaming, resource, and JSON paths). */
|
|
246
|
+
function registerActionRoute(instance, action, context, logger, hasAuth) {
|
|
247
|
+
validateActionRouting(action);
|
|
248
|
+
const method = actionMethod(action);
|
|
249
|
+
const url = action.path ? `/${action.path.replace(/^\//, "")}` : `/${action.name}`;
|
|
250
|
+
const { params, querystring, body } = splitInputSchema(action, method);
|
|
251
|
+
const streaming = isStreamingAction(action);
|
|
252
|
+
instance.route({
|
|
253
|
+
method,
|
|
254
|
+
url,
|
|
255
|
+
schema: {
|
|
256
|
+
description: action.description,
|
|
257
|
+
...params ? { params } : {},
|
|
258
|
+
...querystring ? { querystring } : {},
|
|
259
|
+
...body ? { body } : {},
|
|
260
|
+
response: responseSchema(action)
|
|
261
|
+
},
|
|
262
|
+
handler: async (request, reply) => {
|
|
263
|
+
const authInfo = hasAuth ? request.__silkweave_auth : void 0;
|
|
264
|
+
const actionContext = context.fork({
|
|
265
|
+
logger,
|
|
266
|
+
request,
|
|
267
|
+
...authInfo ? { auth: authInfo } : {}
|
|
268
|
+
});
|
|
269
|
+
const input = action.input.parse(resolveActionInput(action, {
|
|
270
|
+
params: request.params,
|
|
271
|
+
query: request.query,
|
|
272
|
+
body: request.body
|
|
273
|
+
}));
|
|
274
|
+
if (streaming) {
|
|
275
|
+
const format = pickStreamFormat(request.headers.accept);
|
|
276
|
+
if (format) {
|
|
277
|
+
await streamAction(reply, format, action, input, actionContext);
|
|
278
|
+
return reply;
|
|
279
|
+
}
|
|
280
|
+
return runStreamingAction(action, input, actionContext);
|
|
281
|
+
}
|
|
282
|
+
const result = await action.run(input, actionContext);
|
|
283
|
+
const res = await toActionResource(result, binarySchemaMeta(action.output));
|
|
284
|
+
if (res) return sendResource(reply, res);
|
|
285
|
+
return result;
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
}
|
|
191
289
|
const fastify = ({ host, port, auth, cors: corsConfig, ...fastifyOptions }) => {
|
|
192
290
|
const instance = fastify$1(fastifyOptions);
|
|
193
291
|
return (options, baseContext) => {
|
|
@@ -213,67 +311,9 @@ const fastify = ({ host, port, auth, cors: corsConfig, ...fastifyOptions }) => {
|
|
|
213
311
|
});
|
|
214
312
|
const oauthPaths = auth?.provider ? mountOAuthRoutes(instance, auth) : /* @__PURE__ */ new Set();
|
|
215
313
|
if (auth) mountAuthMiddleware(instance, auth, oauthPaths, context);
|
|
216
|
-
instance.setErrorHandler((
|
|
217
|
-
if (error instanceof SilkweaveError) return reply.status(error.statusCode).send({
|
|
218
|
-
error: error.code,
|
|
219
|
-
message: error.message
|
|
220
|
-
});
|
|
221
|
-
if (error instanceof z.ZodError) return reply.status(400).send({
|
|
222
|
-
error: "validation_error",
|
|
223
|
-
issues: error.issues
|
|
224
|
-
});
|
|
225
|
-
const validation = error.validation;
|
|
226
|
-
if (validation) return reply.status(400).send({
|
|
227
|
-
error: "validation_error",
|
|
228
|
-
issues: validation
|
|
229
|
-
});
|
|
230
|
-
instance.log.error(error);
|
|
231
|
-
return reply.status(500).send({
|
|
232
|
-
error: "internal",
|
|
233
|
-
message: "Internal server error"
|
|
234
|
-
});
|
|
235
|
-
});
|
|
314
|
+
instance.setErrorHandler(errorHandler(instance));
|
|
236
315
|
const logger = createActionLogger(instance);
|
|
237
|
-
for (const action of actions)
|
|
238
|
-
validateActionRouting(action);
|
|
239
|
-
const method = actionMethod(action);
|
|
240
|
-
const url = action.path ? `/${action.path.replace(/^\//, "")}` : `/${action.name}`;
|
|
241
|
-
const { params, querystring, body } = splitInputSchema(action, method);
|
|
242
|
-
const streaming = isStreamingAction(action);
|
|
243
|
-
instance.route({
|
|
244
|
-
method,
|
|
245
|
-
url,
|
|
246
|
-
schema: {
|
|
247
|
-
description: action.description,
|
|
248
|
-
...params ? { params } : {},
|
|
249
|
-
...querystring ? { querystring } : {},
|
|
250
|
-
...body ? { body } : {},
|
|
251
|
-
response: { 200: { description: "Successful response" } }
|
|
252
|
-
},
|
|
253
|
-
handler: async (request, reply) => {
|
|
254
|
-
const authInfo = auth ? request.__silkweave_auth : void 0;
|
|
255
|
-
const actionContext = context.fork({
|
|
256
|
-
logger,
|
|
257
|
-
request,
|
|
258
|
-
...authInfo ? { auth: authInfo } : {}
|
|
259
|
-
});
|
|
260
|
-
const input = action.input.parse(resolveActionInput(action, {
|
|
261
|
-
params: request.params,
|
|
262
|
-
query: request.query,
|
|
263
|
-
body: request.body
|
|
264
|
-
}));
|
|
265
|
-
if (streaming) {
|
|
266
|
-
const format = pickStreamFormat(request.headers.accept);
|
|
267
|
-
if (format) {
|
|
268
|
-
await streamAction(reply, format, action, input, actionContext);
|
|
269
|
-
return reply;
|
|
270
|
-
}
|
|
271
|
-
return runStreamingAction(action, input, actionContext);
|
|
272
|
-
}
|
|
273
|
-
return action.run(input, actionContext);
|
|
274
|
-
}
|
|
275
|
-
});
|
|
276
|
-
}
|
|
316
|
+
for (const action of actions) registerActionRoute(instance, action, context, logger, Boolean(auth));
|
|
277
317
|
await instance.listen({
|
|
278
318
|
host,
|
|
279
319
|
port
|
package/build/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["fastifyInstance"],"sources":["../src/adapter/fastify.ts"],"sourcesContent":["import type { FastifyCorsOptions } from '@fastify/cors'\nimport { AuthConfig, AuthInfo, generateProtectedResourceMetadata, OAuthRequest, OAuthResponse, validateToken } from '@silkweave/auth'\nimport { Action, actionMethod, ActionStreamRun, AdapterFactory, buildLogLevels, HttpMethod, isStreamingAction, Logger, LogLevel, methodHasBody, pathParamNames, resolveActionInput, runStreamingAction, SilkweaveContext, SilkweaveError, validateActionRouting } from '@silkweave/core'\nimport { once } from 'events'\nimport { FastifyBaseLogger, FastifyHttpOptions, fastify as fastifyInstance, FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'\nimport { Server } from 'http'\nimport z from 'zod/v4'\n\ntype FastifyLogLevel = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace'\n\nconst PINO_LEVEL_MAP: Record<LogLevel, FastifyLogLevel> = {\n emergency: 'fatal',\n alert: 'fatal',\n critical: 'fatal',\n error: 'error',\n warning: 'warn',\n notice: 'debug',\n info: 'info',\n debug: 'debug'\n}\n\nexport interface FastifyAdapterOptions extends FastifyHttpOptions<Server, FastifyBaseLogger> {\n host?: string\n port?: number\n auth?: AuthConfig\n /** CORS configuration. `false` to disable, `true`/`undefined` for permissive defaults, or a FastifyCorsOptions object. */\n cors?: FastifyCorsOptions | boolean\n}\n\nfunction toOAuthReq(request: FastifyRequest): OAuthRequest {\n return {\n method: request.method,\n url: new URL(request.url, `http://${request.hostname}`),\n headers: Object.fromEntries(Object.entries(request.headers).map(([k, v]) => [k, Array.isArray(v) ? v[0] : v])),\n body: request.body as Record<string, string> | undefined\n }\n}\n\nfunction sendOAuth(reply: FastifyReply, oauthRes: OAuthResponse) {\n for (const [key, value] of Object.entries(oauthRes.headers)) { reply.header(key, value) }\n return reply.status(oauthRes.status).send(oauthRes.body)\n}\n\nfunction mountOAuthRoutes(instance: FastifyInstance, auth: AuthConfig): Set<string> {\n const provider = auth.provider!\n // The provider builds its upstream redirect_uri as `${resourceUrl}${callbackPath}`,\n // so the callback route must match the configured callbackPath, not a hardcoded one.\n const callbackPath = auth.callbackPath ?? '/auth/callback'\n\n const paths = new Set([\n '/.well-known/oauth-authorization-server',\n '/authorize',\n callbackPath,\n '/token',\n '/register'\n ])\n\n instance.get('/.well-known/oauth-authorization-server', async (_req, reply) => {\n return sendOAuth(reply, provider.metadata())\n })\n instance.get('/authorize', async (req, reply) => {\n return sendOAuth(reply, await provider.authorize(toOAuthReq(req)))\n })\n instance.get(callbackPath, async (req, reply) => {\n return sendOAuth(reply, await provider.callback(toOAuthReq(req)))\n })\n instance.post('/token', async (req, reply) => {\n return sendOAuth(reply, await provider.token(toOAuthReq(req)))\n })\n instance.post('/register', async (req, reply) => {\n return sendOAuth(reply, await provider.register(toOAuthReq(req)))\n })\n\n return paths\n}\n\nfunction mountAuthMiddleware(instance: FastifyInstance, auth: AuthConfig, oauthPaths: Set<string>, context: SilkweaveContext) {\n instance.decorateRequest('__silkweave_auth', undefined)\n instance.addHook('onRequest', async (request: FastifyRequest, reply: FastifyReply) => {\n if (request.url.startsWith('/.well-known/') || oauthPaths.has(request.url.split('?')[0])) { return }\n const result = await validateToken(request.headers.authorization, auth, context.fork({ request }))\n if (result.error) {\n for (const [key, value] of Object.entries(result.error.headers)) {\n reply.header(key, value)\n }\n return reply.status(result.error.statusCode).send(result.error.body)\n }\n if (result.auth) {\n (request as FastifyRequest & { __silkweave_auth?: AuthInfo }).__silkweave_auth = result.auth\n }\n })\n}\n\ntype StreamFormat = 'sse' | 'ndjson'\n\nfunction pickStreamFormat(acceptHeader: string | undefined): StreamFormat | null {\n if (!acceptHeader) { return null }\n if (acceptHeader.includes('text/event-stream')) { return 'sse' }\n if (acceptHeader.includes('application/x-ndjson') || acceptHeader.includes('application/ndjson')) { return 'ndjson' }\n return null\n}\n\nfunction encodeChunk(format: StreamFormat, chunk: unknown): string {\n const payload = JSON.stringify(chunk)\n return format === 'sse' ? `data: ${payload}\\n\\n` : `${payload}\\n`\n}\n\nfunction encodeStreamError(format: StreamFormat, error: unknown): string {\n const payload = JSON.stringify({\n error: error instanceof Error ? error.message : String(error),\n name: error instanceof Error ? error.name : 'Error'\n })\n return format === 'sse' ? `event: error\\ndata: ${payload}\\n\\n` : `${payload}\\n`\n}\n\nasync function streamAction(\n reply: FastifyReply,\n format: StreamFormat,\n action: Action,\n input: object,\n context: SilkweaveContext\n): Promise<void> {\n reply.raw.setHeader('Content-Type', format === 'sse' ? 'text/event-stream' : 'application/x-ndjson')\n reply.raw.setHeader('Cache-Control', 'no-cache, no-transform')\n reply.raw.setHeader('Connection', 'keep-alive')\n reply.raw.flushHeaders?.()\n reply.hijack()\n const raw = reply.raw\n const iter = (action.run as ActionStreamRun<object, unknown>)(input, context)\n // On client disconnect the next write() returns false and a plain\n // `once(raw, 'drain')` would park forever - the generator would never resume,\n // its finally/cleanup would never run, and response/context stay pinned. Track\n // 'close' and race the drain against it so we bail and tear the generator down.\n const gone = { value: raw.destroyed || raw.writableEnded }\n const onClose = () => { gone.value = true }\n raw.on('close', onClose)\n const closed = once(raw, 'close')\n try {\n for await (const chunk of iter) {\n if (gone.value) { break }\n if (!raw.write(encodeChunk(format, chunk))) {\n await Promise.race([once(raw, 'drain'), closed])\n if (gone.value) { break }\n }\n }\n if (!gone.value && format === 'sse') { raw.write('event: done\\ndata: {}\\n\\n') }\n } catch (error) {\n if (!gone.value) { raw.write(encodeStreamError(format, error)) }\n } finally {\n raw.off('close', onClose)\n // Ask the generator to run its finally/cleanup (release DB handles etc).\n await iter.return?.().catch(() => { /* generator cleanup best-effort */ })\n if (!raw.writableEnded) { raw.end() }\n }\n}\n\nfunction createActionLogger(instance: FastifyInstance): Logger {\n return {\n ...buildLogLevels((level, data) => {\n const pinoLevel = PINO_LEVEL_MAP[level] ?? 'info'\n instance.log[pinoLevel](data)\n }),\n progress: ({ progress, total, message }) => { instance.log.trace({ progress, total }, message) }\n }\n}\n\ninterface ObjectSchema {\n type: 'object'\n properties: Record<string, unknown>\n required: string[]\n}\n\n/**\n * Split an action's input JSON Schema into Fastify `params`/`querystring`/`body`\n * schemas based on its `path` placeholders and `queryParams`. Fastify's own AJV\n * validation, type coercion, and default-filling then apply per source, and the\n * three are merged back into a single input by `resolveActionInput` at runtime.\n */\nfunction splitInputSchema(action: Action, method: HttpMethod): {\n params?: ObjectSchema\n querystring?: ObjectSchema\n body?: ObjectSchema\n} {\n const json = z.toJSONSchema(action.input) as { properties?: Record<string, unknown>; required?: string[] }\n const properties = json.properties ?? {}\n const required = new Set(json.required ?? [])\n const pathParams = new Set(pathParamNames(action.path))\n const queryKeys = new Set((action.queryParams ?? []).map(String))\n const hasBody = methodHasBody(method)\n\n const params: ObjectSchema = { type: 'object', properties: {}, required: [] }\n const querystring: ObjectSchema = { type: 'object', properties: {}, required: [] }\n const body: ObjectSchema = { type: 'object', properties: {}, required: [] }\n\n for (const [key, prop] of Object.entries(properties)) {\n if (pathParams.has(key)) {\n params.properties[key] = prop\n params.required.push(key)\n } else if (!hasBody || queryKeys.has(key)) {\n querystring.properties[key] = prop\n if (required.has(key)) { querystring.required.push(key) }\n } else {\n body.properties[key] = prop\n if (required.has(key)) { body.required.push(key) }\n }\n }\n\n return {\n params: Object.keys(params.properties).length ? params : undefined,\n querystring: Object.keys(querystring.properties).length ? querystring : undefined,\n body: hasBody && Object.keys(body.properties).length ? body : undefined\n }\n}\n\n/**\n * Register the Scalar API-reference UI. It's an optional peer, so a missing\n * module is skipped with a hint rather than crashing a headless deployment.\n * Resolving the import here (vs. handing `register` a rejecting plugin promise)\n * is what makes the absence catchable now instead of later during `listen`.\n */\nasync function registerScalarDocs(instance: FastifyInstance): Promise<void> {\n const scalar = await import('@scalar/fastify-api-reference').catch((error: unknown) => {\n const code = (error as { code?: string }).code\n if (code === 'ERR_MODULE_NOT_FOUND' || code === 'MODULE_NOT_FOUND') {\n instance.log.info('@scalar/fastify-api-reference is not installed - skipping the API reference UI. Install it to enable the docs UI.')\n return null\n }\n throw error\n })\n if (scalar) {\n await instance.register(scalar.default, { routePrefix: '/' })\n }\n}\n\nexport const fastify: AdapterFactory<FastifyAdapterOptions> = ({ host, port, auth, cors: corsConfig, ...fastifyOptions }) => {\n const instance = fastifyInstance(fastifyOptions)\n return (options, baseContext) => {\n const context = baseContext.fork({ adapter: 'fastify' })\n return {\n context,\n start: async (actions) => {\n if (corsConfig !== false) {\n const userConfig = corsConfig === true || corsConfig === undefined ? {} : corsConfig\n await instance.register(import('@fastify/cors'), { origin: '*', ...userConfig })\n }\n\n await instance.register(import('@fastify/swagger'), {\n openapi: {\n info: {\n title: options.name,\n description: options.description,\n version: options.version\n }\n }\n })\n await registerScalarDocs(instance)\n\n if (auth?.authorizationServers?.length && auth.resourceUrl) {\n instance.get('/.well-known/oauth-protected-resource', () => {\n return generateProtectedResourceMetadata(auth.resourceUrl!, auth.authorizationServers!, auth.requiredScopes)\n })\n }\n\n const oauthPaths = auth?.provider ? mountOAuthRoutes(instance, auth) : new Set<string>()\n\n if (auth) {\n mountAuthMiddleware(instance, auth, oauthPaths, context)\n }\n\n instance.setErrorHandler((error, _request, reply) => {\n if (error instanceof SilkweaveError) {\n return reply.status(error.statusCode).send({ error: error.code, message: error.message })\n }\n if (error instanceof z.ZodError) {\n return reply.status(400).send({ error: 'validation_error', issues: error.issues })\n }\n // Fastify's schema (AJV) validation failures for body/querystring/params.\n const validation = (error as { validation?: unknown }).validation\n if (validation) {\n return reply.status(400).send({ error: 'validation_error', issues: validation })\n }\n instance.log.error(error)\n return reply.status(500).send({ error: 'internal', message: 'Internal server error' })\n })\n\n const logger = createActionLogger(instance)\n\n for (const action of actions) {\n validateActionRouting(action)\n const method = actionMethod(action)\n const url = action.path ? `/${action.path.replace(/^\\//, '')}` : `/${action.name}`\n const { params, querystring, body } = splitInputSchema(action, method)\n const streaming = isStreamingAction(action)\n instance.route({\n method,\n url,\n schema: {\n description: action.description,\n ...(params ? { params } : {}),\n ...(querystring ? { querystring } : {}),\n ...(body ? { body } : {}),\n response: {\n 200: { description: 'Successful response' }\n }\n },\n handler: async (request, reply) => {\n const authInfo = auth ? (request as FastifyRequest & { __silkweave_auth?: AuthInfo }).__silkweave_auth : undefined\n const actionContext = context.fork({ logger, request, ...(authInfo ? { auth: authInfo } : {}) })\n // Fastify's AJV only validates the JSON-Schema projection, which\n // cannot express Zod refinements/transforms. Parse the merged input\n // so .refine()/.email()/.transform() are enforced here as they are\n // over MCP/tRPC/CLI (a ZodError becomes a 400 via setErrorHandler).\n const input = action.input.parse(resolveActionInput(action, {\n params: request.params as Record<string, string | undefined>,\n query: request.query as Record<string, unknown>,\n body: request.body\n }))\n if (streaming) {\n const format = pickStreamFormat(request.headers.accept)\n if (format) {\n await streamAction(reply, format, action, input, actionContext)\n return reply\n }\n return runStreamingAction(action, input, actionContext)\n }\n return action.run(input, actionContext)\n }\n })\n }\n await instance.listen({ host, port })\n },\n stop: async () => { await instance.close() }\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["fastifyInstance"],"sources":["../src/adapter/fastify.ts"],"sourcesContent":["import type { FastifyCorsOptions } from '@fastify/cors'\nimport { AuthConfig, AuthInfo, generateProtectedResourceMetadata, OAuthRequest, OAuthResponse, validateToken } from '@silkweave/auth'\nimport { Action, actionMethod, ActionStreamRun, AdapterFactory, binarySchemaMeta, buildLogLevels, HttpMethod, isBinarySchema, isStreamingAction, Logger, LogLevel, methodHasBody, pathParamNames, resolveActionInput, resourceBytes, runStreamingAction, SilkweaveContext, SilkweaveError, toActionResource, validateActionRouting, type ActionResource } from '@silkweave/core'\nimport { once } from 'events'\nimport { FastifyBaseLogger, FastifyHttpOptions, fastify as fastifyInstance, FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'\nimport { Server } from 'http'\nimport z from 'zod/v4'\n\ntype FastifyLogLevel = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace'\n\nconst PINO_LEVEL_MAP: Record<LogLevel, FastifyLogLevel> = {\n emergency: 'fatal',\n alert: 'fatal',\n critical: 'fatal',\n error: 'error',\n warning: 'warn',\n notice: 'debug',\n info: 'info',\n debug: 'debug'\n}\n\nexport interface FastifyAdapterOptions extends FastifyHttpOptions<Server, FastifyBaseLogger> {\n host?: string\n port?: number\n auth?: AuthConfig\n /** CORS configuration. `false` to disable, `true`/`undefined` for permissive defaults, or a FastifyCorsOptions object. */\n cors?: FastifyCorsOptions | boolean\n}\n\nfunction toOAuthReq(request: FastifyRequest): OAuthRequest {\n return {\n method: request.method,\n url: new URL(request.url, `http://${request.hostname}`),\n headers: Object.fromEntries(Object.entries(request.headers).map(([k, v]) => [k, Array.isArray(v) ? v[0] : v])),\n body: request.body as Record<string, string> | undefined\n }\n}\n\nfunction sendOAuth(reply: FastifyReply, oauthRes: OAuthResponse) {\n for (const [key, value] of Object.entries(oauthRes.headers)) { reply.header(key, value) }\n return reply.status(oauthRes.status).send(oauthRes.body)\n}\n\nfunction mountOAuthRoutes(instance: FastifyInstance, auth: AuthConfig): Set<string> {\n const provider = auth.provider!\n // The provider builds its upstream redirect_uri as `${resourceUrl}${callbackPath}`,\n // so the callback route must match the configured callbackPath, not a hardcoded one.\n const callbackPath = auth.callbackPath ?? '/auth/callback'\n\n const paths = new Set([\n '/.well-known/oauth-authorization-server',\n '/authorize',\n callbackPath,\n '/token',\n '/register'\n ])\n\n instance.get('/.well-known/oauth-authorization-server', async (_req, reply) => {\n return sendOAuth(reply, provider.metadata())\n })\n instance.get('/authorize', async (req, reply) => {\n return sendOAuth(reply, await provider.authorize(toOAuthReq(req)))\n })\n instance.get(callbackPath, async (req, reply) => {\n return sendOAuth(reply, await provider.callback(toOAuthReq(req)))\n })\n instance.post('/token', async (req, reply) => {\n return sendOAuth(reply, await provider.token(toOAuthReq(req)))\n })\n instance.post('/register', async (req, reply) => {\n return sendOAuth(reply, await provider.register(toOAuthReq(req)))\n })\n\n return paths\n}\n\nfunction mountAuthMiddleware(instance: FastifyInstance, auth: AuthConfig, oauthPaths: Set<string>, context: SilkweaveContext) {\n instance.decorateRequest('__silkweave_auth', undefined)\n instance.addHook('onRequest', async (request: FastifyRequest, reply: FastifyReply) => {\n if (request.url.startsWith('/.well-known/') || oauthPaths.has(request.url.split('?')[0])) { return }\n const result = await validateToken(request.headers.authorization, auth, context.fork({ request }))\n if (result.error) {\n for (const [key, value] of Object.entries(result.error.headers)) {\n reply.header(key, value)\n }\n return reply.status(result.error.statusCode).send(result.error.body)\n }\n if (result.auth) {\n (request as FastifyRequest & { __silkweave_auth?: AuthInfo }).__silkweave_auth = result.auth\n }\n })\n}\n\ntype StreamFormat = 'sse' | 'ndjson'\n\nfunction pickStreamFormat(acceptHeader: string | undefined): StreamFormat | null {\n if (!acceptHeader) { return null }\n if (acceptHeader.includes('text/event-stream')) { return 'sse' }\n if (acceptHeader.includes('application/x-ndjson') || acceptHeader.includes('application/ndjson')) { return 'ndjson' }\n return null\n}\n\nfunction encodeChunk(format: StreamFormat, chunk: unknown): string {\n const payload = JSON.stringify(chunk)\n return format === 'sse' ? `data: ${payload}\\n\\n` : `${payload}\\n`\n}\n\nfunction encodeStreamError(format: StreamFormat, error: unknown): string {\n const payload = JSON.stringify({\n error: error instanceof Error ? error.message : String(error),\n name: error instanceof Error ? error.name : 'Error'\n })\n return format === 'sse' ? `event: error\\ndata: ${payload}\\n\\n` : `${payload}\\n`\n}\n\nasync function streamAction(\n reply: FastifyReply,\n format: StreamFormat,\n action: Action,\n input: object,\n context: SilkweaveContext\n): Promise<void> {\n reply.raw.setHeader('Content-Type', format === 'sse' ? 'text/event-stream' : 'application/x-ndjson')\n reply.raw.setHeader('Cache-Control', 'no-cache, no-transform')\n reply.raw.setHeader('Connection', 'keep-alive')\n reply.raw.flushHeaders?.()\n reply.hijack()\n const raw = reply.raw\n const iter = (action.run as ActionStreamRun<object, unknown>)(input, context)\n // On client disconnect the next write() returns false and a plain\n // `once(raw, 'drain')` would park forever - the generator would never resume,\n // its finally/cleanup would never run, and response/context stay pinned. Track\n // 'close' and race the drain against it so we bail and tear the generator down.\n const gone = { value: raw.destroyed || raw.writableEnded }\n const onClose = () => { gone.value = true }\n raw.on('close', onClose)\n const closed = once(raw, 'close')\n try {\n for await (const chunk of iter) {\n if (gone.value) { break }\n if (!raw.write(encodeChunk(format, chunk))) {\n await Promise.race([once(raw, 'drain'), closed])\n if (gone.value) { break }\n }\n }\n if (!gone.value && format === 'sse') { raw.write('event: done\\ndata: {}\\n\\n') }\n } catch (error) {\n if (!gone.value) { raw.write(encodeStreamError(format, error)) }\n } finally {\n raw.off('close', onClose)\n // Ask the generator to run its finally/cleanup (release DB handles etc).\n await iter.return?.().catch(() => { /* generator cleanup best-effort */ })\n if (!raw.writableEnded) { raw.end() }\n }\n}\n\nfunction createActionLogger(instance: FastifyInstance): Logger {\n return {\n ...buildLogLevels((level, data) => {\n const pinoLevel = PINO_LEVEL_MAP[level] ?? 'info'\n instance.log[pinoLevel](data)\n }),\n progress: ({ progress, total, message }) => { instance.log.trace({ progress, total }, message) }\n }\n}\n\ninterface ObjectSchema {\n type: 'object'\n properties: Record<string, unknown>\n required: string[]\n}\n\n/**\n * Split an action's input JSON Schema into Fastify `params`/`querystring`/`body`\n * schemas based on its `path` placeholders and `queryParams`. Fastify's own AJV\n * validation, type coercion, and default-filling then apply per source, and the\n * three are merged back into a single input by `resolveActionInput` at runtime.\n */\nfunction splitInputSchema(action: Action, method: HttpMethod): {\n params?: ObjectSchema\n querystring?: ObjectSchema\n body?: ObjectSchema\n} {\n const json = z.toJSONSchema(action.input) as { properties?: Record<string, unknown>; required?: string[] }\n const properties = json.properties ?? {}\n const required = new Set(json.required ?? [])\n const pathParams = new Set(pathParamNames(action.path))\n const queryKeys = new Set((action.queryParams ?? []).map(String))\n const hasBody = methodHasBody(method)\n\n const params: ObjectSchema = { type: 'object', properties: {}, required: [] }\n const querystring: ObjectSchema = { type: 'object', properties: {}, required: [] }\n const body: ObjectSchema = { type: 'object', properties: {}, required: [] }\n\n for (const [key, prop] of Object.entries(properties)) {\n if (pathParams.has(key)) {\n params.properties[key] = prop\n params.required.push(key)\n } else if (!hasBody || queryKeys.has(key)) {\n querystring.properties[key] = prop\n if (required.has(key)) { querystring.required.push(key) }\n } else {\n body.properties[key] = prop\n if (required.has(key)) { body.required.push(key) }\n }\n }\n\n return {\n params: Object.keys(params.properties).length ? params : undefined,\n querystring: Object.keys(querystring.properties).length ? querystring : undefined,\n body: hasBody && Object.keys(body.properties).length ? body : undefined\n }\n}\n\n/** Strip characters that would break (or smuggle headers into) an HTTP header value. */\nfunction headerSafe(value: string): string {\n return value.replace(/[\"\\r\\n]/g, ' ').trim()\n}\n\n/**\n * Send a resource result as a raw HTTP body: bytes with `Content-Type` from\n * the resource's media type, a `Content-Disposition` filename when the\n * resource carries a name, and the description (if any) as\n * `Content-Description` - over REST the binary itself IS the response, so the\n * metadata rides in headers.\n */\nfunction sendResource(reply: FastifyReply, res: ActionResource) {\n reply.header('Content-Type', res.mimeType)\n if (res.name) { reply.header('Content-Disposition', `inline; filename=\"${headerSafe(res.name)}\"`) }\n if (res.description) { reply.header('Content-Description', headerSafe(res.description)) }\n return reply.send(Buffer.from(resourceBytes(res)))\n}\n\n/**\n * OpenAPI response schema: binary actions document their payload as\n * `type: string, format: binary` under the declared media type.\n */\nfunction responseSchema(action: Action) {\n if (!isBinarySchema(action.output)) {\n return { 200: { description: 'Successful response' } }\n }\n const mimeType = binarySchemaMeta(action.output).mimeType ?? 'application/octet-stream'\n return {\n 200: {\n description: 'Successful response',\n content: { [mimeType]: { schema: { type: 'string', format: 'binary' } } }\n }\n }\n}\n\n/**\n * Register the Scalar API-reference UI. It's an optional peer, so a missing\n * module is skipped with a hint rather than crashing a headless deployment.\n * Resolving the import here (vs. handing `register` a rejecting plugin promise)\n * is what makes the absence catchable now instead of later during `listen`.\n */\nasync function registerScalarDocs(instance: FastifyInstance): Promise<void> {\n const scalar = await import('@scalar/fastify-api-reference').catch((error: unknown) => {\n const code = (error as { code?: string }).code\n if (code === 'ERR_MODULE_NOT_FOUND' || code === 'MODULE_NOT_FOUND') {\n instance.log.info('@scalar/fastify-api-reference is not installed - skipping the API reference UI. Install it to enable the docs UI.')\n return null\n }\n throw error\n })\n if (scalar) {\n await instance.register(scalar.default, { routePrefix: '/' })\n }\n}\n\n/** The instance-wide error handler: Silkweave/Zod/AJV failures map to legible statuses. */\nfunction errorHandler(instance: FastifyInstance) {\n return (error: Error, _request: FastifyRequest, reply: FastifyReply) => {\n if (error instanceof SilkweaveError) {\n return reply.status(error.statusCode).send({ error: error.code, message: error.message })\n }\n if (error instanceof z.ZodError) {\n return reply.status(400).send({ error: 'validation_error', issues: error.issues })\n }\n // Fastify's schema (AJV) validation failures for body/querystring/params.\n const validation = (error as { validation?: unknown }).validation\n if (validation) {\n return reply.status(400).send({ error: 'validation_error', issues: validation })\n }\n instance.log.error(error)\n return reply.status(500).send({ error: 'internal', message: 'Internal server error' })\n }\n}\n\n/** Register one action as a Fastify route (validation, streaming, resource, and JSON paths). */\nfunction registerActionRoute(instance: FastifyInstance, action: Action, context: SilkweaveContext, logger: Logger, hasAuth: boolean) {\n validateActionRouting(action)\n const method = actionMethod(action)\n const url = action.path ? `/${action.path.replace(/^\\//, '')}` : `/${action.name}`\n const { params, querystring, body } = splitInputSchema(action, method)\n const streaming = isStreamingAction(action)\n instance.route({\n method,\n url,\n schema: {\n description: action.description,\n ...(params ? { params } : {}),\n ...(querystring ? { querystring } : {}),\n ...(body ? { body } : {}),\n response: responseSchema(action)\n },\n handler: async (request, reply) => {\n const authInfo = hasAuth ? (request as FastifyRequest & { __silkweave_auth?: AuthInfo }).__silkweave_auth : undefined\n const actionContext = context.fork({ logger, request, ...(authInfo ? { auth: authInfo } : {}) })\n // Fastify's AJV only validates the JSON-Schema projection, which\n // cannot express Zod refinements/transforms. Parse the merged input\n // so .refine()/.email()/.transform() are enforced here as they are\n // over MCP/tRPC/CLI (a ZodError becomes a 400 via setErrorHandler).\n const input = action.input.parse(resolveActionInput(action, {\n params: request.params as Record<string, string | undefined>,\n query: request.query as Record<string, unknown>,\n body: request.body\n }))\n if (streaming) {\n const format = pickStreamFormat(request.headers.accept)\n if (format) {\n await streamAction(reply, format, action, input, actionContext)\n return reply\n }\n return runStreamingAction(action, input, actionContext)\n }\n const result = await (action.run as (input: object, context: SilkweaveContext) => Promise<object>)(input, actionContext)\n // A resource result (resource()/File/Blob/bytes) leaves as raw\n // bytes with mime headers instead of JSON.\n const res = await toActionResource(result, binarySchemaMeta(action.output))\n if (res) { return sendResource(reply, res) }\n return result\n }\n })\n}\n\nexport const fastify: AdapterFactory<FastifyAdapterOptions> = ({ host, port, auth, cors: corsConfig, ...fastifyOptions }) => {\n const instance = fastifyInstance(fastifyOptions)\n return (options, baseContext) => {\n const context = baseContext.fork({ adapter: 'fastify' })\n return {\n context,\n start: async (actions) => {\n if (corsConfig !== false) {\n const userConfig = corsConfig === true || corsConfig === undefined ? {} : corsConfig\n await instance.register(import('@fastify/cors'), { origin: '*', ...userConfig })\n }\n\n await instance.register(import('@fastify/swagger'), {\n openapi: {\n info: {\n title: options.name,\n description: options.description,\n version: options.version\n }\n }\n })\n await registerScalarDocs(instance)\n\n if (auth?.authorizationServers?.length && auth.resourceUrl) {\n instance.get('/.well-known/oauth-protected-resource', () => {\n return generateProtectedResourceMetadata(auth.resourceUrl!, auth.authorizationServers!, auth.requiredScopes)\n })\n }\n\n const oauthPaths = auth?.provider ? mountOAuthRoutes(instance, auth) : new Set<string>()\n\n if (auth) {\n mountAuthMiddleware(instance, auth, oauthPaths, context)\n }\n\n instance.setErrorHandler(errorHandler(instance))\n\n const logger = createActionLogger(instance)\n\n for (const action of actions) {\n registerActionRoute(instance, action, context, logger, Boolean(auth))\n }\n await instance.listen({ host, port })\n },\n stop: async () => { await instance.close() }\n }\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@silkweave/fastify",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Silkweave Fastify REST Adapter",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://www.silkweave.dev",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"@fastify/swagger": "^9.7.0",
|
|
31
31
|
"fastify": "^5.8.2",
|
|
32
32
|
"zod": "^3.25.0",
|
|
33
|
-
"@silkweave/auth": "
|
|
34
|
-
"@silkweave/core": "
|
|
33
|
+
"@silkweave/auth": "5.0.0",
|
|
34
|
+
"@silkweave/core": "5.0.0"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
37
|
"@scalar/fastify-api-reference": "^1.49.0"
|