@lensjs/fastify 1.0.1

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 ADDED
@@ -0,0 +1,71 @@
1
+ # @lensjs/fastify
2
+
3
+ Fastify adapter for Lens. This package provides middleware and integration points to connect your Fastify application with the Lens monitoring and debugging tool. It enables automatic logging of requests, queries (via `@lensjs/watchers`), and cache events.
4
+
5
+ ## Features
6
+
7
+ * **`lens(config: FastifyAdapterConfig)` function**: The main entry point to initialize and integrate Lens with a Fastify application.
8
+ * **`FastifyAdapter` class**: Extends `LensAdapter` from `@lensjs/core` to provide Fastify-specific implementations for setting up watchers, registering routes, and serving the Lens UI.
9
+ * **Request Watching**: Automatically captures incoming request details (method, path, headers, body, status, duration, IP) and logs them.
10
+ * **Query Watching**: Integrates with `@lensjs/watchers` to capture database queries from various ORMs (Kysely, Prisma, Sequelize) if configured.
11
+ * **Cache Watching**: Integrates with `@lensjs/watchers` to capture cache events if configured.
12
+ * **Exception Watching**: Captures and logs unhandled exceptions and errors within your Fastify application.
13
+ * **UI Serving**: Serves the Lens UI within your Fastify application at a configurable path.
14
+ * **Configurable Paths**: Allows specifying base paths, ignored paths, and only paths for request watching.
15
+ * **Body Purging**: Prevents sensitive information from being logged in responses by purging certain body types (e.g., file paths, binary data).
16
+ * **Authentication/User Context**: Supports optional `isAuthenticated` and `getUser` functions to associate request logs with authenticated users.
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pnpm add @lensjs/fastify
22
+ ```
23
+
24
+ ## Usage Example
25
+
26
+ ```typescript
27
+ import Fastify from 'fastify';
28
+ import { lens } from '@lensjs/fastify';
29
+ // import { createKyselyHandler } from '@lensjs/watchers/query/kysely'; // Example for Kysely
30
+
31
+ const fastify = Fastify({
32
+ logger: true
33
+ });
34
+
35
+ // Initialize Lens with Fastify
36
+ lens({
37
+ fastify,
38
+ appName: 'My Fastify App',
39
+ enabled: true, // Set to false in production
40
+ path: '/lens-dashboard', // Access Lens UI at /lens-dashboard
41
+ requestWatcherEnabled: true,
42
+ cacheWatcherEnabled: true,
43
+ exceptionWatcherEnabled: true,
44
+ // queryWatcher: {
45
+ // enabled: true,
46
+ // handler: createKyselyHandler({ provider: 'sqlite' }), // Or createPrismaHandler, createSequelizeHandler
47
+ // },
48
+ // Optional: Integrate with your authentication system
49
+ isAuthenticated: async (req) => {
50
+ return !!req.headers.authorization;
51
+ },
52
+ getUser: async (req) => {
53
+ // Return user details based on your auth system
54
+ return { id: '1', name: 'Authenticated User' };
55
+ },
56
+ });
57
+
58
+ // Your Fastify routes
59
+ fastify.get('/', async (request, reply) => {
60
+ return { hello: 'world' };
61
+ });
62
+
63
+ fastify.listen({ port: 3000 }, (err, address) => {
64
+ if (err) {
65
+ fastify.log.error(err);
66
+ process.exit(1);
67
+ }
68
+ console.log(`Fastify app listening on ${address}`);
69
+ console.log('Lens UI available at http://localhost:3000/lens-dashboard');
70
+ });
71
+ ```
@@ -0,0 +1,236 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/adapter.ts
31
+ var adapter_exports = {};
32
+ __export(adapter_exports, {
33
+ FastifyAdapter: () => FastifyAdapter
34
+ });
35
+ module.exports = __toCommonJS(adapter_exports);
36
+ var import_core = require("@lensjs/core");
37
+ var path = __toESM(require("path"), 1);
38
+ var fs = __toESM(require("fs"), 1);
39
+ var import_date = require("@lensjs/date");
40
+ var import_static = __toESM(require("@fastify/static"), 1);
41
+ var FastifyAdapter = class extends import_core.LensAdapter {
42
+ app;
43
+ config;
44
+ constructor({ app }) {
45
+ super();
46
+ this.app = app;
47
+ }
48
+ setConfig(config) {
49
+ this.config = config;
50
+ return this;
51
+ }
52
+ setup() {
53
+ for (const watcher of this.getWatchers()) {
54
+ switch (watcher.name) {
55
+ case import_core.WatcherTypeEnum.REQUEST:
56
+ if (this.config.requestWatcherEnabled) {
57
+ this.watchRequests(watcher);
58
+ }
59
+ break;
60
+ case import_core.WatcherTypeEnum.QUERY:
61
+ if (this.config.queryWatcher?.enabled) {
62
+ void this.watchQueries(watcher);
63
+ }
64
+ break;
65
+ case import_core.WatcherTypeEnum.CACHE:
66
+ if (this.config.cacheWatcherEnabled) {
67
+ void this.watchCache(watcher);
68
+ }
69
+ break;
70
+ }
71
+ }
72
+ }
73
+ registerRoutes(routes) {
74
+ routes.forEach((route) => {
75
+ this.app.route({
76
+ method: route.method.toUpperCase(),
77
+ url: this.normalizePath(route.path),
78
+ handler: async (request, reply) => {
79
+ const result = await route.handler({
80
+ params: request.params,
81
+ qs: request.query
82
+ });
83
+ return reply.send(result);
84
+ }
85
+ });
86
+ });
87
+ }
88
+ serveUI(uiPath, spaRoute, _dataToInject) {
89
+ this.app.register(import_static.default, {
90
+ root: uiPath,
91
+ prefix: `${this.normalizePath(import_core.lensUtils.normalizePath(spaRoute))}/`,
92
+ wildcard: false,
93
+ serve: false
94
+ });
95
+ this.app.get(`/${spaRoute}/*`, async (request, reply) => {
96
+ const url = request.url;
97
+ if (import_core.lensUtils.isStaticFile(url.split("/"))) {
98
+ const filePath = path.join(
99
+ uiPath,
100
+ import_core.lensUtils.stripBeforeAssetsPath(url)
101
+ );
102
+ return reply.sendFile(`${path.relative(uiPath, filePath)}`);
103
+ }
104
+ return reply.sendFile("index.html", uiPath);
105
+ });
106
+ }
107
+ async watchCache(watcher) {
108
+ if (!this.config.cacheWatcherEnabled) return;
109
+ import_core.lensEmitter.on("cache", async (data) => {
110
+ await watcher?.log(data);
111
+ });
112
+ }
113
+ async watchQueries(watcher) {
114
+ if (!this.config.queryWatcher?.enabled) return;
115
+ const handler = this.config.queryWatcher.handler;
116
+ await handler({
117
+ onQuery: async (query) => {
118
+ const queryPayload = {
119
+ query: query.query,
120
+ duration: query.duration || "0 ms",
121
+ createdAt: query.createdAt || (0, import_date.nowISO)(),
122
+ type: query.type
123
+ };
124
+ await watcher?.log({
125
+ data: queryPayload,
126
+ requestId: import_core.lensContext.getStore()?.requestId ?? ""
127
+ });
128
+ }
129
+ });
130
+ }
131
+ watchRequests(requestWatcher) {
132
+ if (!this.config.requestWatcherEnabled) return;
133
+ this.app.addHook(
134
+ "onRequest",
135
+ (request, _, done) => {
136
+ if (this.shouldIgnorePath(request.url)) return done();
137
+ const context = {
138
+ requestId: import_core.lensUtils.generateRandomUuid()
139
+ };
140
+ request.lensContext = context;
141
+ request.lensStartTime = process.hrtime();
142
+ import_core.lensContext.run(context, done);
143
+ }
144
+ );
145
+ this.app.addHook(
146
+ "onSend",
147
+ async (request, reply, payload) => {
148
+ if (this.shouldIgnorePath(request.url)) return payload;
149
+ reply._lensBody = this.parseResponsePayload(payload);
150
+ return payload;
151
+ }
152
+ );
153
+ this.app.addHook(
154
+ "onResponse",
155
+ async (request, reply) => {
156
+ if (this.shouldIgnorePath(request.url)) return;
157
+ const startTime = request.lensStartTime;
158
+ await this.finalizeRequestLog(
159
+ request,
160
+ reply,
161
+ requestWatcher,
162
+ startTime
163
+ );
164
+ }
165
+ );
166
+ }
167
+ async finalizeRequestLog(request, reply, requestWatcher, start) {
168
+ try {
169
+ const duration = import_core.lensUtils.prettyHrTime(process.hrtime(start));
170
+ const logPayload = {
171
+ request: {
172
+ id: import_core.lensContext.getStore()?.requestId || import_core.lensUtils.generateRandomUuid(),
173
+ method: request.method,
174
+ duration,
175
+ path: request.url,
176
+ headers: request.headers,
177
+ body: request.body ?? {},
178
+ status: reply.statusCode,
179
+ ip: request.ip ?? "",
180
+ createdAt: (0, import_date.nowISO)()
181
+ },
182
+ response: {
183
+ json: this.parseBody(reply._lensBody),
184
+ headers: reply.getHeaders()
185
+ },
186
+ user: await this.config.isAuthenticated?.(request) ? await this.config.getUser?.(request) : null
187
+ };
188
+ await requestWatcher.log(logPayload);
189
+ } catch (err) {
190
+ console.error("Error finalizing request log:", err);
191
+ }
192
+ }
193
+ parseResponsePayload(payload) {
194
+ if (!payload) {
195
+ return null;
196
+ }
197
+ try {
198
+ if (typeof payload === "string") {
199
+ try {
200
+ return JSON.parse(payload);
201
+ } catch {
202
+ const filePath = path.resolve(payload);
203
+ if (fs.existsSync(filePath)) {
204
+ return "Purged By Lens";
205
+ }
206
+ return "Purged By Lens";
207
+ }
208
+ } else if (Buffer.isBuffer(payload)) {
209
+ return "Purged By Lens";
210
+ } else if (typeof payload === "object") {
211
+ return payload;
212
+ } else {
213
+ return payload;
214
+ }
215
+ } catch {
216
+ return "Purged By Lens";
217
+ }
218
+ }
219
+ normalizePath(pathStr) {
220
+ return pathStr.startsWith("/") ? pathStr : `/${pathStr}`;
221
+ }
222
+ parseBody(body) {
223
+ if (!body) {
224
+ return null;
225
+ }
226
+ try {
227
+ return JSON.parse(body);
228
+ } catch (_e) {
229
+ return body;
230
+ }
231
+ }
232
+ };
233
+ // Annotate the CommonJS export names for ESM import in node:
234
+ 0 && (module.exports = {
235
+ FastifyAdapter
236
+ });
@@ -0,0 +1,26 @@
1
+ import { LensAdapter, RouteDefinition } from '@lensjs/core';
2
+ import { RequiredFastifyAdapterConfig } from './types.cjs';
3
+ import { FastifyInstance } from 'fastify';
4
+ import '@lensjs/watchers';
5
+ import '@fastify/static';
6
+
7
+ declare class FastifyAdapter extends LensAdapter {
8
+ protected app: FastifyInstance;
9
+ protected config: RequiredFastifyAdapterConfig;
10
+ constructor({ app }: {
11
+ app: FastifyInstance;
12
+ });
13
+ setConfig(config: RequiredFastifyAdapterConfig): this;
14
+ setup(): void;
15
+ registerRoutes(routes: RouteDefinition[]): void;
16
+ serveUI(uiPath: string, spaRoute: string, _dataToInject: Record<string, any>): void;
17
+ private watchCache;
18
+ private watchQueries;
19
+ private watchRequests;
20
+ private finalizeRequestLog;
21
+ private parseResponsePayload;
22
+ private normalizePath;
23
+ private parseBody;
24
+ }
25
+
26
+ export { FastifyAdapter };
@@ -0,0 +1,26 @@
1
+ import { LensAdapter, RouteDefinition } from '@lensjs/core';
2
+ import { RequiredFastifyAdapterConfig } from './types.js';
3
+ import { FastifyInstance } from 'fastify';
4
+ import '@lensjs/watchers';
5
+ import '@fastify/static';
6
+
7
+ declare class FastifyAdapter extends LensAdapter {
8
+ protected app: FastifyInstance;
9
+ protected config: RequiredFastifyAdapterConfig;
10
+ constructor({ app }: {
11
+ app: FastifyInstance;
12
+ });
13
+ setConfig(config: RequiredFastifyAdapterConfig): this;
14
+ setup(): void;
15
+ registerRoutes(routes: RouteDefinition[]): void;
16
+ serveUI(uiPath: string, spaRoute: string, _dataToInject: Record<string, any>): void;
17
+ private watchCache;
18
+ private watchQueries;
19
+ private watchRequests;
20
+ private finalizeRequestLog;
21
+ private parseResponsePayload;
22
+ private normalizePath;
23
+ private parseBody;
24
+ }
25
+
26
+ export { FastifyAdapter };
@@ -0,0 +1,207 @@
1
+ // src/adapter.ts
2
+ import {
3
+ LensAdapter,
4
+ lensUtils,
5
+ WatcherTypeEnum,
6
+ lensContext,
7
+ lensEmitter
8
+ } from "@lensjs/core";
9
+ import * as path from "path";
10
+ import * as fs from "fs";
11
+ import { nowISO } from "@lensjs/date";
12
+ import fastifyStatic from "@fastify/static";
13
+ var FastifyAdapter = class extends LensAdapter {
14
+ app;
15
+ config;
16
+ constructor({ app }) {
17
+ super();
18
+ this.app = app;
19
+ }
20
+ setConfig(config) {
21
+ this.config = config;
22
+ return this;
23
+ }
24
+ setup() {
25
+ for (const watcher of this.getWatchers()) {
26
+ switch (watcher.name) {
27
+ case WatcherTypeEnum.REQUEST:
28
+ if (this.config.requestWatcherEnabled) {
29
+ this.watchRequests(watcher);
30
+ }
31
+ break;
32
+ case WatcherTypeEnum.QUERY:
33
+ if (this.config.queryWatcher?.enabled) {
34
+ void this.watchQueries(watcher);
35
+ }
36
+ break;
37
+ case WatcherTypeEnum.CACHE:
38
+ if (this.config.cacheWatcherEnabled) {
39
+ void this.watchCache(watcher);
40
+ }
41
+ break;
42
+ }
43
+ }
44
+ }
45
+ registerRoutes(routes) {
46
+ routes.forEach((route) => {
47
+ this.app.route({
48
+ method: route.method.toUpperCase(),
49
+ url: this.normalizePath(route.path),
50
+ handler: async (request, reply) => {
51
+ const result = await route.handler({
52
+ params: request.params,
53
+ qs: request.query
54
+ });
55
+ return reply.send(result);
56
+ }
57
+ });
58
+ });
59
+ }
60
+ serveUI(uiPath, spaRoute, _dataToInject) {
61
+ this.app.register(fastifyStatic, {
62
+ root: uiPath,
63
+ prefix: `${this.normalizePath(lensUtils.normalizePath(spaRoute))}/`,
64
+ wildcard: false,
65
+ serve: false
66
+ });
67
+ this.app.get(`/${spaRoute}/*`, async (request, reply) => {
68
+ const url = request.url;
69
+ if (lensUtils.isStaticFile(url.split("/"))) {
70
+ const filePath = path.join(
71
+ uiPath,
72
+ lensUtils.stripBeforeAssetsPath(url)
73
+ );
74
+ return reply.sendFile(`${path.relative(uiPath, filePath)}`);
75
+ }
76
+ return reply.sendFile("index.html", uiPath);
77
+ });
78
+ }
79
+ async watchCache(watcher) {
80
+ if (!this.config.cacheWatcherEnabled) return;
81
+ lensEmitter.on("cache", async (data) => {
82
+ await watcher?.log(data);
83
+ });
84
+ }
85
+ async watchQueries(watcher) {
86
+ if (!this.config.queryWatcher?.enabled) return;
87
+ const handler = this.config.queryWatcher.handler;
88
+ await handler({
89
+ onQuery: async (query) => {
90
+ const queryPayload = {
91
+ query: query.query,
92
+ duration: query.duration || "0 ms",
93
+ createdAt: query.createdAt || nowISO(),
94
+ type: query.type
95
+ };
96
+ await watcher?.log({
97
+ data: queryPayload,
98
+ requestId: lensContext.getStore()?.requestId ?? ""
99
+ });
100
+ }
101
+ });
102
+ }
103
+ watchRequests(requestWatcher) {
104
+ if (!this.config.requestWatcherEnabled) return;
105
+ this.app.addHook(
106
+ "onRequest",
107
+ (request, _, done) => {
108
+ if (this.shouldIgnorePath(request.url)) return done();
109
+ const context = {
110
+ requestId: lensUtils.generateRandomUuid()
111
+ };
112
+ request.lensContext = context;
113
+ request.lensStartTime = process.hrtime();
114
+ lensContext.run(context, done);
115
+ }
116
+ );
117
+ this.app.addHook(
118
+ "onSend",
119
+ async (request, reply, payload) => {
120
+ if (this.shouldIgnorePath(request.url)) return payload;
121
+ reply._lensBody = this.parseResponsePayload(payload);
122
+ return payload;
123
+ }
124
+ );
125
+ this.app.addHook(
126
+ "onResponse",
127
+ async (request, reply) => {
128
+ if (this.shouldIgnorePath(request.url)) return;
129
+ const startTime = request.lensStartTime;
130
+ await this.finalizeRequestLog(
131
+ request,
132
+ reply,
133
+ requestWatcher,
134
+ startTime
135
+ );
136
+ }
137
+ );
138
+ }
139
+ async finalizeRequestLog(request, reply, requestWatcher, start) {
140
+ try {
141
+ const duration = lensUtils.prettyHrTime(process.hrtime(start));
142
+ const logPayload = {
143
+ request: {
144
+ id: lensContext.getStore()?.requestId || lensUtils.generateRandomUuid(),
145
+ method: request.method,
146
+ duration,
147
+ path: request.url,
148
+ headers: request.headers,
149
+ body: request.body ?? {},
150
+ status: reply.statusCode,
151
+ ip: request.ip ?? "",
152
+ createdAt: nowISO()
153
+ },
154
+ response: {
155
+ json: this.parseBody(reply._lensBody),
156
+ headers: reply.getHeaders()
157
+ },
158
+ user: await this.config.isAuthenticated?.(request) ? await this.config.getUser?.(request) : null
159
+ };
160
+ await requestWatcher.log(logPayload);
161
+ } catch (err) {
162
+ console.error("Error finalizing request log:", err);
163
+ }
164
+ }
165
+ parseResponsePayload(payload) {
166
+ if (!payload) {
167
+ return null;
168
+ }
169
+ try {
170
+ if (typeof payload === "string") {
171
+ try {
172
+ return JSON.parse(payload);
173
+ } catch {
174
+ const filePath = path.resolve(payload);
175
+ if (fs.existsSync(filePath)) {
176
+ return "Purged By Lens";
177
+ }
178
+ return "Purged By Lens";
179
+ }
180
+ } else if (Buffer.isBuffer(payload)) {
181
+ return "Purged By Lens";
182
+ } else if (typeof payload === "object") {
183
+ return payload;
184
+ } else {
185
+ return payload;
186
+ }
187
+ } catch {
188
+ return "Purged By Lens";
189
+ }
190
+ }
191
+ normalizePath(pathStr) {
192
+ return pathStr.startsWith("/") ? pathStr : `/${pathStr}`;
193
+ }
194
+ parseBody(body) {
195
+ if (!body) {
196
+ return null;
197
+ }
198
+ try {
199
+ return JSON.parse(body);
200
+ } catch (_e) {
201
+ return body;
202
+ }
203
+ }
204
+ };
205
+ export {
206
+ FastifyAdapter
207
+ };
package/dist/index.cjs ADDED
@@ -0,0 +1,332 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ FastifyAdapter: () => FastifyAdapter,
34
+ lens: () => lens
35
+ });
36
+ module.exports = __toCommonJS(index_exports);
37
+ var import_core2 = require("@lensjs/core");
38
+
39
+ // src/adapter.ts
40
+ var import_core = require("@lensjs/core");
41
+ var path = __toESM(require("path"), 1);
42
+ var fs = __toESM(require("fs"), 1);
43
+ var import_date = require("@lensjs/date");
44
+ var import_static = __toESM(require("@fastify/static"), 1);
45
+ var FastifyAdapter = class extends import_core.LensAdapter {
46
+ app;
47
+ config;
48
+ constructor({ app }) {
49
+ super();
50
+ this.app = app;
51
+ }
52
+ setConfig(config) {
53
+ this.config = config;
54
+ return this;
55
+ }
56
+ setup() {
57
+ for (const watcher of this.getWatchers()) {
58
+ switch (watcher.name) {
59
+ case import_core.WatcherTypeEnum.REQUEST:
60
+ if (this.config.requestWatcherEnabled) {
61
+ this.watchRequests(watcher);
62
+ }
63
+ break;
64
+ case import_core.WatcherTypeEnum.QUERY:
65
+ if (this.config.queryWatcher?.enabled) {
66
+ void this.watchQueries(watcher);
67
+ }
68
+ break;
69
+ case import_core.WatcherTypeEnum.CACHE:
70
+ if (this.config.cacheWatcherEnabled) {
71
+ void this.watchCache(watcher);
72
+ }
73
+ break;
74
+ }
75
+ }
76
+ }
77
+ registerRoutes(routes) {
78
+ routes.forEach((route) => {
79
+ this.app.route({
80
+ method: route.method.toUpperCase(),
81
+ url: this.normalizePath(route.path),
82
+ handler: async (request, reply) => {
83
+ const result = await route.handler({
84
+ params: request.params,
85
+ qs: request.query
86
+ });
87
+ return reply.send(result);
88
+ }
89
+ });
90
+ });
91
+ }
92
+ serveUI(uiPath, spaRoute, _dataToInject) {
93
+ this.app.register(import_static.default, {
94
+ root: uiPath,
95
+ prefix: `${this.normalizePath(import_core.lensUtils.normalizePath(spaRoute))}/`,
96
+ wildcard: false,
97
+ serve: false
98
+ });
99
+ this.app.get(`/${spaRoute}/*`, async (request, reply) => {
100
+ const url = request.url;
101
+ if (import_core.lensUtils.isStaticFile(url.split("/"))) {
102
+ const filePath = path.join(
103
+ uiPath,
104
+ import_core.lensUtils.stripBeforeAssetsPath(url)
105
+ );
106
+ return reply.sendFile(`${path.relative(uiPath, filePath)}`);
107
+ }
108
+ return reply.sendFile("index.html", uiPath);
109
+ });
110
+ }
111
+ async watchCache(watcher) {
112
+ if (!this.config.cacheWatcherEnabled) return;
113
+ import_core.lensEmitter.on("cache", async (data) => {
114
+ await watcher?.log(data);
115
+ });
116
+ }
117
+ async watchQueries(watcher) {
118
+ if (!this.config.queryWatcher?.enabled) return;
119
+ const handler = this.config.queryWatcher.handler;
120
+ await handler({
121
+ onQuery: async (query) => {
122
+ const queryPayload = {
123
+ query: query.query,
124
+ duration: query.duration || "0 ms",
125
+ createdAt: query.createdAt || (0, import_date.nowISO)(),
126
+ type: query.type
127
+ };
128
+ await watcher?.log({
129
+ data: queryPayload,
130
+ requestId: import_core.lensContext.getStore()?.requestId ?? ""
131
+ });
132
+ }
133
+ });
134
+ }
135
+ watchRequests(requestWatcher) {
136
+ if (!this.config.requestWatcherEnabled) return;
137
+ this.app.addHook(
138
+ "onRequest",
139
+ (request, _, done) => {
140
+ if (this.shouldIgnorePath(request.url)) return done();
141
+ const context = {
142
+ requestId: import_core.lensUtils.generateRandomUuid()
143
+ };
144
+ request.lensContext = context;
145
+ request.lensStartTime = process.hrtime();
146
+ import_core.lensContext.run(context, done);
147
+ }
148
+ );
149
+ this.app.addHook(
150
+ "onSend",
151
+ async (request, reply, payload) => {
152
+ if (this.shouldIgnorePath(request.url)) return payload;
153
+ reply._lensBody = this.parseResponsePayload(payload);
154
+ return payload;
155
+ }
156
+ );
157
+ this.app.addHook(
158
+ "onResponse",
159
+ async (request, reply) => {
160
+ if (this.shouldIgnorePath(request.url)) return;
161
+ const startTime = request.lensStartTime;
162
+ await this.finalizeRequestLog(
163
+ request,
164
+ reply,
165
+ requestWatcher,
166
+ startTime
167
+ );
168
+ }
169
+ );
170
+ }
171
+ async finalizeRequestLog(request, reply, requestWatcher, start) {
172
+ try {
173
+ const duration = import_core.lensUtils.prettyHrTime(process.hrtime(start));
174
+ const logPayload = {
175
+ request: {
176
+ id: import_core.lensContext.getStore()?.requestId || import_core.lensUtils.generateRandomUuid(),
177
+ method: request.method,
178
+ duration,
179
+ path: request.url,
180
+ headers: request.headers,
181
+ body: request.body ?? {},
182
+ status: reply.statusCode,
183
+ ip: request.ip ?? "",
184
+ createdAt: (0, import_date.nowISO)()
185
+ },
186
+ response: {
187
+ json: this.parseBody(reply._lensBody),
188
+ headers: reply.getHeaders()
189
+ },
190
+ user: await this.config.isAuthenticated?.(request) ? await this.config.getUser?.(request) : null
191
+ };
192
+ await requestWatcher.log(logPayload);
193
+ } catch (err) {
194
+ console.error("Error finalizing request log:", err);
195
+ }
196
+ }
197
+ parseResponsePayload(payload) {
198
+ if (!payload) {
199
+ return null;
200
+ }
201
+ try {
202
+ if (typeof payload === "string") {
203
+ try {
204
+ return JSON.parse(payload);
205
+ } catch {
206
+ const filePath = path.resolve(payload);
207
+ if (fs.existsSync(filePath)) {
208
+ return "Purged By Lens";
209
+ }
210
+ return "Purged By Lens";
211
+ }
212
+ } else if (Buffer.isBuffer(payload)) {
213
+ return "Purged By Lens";
214
+ } else if (typeof payload === "object") {
215
+ return payload;
216
+ } else {
217
+ return payload;
218
+ }
219
+ } catch {
220
+ return "Purged By Lens";
221
+ }
222
+ }
223
+ normalizePath(pathStr) {
224
+ return pathStr.startsWith("/") ? pathStr : `/${pathStr}`;
225
+ }
226
+ parseBody(body) {
227
+ if (!body) {
228
+ return null;
229
+ }
230
+ try {
231
+ return JSON.parse(body);
232
+ } catch (_e) {
233
+ return body;
234
+ }
235
+ }
236
+ };
237
+
238
+ // src/index.ts
239
+ var import_core3 = require("@lensjs/core");
240
+ var import_core4 = require("@lensjs/core");
241
+ var defaultConfig = {
242
+ appName: "Lens",
243
+ enabled: true,
244
+ path: "/lens",
245
+ ignoredPaths: [],
246
+ onlyPaths: [],
247
+ requestWatcherEnabled: true,
248
+ cacheWatcherEnabled: false,
249
+ exceptionWatcherEnabled: true,
250
+ registerErrorHandler: true
251
+ };
252
+ var lens = async (config) => {
253
+ const adapter = new FastifyAdapter({ app: config.app });
254
+ const watchers = [];
255
+ const mergedConfig = {
256
+ ...defaultConfig,
257
+ ...config
258
+ };
259
+ const defaultWatchers = [
260
+ {
261
+ enabled: mergedConfig.requestWatcherEnabled,
262
+ watcher: new import_core2.RequestWatcher()
263
+ },
264
+ {
265
+ enabled: mergedConfig.cacheWatcherEnabled,
266
+ watcher: new import_core2.CacheWatcher()
267
+ },
268
+ {
269
+ enabled: mergedConfig.queryWatcher?.enabled,
270
+ watcher: new import_core2.QueryWatcher()
271
+ },
272
+ {
273
+ enabled: mergedConfig.exceptionWatcherEnabled,
274
+ watcher: new import_core2.ExceptionWatcher()
275
+ }
276
+ ];
277
+ defaultWatchers.forEach((watcher) => {
278
+ if (watcher.enabled) {
279
+ watchers.push(watcher.watcher);
280
+ }
281
+ });
282
+ const { ignoredPaths, normalizedPath } = import_core2.lensUtils.prepareIgnoredPaths(
283
+ mergedConfig.path,
284
+ mergedConfig.ignoredPaths
285
+ );
286
+ adapter.setConfig(mergedConfig).setIgnoredPaths(ignoredPaths).setOnlyPaths(mergedConfig.onlyPaths);
287
+ if (mergedConfig.exceptionWatcherEnabled && mergedConfig.registerErrorHandler) {
288
+ handleExceptions({
289
+ app: mergedConfig.app,
290
+ enabled: mergedConfig.exceptionWatcherEnabled && mergedConfig.enabled,
291
+ watcher: watchers.find(
292
+ (w) => w.name === import_core3.WatcherTypeEnum.EXCEPTION
293
+ )
294
+ });
295
+ }
296
+ await import_core2.Lens.setAdapter(adapter).setWatchers(watchers).start({
297
+ appName: mergedConfig.appName,
298
+ enabled: mergedConfig.enabled,
299
+ basePath: normalizedPath
300
+ });
301
+ const exceptionWatcher = watchers.find(
302
+ (w) => w.name === import_core3.WatcherTypeEnum.EXCEPTION
303
+ );
304
+ return {
305
+ logException: (error) => logException(
306
+ error,
307
+ mergedConfig.exceptionWatcherEnabled && mergedConfig.enabled,
308
+ exceptionWatcher
309
+ )
310
+ };
311
+ };
312
+ function logException(error, enabled, watcher) {
313
+ if (!enabled || !watcher) return;
314
+ watcher.log({
315
+ ...import_core4.lensExceptionUtils.constructErrorObject(error),
316
+ requestId: import_core2.lensContext.getStore()?.requestId ?? ""
317
+ });
318
+ }
319
+ function handleExceptions({
320
+ app,
321
+ enabled,
322
+ watcher
323
+ }) {
324
+ app.setErrorHandler((err) => {
325
+ logException(err, enabled, watcher);
326
+ });
327
+ }
328
+ // Annotate the CommonJS export names for ESM import in node:
329
+ 0 && (module.exports = {
330
+ FastifyAdapter,
331
+ lens
332
+ });
@@ -0,0 +1,13 @@
1
+ import { FastifyAdapterConfig } from './types.cjs';
2
+ export { RequiredFastifyAdapterConfig } from './types.cjs';
3
+ import { FastifyError } from 'fastify';
4
+ export { FastifyAdapter } from './adapter.cjs';
5
+ import '@lensjs/watchers';
6
+ import '@lensjs/core';
7
+ import '@fastify/static';
8
+
9
+ declare const lens: (config: FastifyAdapterConfig) => Promise<{
10
+ logException: (error: FastifyError) => void;
11
+ }>;
12
+
13
+ export { FastifyAdapterConfig, lens };
@@ -0,0 +1,13 @@
1
+ import { FastifyAdapterConfig } from './types.js';
2
+ export { RequiredFastifyAdapterConfig } from './types.js';
3
+ import { FastifyError } from 'fastify';
4
+ export { FastifyAdapter } from './adapter.js';
5
+ import '@lensjs/watchers';
6
+ import '@lensjs/core';
7
+ import '@fastify/static';
8
+
9
+ declare const lens: (config: FastifyAdapterConfig) => Promise<{
10
+ logException: (error: FastifyError) => void;
11
+ }>;
12
+
13
+ export { FastifyAdapterConfig, lens };
package/dist/index.js ADDED
@@ -0,0 +1,310 @@
1
+ // src/index.ts
2
+ import {
3
+ CacheWatcher as CacheWatcher2,
4
+ ExceptionWatcher,
5
+ Lens,
6
+ lensContext as lensContext2,
7
+ lensUtils as lensUtils2,
8
+ QueryWatcher as QueryWatcher2,
9
+ RequestWatcher as RequestWatcher2
10
+ } from "@lensjs/core";
11
+
12
+ // src/adapter.ts
13
+ import {
14
+ LensAdapter,
15
+ lensUtils,
16
+ WatcherTypeEnum,
17
+ lensContext,
18
+ lensEmitter
19
+ } from "@lensjs/core";
20
+ import * as path from "path";
21
+ import * as fs from "fs";
22
+ import { nowISO } from "@lensjs/date";
23
+ import fastifyStatic from "@fastify/static";
24
+ var FastifyAdapter = class extends LensAdapter {
25
+ app;
26
+ config;
27
+ constructor({ app }) {
28
+ super();
29
+ this.app = app;
30
+ }
31
+ setConfig(config) {
32
+ this.config = config;
33
+ return this;
34
+ }
35
+ setup() {
36
+ for (const watcher of this.getWatchers()) {
37
+ switch (watcher.name) {
38
+ case WatcherTypeEnum.REQUEST:
39
+ if (this.config.requestWatcherEnabled) {
40
+ this.watchRequests(watcher);
41
+ }
42
+ break;
43
+ case WatcherTypeEnum.QUERY:
44
+ if (this.config.queryWatcher?.enabled) {
45
+ void this.watchQueries(watcher);
46
+ }
47
+ break;
48
+ case WatcherTypeEnum.CACHE:
49
+ if (this.config.cacheWatcherEnabled) {
50
+ void this.watchCache(watcher);
51
+ }
52
+ break;
53
+ }
54
+ }
55
+ }
56
+ registerRoutes(routes) {
57
+ routes.forEach((route) => {
58
+ this.app.route({
59
+ method: route.method.toUpperCase(),
60
+ url: this.normalizePath(route.path),
61
+ handler: async (request, reply) => {
62
+ const result = await route.handler({
63
+ params: request.params,
64
+ qs: request.query
65
+ });
66
+ return reply.send(result);
67
+ }
68
+ });
69
+ });
70
+ }
71
+ serveUI(uiPath, spaRoute, _dataToInject) {
72
+ this.app.register(fastifyStatic, {
73
+ root: uiPath,
74
+ prefix: `${this.normalizePath(lensUtils.normalizePath(spaRoute))}/`,
75
+ wildcard: false,
76
+ serve: false
77
+ });
78
+ this.app.get(`/${spaRoute}/*`, async (request, reply) => {
79
+ const url = request.url;
80
+ if (lensUtils.isStaticFile(url.split("/"))) {
81
+ const filePath = path.join(
82
+ uiPath,
83
+ lensUtils.stripBeforeAssetsPath(url)
84
+ );
85
+ return reply.sendFile(`${path.relative(uiPath, filePath)}`);
86
+ }
87
+ return reply.sendFile("index.html", uiPath);
88
+ });
89
+ }
90
+ async watchCache(watcher) {
91
+ if (!this.config.cacheWatcherEnabled) return;
92
+ lensEmitter.on("cache", async (data) => {
93
+ await watcher?.log(data);
94
+ });
95
+ }
96
+ async watchQueries(watcher) {
97
+ if (!this.config.queryWatcher?.enabled) return;
98
+ const handler = this.config.queryWatcher.handler;
99
+ await handler({
100
+ onQuery: async (query) => {
101
+ const queryPayload = {
102
+ query: query.query,
103
+ duration: query.duration || "0 ms",
104
+ createdAt: query.createdAt || nowISO(),
105
+ type: query.type
106
+ };
107
+ await watcher?.log({
108
+ data: queryPayload,
109
+ requestId: lensContext.getStore()?.requestId ?? ""
110
+ });
111
+ }
112
+ });
113
+ }
114
+ watchRequests(requestWatcher) {
115
+ if (!this.config.requestWatcherEnabled) return;
116
+ this.app.addHook(
117
+ "onRequest",
118
+ (request, _, done) => {
119
+ if (this.shouldIgnorePath(request.url)) return done();
120
+ const context = {
121
+ requestId: lensUtils.generateRandomUuid()
122
+ };
123
+ request.lensContext = context;
124
+ request.lensStartTime = process.hrtime();
125
+ lensContext.run(context, done);
126
+ }
127
+ );
128
+ this.app.addHook(
129
+ "onSend",
130
+ async (request, reply, payload) => {
131
+ if (this.shouldIgnorePath(request.url)) return payload;
132
+ reply._lensBody = this.parseResponsePayload(payload);
133
+ return payload;
134
+ }
135
+ );
136
+ this.app.addHook(
137
+ "onResponse",
138
+ async (request, reply) => {
139
+ if (this.shouldIgnorePath(request.url)) return;
140
+ const startTime = request.lensStartTime;
141
+ await this.finalizeRequestLog(
142
+ request,
143
+ reply,
144
+ requestWatcher,
145
+ startTime
146
+ );
147
+ }
148
+ );
149
+ }
150
+ async finalizeRequestLog(request, reply, requestWatcher, start) {
151
+ try {
152
+ const duration = lensUtils.prettyHrTime(process.hrtime(start));
153
+ const logPayload = {
154
+ request: {
155
+ id: lensContext.getStore()?.requestId || lensUtils.generateRandomUuid(),
156
+ method: request.method,
157
+ duration,
158
+ path: request.url,
159
+ headers: request.headers,
160
+ body: request.body ?? {},
161
+ status: reply.statusCode,
162
+ ip: request.ip ?? "",
163
+ createdAt: nowISO()
164
+ },
165
+ response: {
166
+ json: this.parseBody(reply._lensBody),
167
+ headers: reply.getHeaders()
168
+ },
169
+ user: await this.config.isAuthenticated?.(request) ? await this.config.getUser?.(request) : null
170
+ };
171
+ await requestWatcher.log(logPayload);
172
+ } catch (err) {
173
+ console.error("Error finalizing request log:", err);
174
+ }
175
+ }
176
+ parseResponsePayload(payload) {
177
+ if (!payload) {
178
+ return null;
179
+ }
180
+ try {
181
+ if (typeof payload === "string") {
182
+ try {
183
+ return JSON.parse(payload);
184
+ } catch {
185
+ const filePath = path.resolve(payload);
186
+ if (fs.existsSync(filePath)) {
187
+ return "Purged By Lens";
188
+ }
189
+ return "Purged By Lens";
190
+ }
191
+ } else if (Buffer.isBuffer(payload)) {
192
+ return "Purged By Lens";
193
+ } else if (typeof payload === "object") {
194
+ return payload;
195
+ } else {
196
+ return payload;
197
+ }
198
+ } catch {
199
+ return "Purged By Lens";
200
+ }
201
+ }
202
+ normalizePath(pathStr) {
203
+ return pathStr.startsWith("/") ? pathStr : `/${pathStr}`;
204
+ }
205
+ parseBody(body) {
206
+ if (!body) {
207
+ return null;
208
+ }
209
+ try {
210
+ return JSON.parse(body);
211
+ } catch (_e) {
212
+ return body;
213
+ }
214
+ }
215
+ };
216
+
217
+ // src/index.ts
218
+ import { WatcherTypeEnum as WatcherTypeEnum2 } from "@lensjs/core";
219
+ import { lensExceptionUtils } from "@lensjs/core";
220
+ var defaultConfig = {
221
+ appName: "Lens",
222
+ enabled: true,
223
+ path: "/lens",
224
+ ignoredPaths: [],
225
+ onlyPaths: [],
226
+ requestWatcherEnabled: true,
227
+ cacheWatcherEnabled: false,
228
+ exceptionWatcherEnabled: true,
229
+ registerErrorHandler: true
230
+ };
231
+ var lens = async (config) => {
232
+ const adapter = new FastifyAdapter({ app: config.app });
233
+ const watchers = [];
234
+ const mergedConfig = {
235
+ ...defaultConfig,
236
+ ...config
237
+ };
238
+ const defaultWatchers = [
239
+ {
240
+ enabled: mergedConfig.requestWatcherEnabled,
241
+ watcher: new RequestWatcher2()
242
+ },
243
+ {
244
+ enabled: mergedConfig.cacheWatcherEnabled,
245
+ watcher: new CacheWatcher2()
246
+ },
247
+ {
248
+ enabled: mergedConfig.queryWatcher?.enabled,
249
+ watcher: new QueryWatcher2()
250
+ },
251
+ {
252
+ enabled: mergedConfig.exceptionWatcherEnabled,
253
+ watcher: new ExceptionWatcher()
254
+ }
255
+ ];
256
+ defaultWatchers.forEach((watcher) => {
257
+ if (watcher.enabled) {
258
+ watchers.push(watcher.watcher);
259
+ }
260
+ });
261
+ const { ignoredPaths, normalizedPath } = lensUtils2.prepareIgnoredPaths(
262
+ mergedConfig.path,
263
+ mergedConfig.ignoredPaths
264
+ );
265
+ adapter.setConfig(mergedConfig).setIgnoredPaths(ignoredPaths).setOnlyPaths(mergedConfig.onlyPaths);
266
+ if (mergedConfig.exceptionWatcherEnabled && mergedConfig.registerErrorHandler) {
267
+ handleExceptions({
268
+ app: mergedConfig.app,
269
+ enabled: mergedConfig.exceptionWatcherEnabled && mergedConfig.enabled,
270
+ watcher: watchers.find(
271
+ (w) => w.name === WatcherTypeEnum2.EXCEPTION
272
+ )
273
+ });
274
+ }
275
+ await Lens.setAdapter(adapter).setWatchers(watchers).start({
276
+ appName: mergedConfig.appName,
277
+ enabled: mergedConfig.enabled,
278
+ basePath: normalizedPath
279
+ });
280
+ const exceptionWatcher = watchers.find(
281
+ (w) => w.name === WatcherTypeEnum2.EXCEPTION
282
+ );
283
+ return {
284
+ logException: (error) => logException(
285
+ error,
286
+ mergedConfig.exceptionWatcherEnabled && mergedConfig.enabled,
287
+ exceptionWatcher
288
+ )
289
+ };
290
+ };
291
+ function logException(error, enabled, watcher) {
292
+ if (!enabled || !watcher) return;
293
+ watcher.log({
294
+ ...lensExceptionUtils.constructErrorObject(error),
295
+ requestId: lensContext2.getStore()?.requestId ?? ""
296
+ });
297
+ }
298
+ function handleExceptions({
299
+ app,
300
+ enabled,
301
+ watcher
302
+ }) {
303
+ app.setErrorHandler((err) => {
304
+ logException(err, enabled, watcher);
305
+ });
306
+ }
307
+ export {
308
+ FastifyAdapter,
309
+ lens
310
+ };
package/dist/types.cjs ADDED
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+
16
+ // src/types.ts
17
+ var types_exports = {};
18
+ module.exports = __toCommonJS(types_exports);
@@ -0,0 +1,40 @@
1
+ import { FastifyInstance, FastifyRequest } from 'fastify';
2
+ import { QueryWatcherHandler } from '@lensjs/watchers';
3
+ import { UserEntry } from '@lensjs/core';
4
+ import { SendOptions } from '@fastify/static';
5
+
6
+ type FastifyAdapterConfig = {
7
+ app: FastifyInstance;
8
+ appName?: string;
9
+ enabled?: boolean;
10
+ path?: string;
11
+ ignoredPaths?: RegExp[];
12
+ onlyPaths?: RegExp[];
13
+ requestWatcherEnabled?: boolean;
14
+ cacheWatcherEnabled?: boolean;
15
+ exceptionWatcherEnabled?: boolean;
16
+ registerErrorHandler?: boolean;
17
+ queryWatcher?: {
18
+ enabled: boolean;
19
+ handler: QueryWatcherHandler;
20
+ };
21
+ isAuthenticated?: (request: FastifyRequest) => Promise<boolean>;
22
+ getUser?: (request: FastifyRequest) => Promise<UserEntry>;
23
+ };
24
+ type RequiredFastifyAdapterConfig = Required<FastifyAdapterConfig> & {
25
+ queryWatcher?: FastifyAdapterConfig["queryWatcher"];
26
+ isAuthenticated?: FastifyAdapterConfig["isAuthenticated"];
27
+ getUser?: FastifyAdapterConfig["getUser"];
28
+ };
29
+ declare module "fastify" {
30
+ interface FastifyReply {
31
+ sendFile(filename: string, rootPath?: string): FastifyReply;
32
+ sendFile(filename: string, options?: SendOptions): FastifyReply;
33
+ sendFile(filename: string, rootPath?: string, options?: SendOptions): FastifyReply;
34
+ download(filepath: string, options?: SendOptions): FastifyReply;
35
+ download(filepath: string, filename?: string): FastifyReply;
36
+ download(filepath: string, filename?: string, options?: SendOptions): FastifyReply;
37
+ }
38
+ }
39
+
40
+ export type { FastifyAdapterConfig, RequiredFastifyAdapterConfig };
@@ -0,0 +1,40 @@
1
+ import { FastifyInstance, FastifyRequest } from 'fastify';
2
+ import { QueryWatcherHandler } from '@lensjs/watchers';
3
+ import { UserEntry } from '@lensjs/core';
4
+ import { SendOptions } from '@fastify/static';
5
+
6
+ type FastifyAdapterConfig = {
7
+ app: FastifyInstance;
8
+ appName?: string;
9
+ enabled?: boolean;
10
+ path?: string;
11
+ ignoredPaths?: RegExp[];
12
+ onlyPaths?: RegExp[];
13
+ requestWatcherEnabled?: boolean;
14
+ cacheWatcherEnabled?: boolean;
15
+ exceptionWatcherEnabled?: boolean;
16
+ registerErrorHandler?: boolean;
17
+ queryWatcher?: {
18
+ enabled: boolean;
19
+ handler: QueryWatcherHandler;
20
+ };
21
+ isAuthenticated?: (request: FastifyRequest) => Promise<boolean>;
22
+ getUser?: (request: FastifyRequest) => Promise<UserEntry>;
23
+ };
24
+ type RequiredFastifyAdapterConfig = Required<FastifyAdapterConfig> & {
25
+ queryWatcher?: FastifyAdapterConfig["queryWatcher"];
26
+ isAuthenticated?: FastifyAdapterConfig["isAuthenticated"];
27
+ getUser?: FastifyAdapterConfig["getUser"];
28
+ };
29
+ declare module "fastify" {
30
+ interface FastifyReply {
31
+ sendFile(filename: string, rootPath?: string): FastifyReply;
32
+ sendFile(filename: string, options?: SendOptions): FastifyReply;
33
+ sendFile(filename: string, rootPath?: string, options?: SendOptions): FastifyReply;
34
+ download(filepath: string, options?: SendOptions): FastifyReply;
35
+ download(filepath: string, filename?: string): FastifyReply;
36
+ download(filepath: string, filename?: string, options?: SendOptions): FastifyReply;
37
+ }
38
+ }
39
+
40
+ export type { FastifyAdapterConfig, RequiredFastifyAdapterConfig };
package/dist/types.js ADDED
File without changes
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@lensjs/fastify",
3
+ "version": "1.0.1",
4
+ "description": "Fastify adapter for LensJs",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "type": "module",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "require": "./dist/index.cjs",
14
+ "import": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "dependencies": {
21
+ "@fastify/static": "8.2.0",
22
+ "@lensjs/core": "2.2.0",
23
+ "@lensjs/date": "1.0.12",
24
+ "@lensjs/typescript-config": "1.0.12",
25
+ "@lensjs/watchers": "1.0.16"
26
+ },
27
+ "devDependencies": {
28
+ "fastify": "^5.6.0",
29
+ "vitest": "^3.2.4"
30
+ },
31
+ "peerDependencies": {
32
+ "fastify": "^5.2.1"
33
+ },
34
+ "scripts": {
35
+ "build": "tsup --clean",
36
+ "test": "vitest run"
37
+ }
38
+ }