@silkweave/fastify 1.3.0 → 1.3.2
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/.turbo/turbo-build.log +17 -18
- package/.turbo/turbo-check.log +12 -13
- package/.turbo/turbo-lint.log +1 -2
- package/.turbo/turbo-prepack.log +8 -8
- package/README.md +2 -2
- package/build/index.js +84 -61
- package/build/index.js.map +1 -1
- package/package.json +5 -5
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
DTS Build
|
|
17
|
-
DTS
|
|
18
|
-
DTS build/index.d.ts 455.00 B
|
|
1
|
+
|
|
2
|
+
> @silkweave/fastify@1.3.1 build /Users/atomic/projects/ai/silkweave/packages/fastify
|
|
3
|
+
> tsup
|
|
4
|
+
|
|
5
|
+
CLI Building entry: src/index.ts
|
|
6
|
+
CLI Using tsconfig: tsconfig.json
|
|
7
|
+
CLI tsup v8.5.1
|
|
8
|
+
CLI Using tsup config: /Users/atomic/projects/ai/silkweave/packages/fastify/tsup.config.ts
|
|
9
|
+
CLI Target: es2022
|
|
10
|
+
CLI Cleaning output folder
|
|
11
|
+
ESM Build start
|
|
12
|
+
ESM build/index.js 5.31 KB
|
|
13
|
+
ESM build/index.js.map 10.01 KB
|
|
14
|
+
ESM ⚡️ Build success in 6ms
|
|
15
|
+
DTS Build start
|
|
16
|
+
DTS ⚡️ Build success in 898ms
|
|
17
|
+
DTS build/index.d.ts 455.00 B
|
package/.turbo/turbo-check.log
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
>
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
>
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
|
|
2
|
+
> @silkweave/fastify@1.3.1 check /Users/atomic/projects/ai/silkweave/packages/fastify
|
|
3
|
+
> pnpm lint && pnpm typecheck
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
> @silkweave/fastify@1.3.1 lint /Users/atomic/projects/ai/silkweave/packages/fastify
|
|
7
|
+
> eslint
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
> @silkweave/fastify@1.3.1 typecheck /Users/atomic/projects/ai/silkweave/packages/fastify
|
|
11
|
+
> tsc --noEmit
|
|
12
|
+
|
package/.turbo/turbo-lint.log
CHANGED
package/.turbo/turbo-prepack.log
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
> @silkweave/fastify@1.3.0 prepack /Users/atomic/projects/ai/
|
|
3
|
+
> @silkweave/fastify@1.3.0 prepack /Users/atomic/projects/ai/silkweave/packages/fastify
|
|
4
4
|
> pnpm clean && pnpm build
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
> @silkweave/fastify@1.3.0 clean /Users/atomic/projects/ai/
|
|
7
|
+
> @silkweave/fastify@1.3.0 clean /Users/atomic/projects/ai/silkweave/packages/fastify
|
|
8
8
|
> rimraf build
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
> @silkweave/fastify@1.3.0 build /Users/atomic/projects/ai/
|
|
11
|
+
> @silkweave/fastify@1.3.0 build /Users/atomic/projects/ai/silkweave/packages/fastify
|
|
12
12
|
> tsup
|
|
13
13
|
|
|
14
14
|
[34mCLI[39m Building entry: src/index.ts
|
|
15
15
|
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
16
16
|
[34mCLI[39m tsup v8.5.1
|
|
17
|
-
[34mCLI[39m Using tsup config: /Users/atomic/projects/ai/
|
|
17
|
+
[34mCLI[39m Using tsup config: /Users/atomic/projects/ai/silkweave/packages/fastify/tsup.config.ts
|
|
18
18
|
[34mCLI[39m Target: es2022
|
|
19
19
|
[34mCLI[39m Cleaning output folder
|
|
20
20
|
[34mESM[39m Build start
|
|
21
|
-
[32mESM[39m [1mbuild/index.js [22m[
|
|
22
|
-
[32mESM[39m [1mbuild/index.js.map [22m[
|
|
23
|
-
[32mESM[39m ⚡️ Build success in
|
|
21
|
+
[32mESM[39m [1mbuild/index.js [22m[32m5.54 KB[39m
|
|
22
|
+
[32mESM[39m [1mbuild/index.js.map [22m[32m9.94 KB[39m
|
|
23
|
+
[32mESM[39m ⚡️ Build success in 13ms
|
|
24
24
|
DTS Build start
|
|
25
|
-
DTS ⚡️ Build success in
|
|
25
|
+
DTS ⚡️ Build success in 984ms
|
|
26
26
|
DTS build/index.d.ts 455.00 B
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @silkweave/fastify
|
|
2
2
|
|
|
3
|
-
Fastify REST adapter for [Silkweave](https://github.com/
|
|
3
|
+
Fastify REST adapter for [Silkweave](https://github.com/silkweave/silkweave) — expose your actions as a REST API with auto-generated OpenAPI/Swagger documentation.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -56,5 +56,5 @@ fastify({
|
|
|
56
56
|
|
|
57
57
|
## See Also
|
|
58
58
|
|
|
59
|
-
- [Silkweave README](https://github.com/
|
|
59
|
+
- [Silkweave README](https://github.com/silkweave/silkweave) — Full documentation
|
|
60
60
|
- [`@silkweave/core`](https://www.npmjs.com/package/@silkweave/core) — Core library
|
package/build/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// src/adapter/fastify.ts
|
|
2
2
|
import { generateProtectedResourceMetadata, validateToken } from "@silkweave/auth";
|
|
3
|
+
import { SilkweaveError } from "@silkweave/core";
|
|
3
4
|
import { buildLogLevels } from "@silkweave/logger";
|
|
4
5
|
import { fastify as fastifyInstance } from "fastify";
|
|
6
|
+
import z from "zod";
|
|
5
7
|
var PINO_LEVEL_MAP = {
|
|
6
8
|
emergency: "fatal",
|
|
7
9
|
alert: "fatal",
|
|
@@ -12,6 +14,75 @@ var PINO_LEVEL_MAP = {
|
|
|
12
14
|
info: "info",
|
|
13
15
|
debug: "debug"
|
|
14
16
|
};
|
|
17
|
+
function toOAuthReq(request) {
|
|
18
|
+
return {
|
|
19
|
+
method: request.method,
|
|
20
|
+
url: new URL(request.url, `http://${request.hostname}`),
|
|
21
|
+
headers: Object.fromEntries(Object.entries(request.headers).map(([k, v]) => [k, Array.isArray(v) ? v[0] : v])),
|
|
22
|
+
body: request.body
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function sendOAuth(reply, oauthRes) {
|
|
26
|
+
for (const [key, value] of Object.entries(oauthRes.headers)) {
|
|
27
|
+
reply.header(key, value);
|
|
28
|
+
}
|
|
29
|
+
return reply.status(oauthRes.status).send(oauthRes.body);
|
|
30
|
+
}
|
|
31
|
+
function mountOAuthRoutes(instance, auth) {
|
|
32
|
+
const provider = auth.provider;
|
|
33
|
+
const paths = /* @__PURE__ */ new Set([
|
|
34
|
+
"/.well-known/oauth-authorization-server",
|
|
35
|
+
"/authorize",
|
|
36
|
+
"/auth/callback",
|
|
37
|
+
"/token",
|
|
38
|
+
"/register"
|
|
39
|
+
]);
|
|
40
|
+
instance.get("/.well-known/oauth-authorization-server", async (_req, reply) => {
|
|
41
|
+
return sendOAuth(reply, provider.metadata());
|
|
42
|
+
});
|
|
43
|
+
instance.get("/authorize", async (req, reply) => {
|
|
44
|
+
return sendOAuth(reply, await provider.authorize(toOAuthReq(req)));
|
|
45
|
+
});
|
|
46
|
+
instance.get("/auth/callback", async (req, reply) => {
|
|
47
|
+
return sendOAuth(reply, await provider.callback(toOAuthReq(req)));
|
|
48
|
+
});
|
|
49
|
+
instance.post("/token", async (req, reply) => {
|
|
50
|
+
return sendOAuth(reply, await provider.token(toOAuthReq(req)));
|
|
51
|
+
});
|
|
52
|
+
instance.post("/register", async (req, reply) => {
|
|
53
|
+
return sendOAuth(reply, await provider.register(toOAuthReq(req)));
|
|
54
|
+
});
|
|
55
|
+
return paths;
|
|
56
|
+
}
|
|
57
|
+
function mountAuthMiddleware(instance, auth, oauthPaths) {
|
|
58
|
+
instance.decorateRequest("__silkweave_auth", void 0);
|
|
59
|
+
instance.addHook("onRequest", async (request, reply) => {
|
|
60
|
+
if (request.url.startsWith("/.well-known/") || oauthPaths.has(request.url.split("?")[0])) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const result = await validateToken(request.headers.authorization, auth);
|
|
64
|
+
if (result.error) {
|
|
65
|
+
for (const [key, value] of Object.entries(result.error.headers)) {
|
|
66
|
+
reply.header(key, value);
|
|
67
|
+
}
|
|
68
|
+
return reply.status(result.error.statusCode).send(result.error.body);
|
|
69
|
+
}
|
|
70
|
+
if (result.auth) {
|
|
71
|
+
request.__silkweave_auth = result.auth;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function createActionLogger(instance) {
|
|
76
|
+
return {
|
|
77
|
+
...buildLogLevels((level, data) => {
|
|
78
|
+
const pinoLevel = PINO_LEVEL_MAP[level] ?? "info";
|
|
79
|
+
instance.log[pinoLevel](data);
|
|
80
|
+
}),
|
|
81
|
+
progress: ({ progress, total, message }) => {
|
|
82
|
+
instance.log.trace({ progress, total }, message);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
15
86
|
var fastify = ({ host, port, auth, ...fastifyOptions }) => {
|
|
16
87
|
const instance = fastifyInstance(fastifyOptions);
|
|
17
88
|
return (options, baseContext) => {
|
|
@@ -34,60 +105,21 @@ var fastify = ({ host, port, auth, ...fastifyOptions }) => {
|
|
|
34
105
|
return generateProtectedResourceMetadata(auth.resourceUrl, auth.authorizationServers);
|
|
35
106
|
});
|
|
36
107
|
}
|
|
37
|
-
const oauthPaths = /* @__PURE__ */ new Set();
|
|
38
|
-
if (auth?.provider) {
|
|
39
|
-
const provider = auth.provider;
|
|
40
|
-
const toOAuthReq = (request) => ({
|
|
41
|
-
method: request.method,
|
|
42
|
-
url: new URL(request.url, `http://${request.hostname}`),
|
|
43
|
-
headers: Object.fromEntries(Object.entries(request.headers).map(([k, v]) => [k, Array.isArray(v) ? v[0] : v])),
|
|
44
|
-
body: request.body
|
|
45
|
-
});
|
|
46
|
-
const sendOAuth = (reply, oauthRes) => {
|
|
47
|
-
for (const [key, value] of Object.entries(oauthRes.headers)) {
|
|
48
|
-
reply.header(key, value);
|
|
49
|
-
}
|
|
50
|
-
return reply.status(oauthRes.status).send(oauthRes.body);
|
|
51
|
-
};
|
|
52
|
-
oauthPaths.add("/.well-known/oauth-authorization-server");
|
|
53
|
-
oauthPaths.add("/authorize");
|
|
54
|
-
oauthPaths.add("/auth/callback");
|
|
55
|
-
oauthPaths.add("/token");
|
|
56
|
-
oauthPaths.add("/register");
|
|
57
|
-
instance.get("/.well-known/oauth-authorization-server", async (_req, reply) => {
|
|
58
|
-
return sendOAuth(reply, provider.metadata());
|
|
59
|
-
});
|
|
60
|
-
instance.get("/authorize", async (req, reply) => {
|
|
61
|
-
return sendOAuth(reply, await provider.authorize(toOAuthReq(req)));
|
|
62
|
-
});
|
|
63
|
-
instance.get("/auth/callback", async (req, reply) => {
|
|
64
|
-
return sendOAuth(reply, await provider.callback(toOAuthReq(req)));
|
|
65
|
-
});
|
|
66
|
-
instance.post("/token", async (req, reply) => {
|
|
67
|
-
return sendOAuth(reply, await provider.token(toOAuthReq(req)));
|
|
68
|
-
});
|
|
69
|
-
instance.post("/register", async (req, reply) => {
|
|
70
|
-
return sendOAuth(reply, await provider.register(toOAuthReq(req)));
|
|
71
|
-
});
|
|
72
|
-
}
|
|
108
|
+
const oauthPaths = auth?.provider ? mountOAuthRoutes(instance, auth) : /* @__PURE__ */ new Set();
|
|
73
109
|
if (auth) {
|
|
74
|
-
instance
|
|
75
|
-
instance.addHook("onRequest", async (request, reply) => {
|
|
76
|
-
if (request.url.startsWith("/.well-known/") || oauthPaths.has(request.url.split("?")[0])) {
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
const result = await validateToken(request.headers.authorization, auth);
|
|
80
|
-
if (result.error) {
|
|
81
|
-
for (const [key, value] of Object.entries(result.error.headers)) {
|
|
82
|
-
reply.header(key, value);
|
|
83
|
-
}
|
|
84
|
-
return reply.status(result.error.statusCode).send(result.error.body);
|
|
85
|
-
}
|
|
86
|
-
if (result.auth) {
|
|
87
|
-
request.__silkweave_auth = result.auth;
|
|
88
|
-
}
|
|
89
|
-
});
|
|
110
|
+
mountAuthMiddleware(instance, auth, oauthPaths);
|
|
90
111
|
}
|
|
112
|
+
instance.setErrorHandler((error, _request, reply) => {
|
|
113
|
+
if (error instanceof SilkweaveError) {
|
|
114
|
+
return reply.status(error.statusCode).send({ error: error.code, message: error.message });
|
|
115
|
+
}
|
|
116
|
+
if (error instanceof z.ZodError) {
|
|
117
|
+
return reply.status(400).send({ error: "validation_error", issues: error.issues });
|
|
118
|
+
}
|
|
119
|
+
instance.log.error(error);
|
|
120
|
+
return reply.status(500).send({ error: "internal", message: "Internal server error" });
|
|
121
|
+
});
|
|
122
|
+
const logger = createActionLogger(instance);
|
|
91
123
|
for (const action of actions) {
|
|
92
124
|
const schema = action.input.toJSONSchema();
|
|
93
125
|
instance.post(`/${action.name}`, {
|
|
@@ -103,15 +135,6 @@ var fastify = ({ host, port, auth, ...fastifyOptions }) => {
|
|
|
103
135
|
}
|
|
104
136
|
}
|
|
105
137
|
}, (request) => {
|
|
106
|
-
const logger = {
|
|
107
|
-
...buildLogLevels((level, data) => {
|
|
108
|
-
const pinoLevel = PINO_LEVEL_MAP[level] ?? "info";
|
|
109
|
-
instance.log[pinoLevel](data);
|
|
110
|
-
}),
|
|
111
|
-
progress: ({ progress, total, message }) => {
|
|
112
|
-
instance.log.trace({ progress, total }, message);
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
138
|
const authInfo = auth ? request.__silkweave_auth : void 0;
|
|
116
139
|
return action.run(request.body, context.fork({ logger, request, ...authInfo ? { auth: authInfo } : {} }));
|
|
117
140
|
});
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapter/fastify.ts"],"sourcesContent":["import { AuthConfig, AuthInfo, generateProtectedResourceMetadata, OAuthRequest, OAuthResponse, validateToken } from '@silkweave/auth'\nimport { AdapterFactory } from '@silkweave/core'\nimport { buildLogLevels, Logger, LogLevel } from '@silkweave/logger'\nimport { FastifyBaseLogger, FastifyHttpOptions, fastify as fastifyInstance, FastifyReply, FastifyRequest } from 'fastify'\nimport { Server } from 'http'\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}\n\nexport const fastify: AdapterFactory<FastifyAdapterOptions> = ({ host, port, auth, ...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 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 instance.register(import('@scalar/fastify-api-reference'), { routePrefix: '/' as `/${string}` })\n\n if (auth?.authorizationServers?.length && auth.resourceUrl) {\n instance.get('/.well-known/oauth-protected-resource', () => {\n return generateProtectedResourceMetadata(auth.resourceUrl!, auth.authorizationServers!)\n })\n }\n\n const oauthPaths = new Set<string>()\n if (auth?.provider) {\n const provider = auth.provider\n const toOAuthReq = (request: FastifyRequest): OAuthRequest => ({\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 const 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\n oauthPaths.add('/.well-known/oauth-authorization-server')\n oauthPaths.add('/authorize')\n oauthPaths.add('/auth/callback')\n oauthPaths.add('/token')\n oauthPaths.add('/register')\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('/auth/callback', 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\n if (auth) {\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)\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\n for (const action of actions) {\n const schema = action.input.toJSONSchema()\n instance.post(`/${action.name}`, {\n schema: {\n description: action.description,\n body: {\n type: 'object',\n properties: schema.properties,\n required: schema.required\n },\n response: {\n 200: { description: 'Successful response' }\n }\n }\n }, (request) => {\n const logger: Logger = {\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 const authInfo = auth ? (request as FastifyRequest & { __silkweave_auth?: AuthInfo }).__silkweave_auth : undefined\n return action.run(request.body, context.fork({ logger, request, ...(authInfo ? { auth: authInfo } : {}) }))\n })\n }\n await instance.listen({ host, port })\n },\n stop: async () => { await instance.close() }\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/adapter/fastify.ts"],"sourcesContent":["import { AuthConfig, AuthInfo, generateProtectedResourceMetadata, OAuthRequest, OAuthResponse, validateToken } from '@silkweave/auth'\nimport { AdapterFactory, SilkweaveError } from '@silkweave/core'\nimport { buildLogLevels, Logger, LogLevel } from '@silkweave/logger'\nimport { FastifyBaseLogger, FastifyHttpOptions, fastify as fastifyInstance, FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'\nimport { Server } from 'http'\nimport z from 'zod'\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}\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\n const paths = new Set([\n '/.well-known/oauth-authorization-server',\n '/authorize',\n '/auth/callback',\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('/auth/callback', 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>) {\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)\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\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\nexport const fastify: AdapterFactory<FastifyAdapterOptions> = ({ host, port, auth, ...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 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 instance.register(import('@scalar/fastify-api-reference'), { routePrefix: '/' as `/${string}` })\n\n if (auth?.authorizationServers?.length && auth.resourceUrl) {\n instance.get('/.well-known/oauth-protected-resource', () => {\n return generateProtectedResourceMetadata(auth.resourceUrl!, auth.authorizationServers!)\n })\n }\n\n const oauthPaths = auth?.provider ? mountOAuthRoutes(instance, auth) : new Set<string>()\n\n if (auth) {\n mountAuthMiddleware(instance, auth, oauthPaths)\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 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 const schema = action.input.toJSONSchema()\n instance.post(`/${action.name}`, {\n schema: {\n description: action.description,\n body: {\n type: 'object',\n properties: schema.properties,\n required: schema.required\n },\n response: {\n 200: { description: 'Successful response' }\n }\n }\n }, (request) => {\n const authInfo = auth ? (request as FastifyRequest & { __silkweave_auth?: AuthInfo }).__silkweave_auth : undefined\n return action.run(request.body, context.fork({ logger, request, ...(authInfo ? { auth: authInfo } : {}) }))\n })\n }\n await instance.listen({ host, port })\n },\n stop: async () => { await instance.close() }\n }\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@silkweave/fastify",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.2",
|
|
4
4
|
"description": "Silkweave Fastify REST Adapter",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
|
-
"url": "git+ssh://git@github.com/
|
|
7
|
+
"url": "git+ssh://git@github.com/silkweave/silkweave.git",
|
|
8
8
|
"directory": "packages/fastify"
|
|
9
9
|
},
|
|
10
10
|
"type": "module",
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
"@scalar/fastify-api-reference": "^1.49.0",
|
|
16
16
|
"fastify": "^5.8.2",
|
|
17
17
|
"zod": "^4.3.6",
|
|
18
|
-
"@silkweave/
|
|
19
|
-
"@silkweave/
|
|
20
|
-
"@silkweave/logger": "1.3.
|
|
18
|
+
"@silkweave/auth": "1.3.2",
|
|
19
|
+
"@silkweave/core": "1.3.2",
|
|
20
|
+
"@silkweave/logger": "1.3.2"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@eslint/js": "^10.0.1",
|