@lensjs/core 1.0.12 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/README.md +69 -0
  2. package/dist/abstracts/store.cjs +23 -0
  3. package/dist/abstracts/store.d.cts +7 -2
  4. package/dist/abstracts/store.d.ts +7 -2
  5. package/dist/abstracts/store.js +23 -0
  6. package/dist/core/api_controller.cjs +47 -4
  7. package/dist/core/api_controller.d.cts +7 -3
  8. package/dist/core/api_controller.d.ts +7 -3
  9. package/dist/core/api_controller.js +47 -4
  10. package/dist/core/lens.cjs +109 -10
  11. package/dist/core/lens.js +110 -11
  12. package/dist/exception-3AZsPtAg.d.ts +52 -0
  13. package/dist/exception-C69UCHPk.d.cts +52 -0
  14. package/dist/index.cjs +301 -19
  15. package/dist/index.d.cts +7 -2
  16. package/dist/index.d.ts +7 -2
  17. package/dist/index.js +296 -20
  18. package/dist/stores/better_sqlite.cjs +40 -6
  19. package/dist/stores/better_sqlite.d.cts +17 -1
  20. package/dist/stores/better_sqlite.d.ts +17 -1
  21. package/dist/stores/better_sqlite.js +41 -7
  22. package/dist/stores/index.cjs +40 -6
  23. package/dist/stores/index.js +41 -7
  24. package/dist/types/index.cjs +2 -0
  25. package/dist/types/index.d.cts +49 -2
  26. package/dist/types/index.d.ts +49 -2
  27. package/dist/types/index.js +2 -0
  28. package/dist/ui/assets/CacheActionBadge-3t8U516j.js +1 -0
  29. package/dist/ui/assets/CacheEntriesTable-BqLquILg.js +1 -0
  30. package/dist/ui/assets/CacheEntryContainer-B86waEsR.js +2 -0
  31. package/dist/ui/assets/CacheEntryDetails-Dm-oXALj.js +1 -0
  32. package/dist/ui/assets/CacheEntryDetailsContainer-BCyXGgkx.js +2 -0
  33. package/dist/ui/assets/ExceptionContainer-DSQBz5cb.js +2 -0
  34. package/dist/ui/assets/ExceptionDetails-gmpSQ_eu.js +16 -0
  35. package/dist/ui/assets/ExceptionDetailsContainer-BHIz-TUv.js +2 -0
  36. package/dist/ui/assets/ExceptionTable-BhrX9MSS.js +1 -0
  37. package/dist/ui/assets/LoadMore-26PcNWcP.js +1 -0
  38. package/dist/ui/assets/QueriesContainer-BSF-O4s3.js +2 -0
  39. package/dist/ui/assets/{QueryDetailsContainer-E7P-IO7f.js → QueryDetailsContainer-BjQM9QIb.js} +15 -15
  40. package/dist/ui/assets/QueryTable-szgIT5Uc.js +1 -0
  41. package/dist/ui/assets/RequestDetails-CvQhX-2F.js +1 -0
  42. package/dist/ui/assets/{RequestDetailsContainer-DuDo-IqS.js → RequestDetailsContainer-XYPFJFX0.js} +2 -2
  43. package/dist/ui/assets/RequestsContainer-D0QPK2Ii.js +2 -0
  44. package/dist/ui/assets/RequetsTable-6Fqchsrt.js +1 -0
  45. package/dist/ui/assets/{StatusCode-FQEjz7gK.js → StatusCode-CfVCLID2.js} +1 -1
  46. package/dist/ui/assets/TabbedDataViewer-Cl5ednx4.js +1 -0
  47. package/dist/ui/assets/{Table-DYaXk80S.js → Table-CGe8JwTO.js} +2 -2
  48. package/dist/ui/assets/columns-BFxCubt5.js +1 -0
  49. package/dist/ui/assets/columns-Cw7tw3Em.js +1 -0
  50. package/dist/ui/assets/columns-RiCoo9Ea.js +1 -0
  51. package/dist/ui/assets/{index-CpP2Ap5X.js → index-BRRKsoNv.js} +1 -1
  52. package/dist/ui/assets/index-BzFeZyjf.css +1 -0
  53. package/dist/ui/assets/{index-BS8XxorB.js → index-XoJlyTFO.js} +32 -22
  54. package/dist/ui/assets/useCacheEntries-SCADuxKq.js +1 -0
  55. package/dist/ui/assets/useExceptions-BMGL3nir.js +1 -0
  56. package/dist/ui/assets/useLensApi-BYyiIIZR.js +1 -0
  57. package/dist/ui/assets/{useLoadMore-CJltToLI.js → useLoadMore-CksOcXOF.js} +1 -1
  58. package/dist/ui/assets/useQueries-6nYr0oG5.js +1 -0
  59. package/dist/ui/index.html +2 -2
  60. package/dist/utils/async_context.cjs +144 -0
  61. package/dist/utils/async_context.d.cts +13 -0
  62. package/dist/utils/async_context.d.ts +13 -0
  63. package/dist/utils/async_context.js +108 -0
  64. package/dist/utils/event_emitter.cjs +5 -2
  65. package/dist/utils/event_emitter.d.cts +8 -1
  66. package/dist/utils/event_emitter.d.ts +8 -1
  67. package/dist/utils/event_emitter.js +3 -1
  68. package/dist/utils/exception.cjs +130 -0
  69. package/dist/utils/exception.d.cts +3 -0
  70. package/dist/utils/exception.d.ts +3 -0
  71. package/dist/utils/exception.js +91 -0
  72. package/dist/watchers/cache_watcher.cjs +107 -0
  73. package/dist/watchers/cache_watcher.d.cts +11 -0
  74. package/dist/watchers/cache_watcher.d.ts +11 -0
  75. package/dist/watchers/cache_watcher.js +84 -0
  76. package/dist/watchers/exception_watcher.cjs +108 -0
  77. package/dist/watchers/exception_watcher.d.cts +10 -0
  78. package/dist/watchers/exception_watcher.d.ts +10 -0
  79. package/dist/watchers/exception_watcher.js +75 -0
  80. package/dist/watchers/index.cjs +81 -0
  81. package/dist/watchers/index.d.cts +2 -0
  82. package/dist/watchers/index.d.ts +2 -0
  83. package/dist/watchers/index.js +69 -0
  84. package/package.json +8 -6
  85. package/dist/ui/assets/QueriesContainer-CAAsjjW5.js +0 -2
  86. package/dist/ui/assets/QueryTable-BcrtUssT.js +0 -1
  87. package/dist/ui/assets/RequestDetails-C2DZBu5H.js +0 -1
  88. package/dist/ui/assets/RequestsContainer-DK3hQVz9.js +0 -2
  89. package/dist/ui/assets/RequetsTable-DgP8p60b.js +0 -1
  90. package/dist/ui/assets/TabbedDataViewer-cBDdPwIz.js +0 -1
  91. package/dist/ui/assets/index-DzNHqeKh.css +0 -1
  92. package/dist/ui/assets/useLensApi-DG6atd6d.js +0 -1
  93. package/dist/ui/assets/useQueries-C8mDDDc6.js +0 -1
package/README.md ADDED
@@ -0,0 +1,69 @@
1
+ # @lensjs/core
2
+
3
+ The core library for Lens, providing the fundamental architecture for monitoring and debugging applications. It defines the abstract concepts of adapters, stores, and watchers, along with utilities for event emission, asynchronous context management, and SQL formatting. This package also includes the embedded UI for the Lens dashboard.
4
+
5
+ ## Features
6
+
7
+ * **`Lens` class**: The central class for initializing Lens, setting up adapters and watchers, and starting the monitoring process.
8
+ * **`LensAdapter` (abstract class)**: Defines the interface for integrating Lens with different application frameworks (e.g., Express, Adonis). It handles route registration and UI serving.
9
+ * **`LensStore` (abstract class)**: Defines the interface for data storage, allowing Lens to persist and retrieve captured events (requests, queries, cache entries). Includes methods for saving, retrieving, and truncating data.
10
+ * **`LensWatcher` (abstract class)**: Defines the interface for capturing specific types of events within an application.
11
+ * **Concrete Watchers**:
12
+ * `RequestWatcher`: Captures and logs details of incoming HTTP requests.
13
+ * `QueryWatcher`: Captures and logs database queries.
14
+ * `CacheWatcher`: Captures and logs cache interactions.
15
+ * `ExceptionWatcher`: Captures and logs exceptions and errors.
16
+ * **`ApiController`**: Provides the API endpoints for the Lens UI to fetch monitoring data.
17
+ * **`lensEmitter`**: A global event emitter for internal communication between different parts of Lens.
18
+ * **`lensContext`**: Utilizes `AsyncLocalStorage` for managing asynchronous context, primarily to associate events with a specific request ID.
19
+ * **`lensUtils`**: A collection of utility functions, including:
20
+ * `generateRandomUuid`: Generates unique IDs.
21
+ * `interpolateQuery`: Interpolates SQL query placeholders with actual values.
22
+ * `formatSqlQuery`: Formats SQL queries for readability.
23
+ * `getMeta`: Provides `__filename` and `__dirname` in both CommonJS and ESM environments.
24
+ * `isStaticFile`, `stripBeforeAssetsPath`: Utilities for handling static file paths.
25
+ * `prepareIgnoredPaths`, `shouldIgnoreCurrentPath`: Logic for path-based filtering.
26
+ * `prettyHrTime`: Formats high-resolution time differences.
27
+ * **`BetterSqliteStore`**: A concrete implementation of `LensStore` using Better SQLite for data persistence.
28
+ * **Embedded UI**: Includes a built-in web interface for visualizing captured application data.
29
+
30
+ ## Installation
31
+
32
+ ```bash
33
+ pnpm add @lensjs/core
34
+ ```
35
+
36
+ ## Usage Example (Conceptual - typically used via framework adapters)
37
+
38
+ ```typescript
39
+ import { Lens, RequestWatcher, QueryWatcher, CacheWatcher } from '@lensjs/core';
40
+ import { BetterSqliteStore } from '@lensjs/core/stores';
41
+ // Assuming you have a custom adapter for your framework
42
+ import MyFrameworkAdapter from './my-framework-adapter';
43
+
44
+ async function bootstrapLens(appInstance: any) {
45
+ const store = new BetterSqliteStore();
46
+ await store.initialize();
47
+
48
+ const adapter = new MyFrameworkAdapter({ app: appInstance });
49
+
50
+ await Lens.setStore(store)
51
+ .setAdapter(adapter)
52
+ .setWatchers([
53
+ new RequestWatcher(),
54
+ new QueryWatcher(),
55
+ new CacheWatcher(),
56
+ new ExceptionWatcher(),
57
+ ])
58
+ .start({
59
+ appName: 'My Application',
60
+ enabled: process.env.NODE_ENV !== 'production',
61
+ basePath: 'lens-dashboard', // UI will be served at /lens-dashboard
62
+ });
63
+
64
+ console.log('Lens core initialized.');
65
+ }
66
+
67
+ // In your application's main entry point:
68
+ // bootstrapLens(yourFrameworkAppInstance);
69
+ ```
@@ -24,4 +24,27 @@ __export(store_exports, {
24
24
  });
25
25
  module.exports = __toCommonJS(store_exports);
26
26
  var Store = class {
27
+ getAllExceptions(_paginationParams) {
28
+ return this.defaultMinimalPaginate();
29
+ }
30
+ stringifyData(data) {
31
+ if (typeof data === "string") {
32
+ return data;
33
+ }
34
+ try {
35
+ return JSON.stringify(data);
36
+ } catch (e) {
37
+ console.error(`Failed to stringify lens data: ${e}`);
38
+ }
39
+ }
40
+ defaultMinimalPaginate() {
41
+ return Promise.resolve({
42
+ data: [],
43
+ meta: {
44
+ currentPage: 0,
45
+ lastPage: 0,
46
+ total: 0
47
+ }
48
+ });
49
+ }
27
50
  };
@@ -1,6 +1,7 @@
1
1
  import { WatcherTypeEnum, PaginationParams, Paginator, LensEntry } from '../types/index.cjs';
2
2
  import 'sql-formatter';
3
3
 
4
+ type MinimalPaginatePromise = Promise<Paginator<Omit<LensEntry, "data">[]>>;
4
5
  declare abstract class Store {
5
6
  abstract initialize(): Promise<void>;
6
7
  abstract save(entry: {
@@ -11,13 +12,17 @@ declare abstract class Store {
11
12
  timestamp?: string;
12
13
  requestId?: string;
13
14
  }): Promise<void>;
14
- abstract getAllRequests(paginationParams: PaginationParams): Promise<Paginator<Omit<LensEntry, "data">[]>>;
15
+ abstract getAllRequests(paginationParams: PaginationParams): MinimalPaginatePromise;
15
16
  abstract getAllQueries(paginationParams: PaginationParams): Promise<Paginator<LensEntry[]>>;
16
- abstract allByRequestId(requestId: string, type: WatcherTypeEnum): Promise<LensEntry[]>;
17
+ abstract getAllCacheEntries(paginationParams: PaginationParams): MinimalPaginatePromise;
18
+ abstract allByRequestId(requestId: string, type: WatcherTypeEnum, includeFullData?: boolean): Promise<LensEntry[]>;
17
19
  abstract find(type: WatcherTypeEnum, id: string): Promise<LensEntry | null>;
18
20
  abstract truncate(): Promise<void>;
19
21
  abstract paginate<T>(type: WatcherTypeEnum, pagination: PaginationParams): Promise<Paginator<T>>;
20
22
  abstract count(type: WatcherTypeEnum): Promise<number>;
23
+ getAllExceptions(_paginationParams: PaginationParams): MinimalPaginatePromise;
24
+ protected stringifyData(data: Record<string, any> | string): string | undefined;
25
+ protected defaultMinimalPaginate(): MinimalPaginatePromise;
21
26
  }
22
27
 
23
28
  export { Store as default };
@@ -1,6 +1,7 @@
1
1
  import { WatcherTypeEnum, PaginationParams, Paginator, LensEntry } from '../types/index.js';
2
2
  import 'sql-formatter';
3
3
 
4
+ type MinimalPaginatePromise = Promise<Paginator<Omit<LensEntry, "data">[]>>;
4
5
  declare abstract class Store {
5
6
  abstract initialize(): Promise<void>;
6
7
  abstract save(entry: {
@@ -11,13 +12,17 @@ declare abstract class Store {
11
12
  timestamp?: string;
12
13
  requestId?: string;
13
14
  }): Promise<void>;
14
- abstract getAllRequests(paginationParams: PaginationParams): Promise<Paginator<Omit<LensEntry, "data">[]>>;
15
+ abstract getAllRequests(paginationParams: PaginationParams): MinimalPaginatePromise;
15
16
  abstract getAllQueries(paginationParams: PaginationParams): Promise<Paginator<LensEntry[]>>;
16
- abstract allByRequestId(requestId: string, type: WatcherTypeEnum): Promise<LensEntry[]>;
17
+ abstract getAllCacheEntries(paginationParams: PaginationParams): MinimalPaginatePromise;
18
+ abstract allByRequestId(requestId: string, type: WatcherTypeEnum, includeFullData?: boolean): Promise<LensEntry[]>;
17
19
  abstract find(type: WatcherTypeEnum, id: string): Promise<LensEntry | null>;
18
20
  abstract truncate(): Promise<void>;
19
21
  abstract paginate<T>(type: WatcherTypeEnum, pagination: PaginationParams): Promise<Paginator<T>>;
20
22
  abstract count(type: WatcherTypeEnum): Promise<number>;
23
+ getAllExceptions(_paginationParams: PaginationParams): MinimalPaginatePromise;
24
+ protected stringifyData(data: Record<string, any> | string): string | undefined;
25
+ protected defaultMinimalPaginate(): MinimalPaginatePromise;
21
26
  }
22
27
 
23
28
  export { Store as default };
@@ -1,5 +1,28 @@
1
1
  // src/abstracts/store.ts
2
2
  var Store = class {
3
+ getAllExceptions(_paginationParams) {
4
+ return this.defaultMinimalPaginate();
5
+ }
6
+ stringifyData(data) {
7
+ if (typeof data === "string") {
8
+ return data;
9
+ }
10
+ try {
11
+ return JSON.stringify(data);
12
+ } catch (e) {
13
+ console.error(`Failed to stringify lens data: ${e}`);
14
+ }
15
+ }
16
+ defaultMinimalPaginate() {
17
+ return Promise.resolve({
18
+ data: [],
19
+ meta: {
20
+ currentPage: 0,
21
+ lastPage: 0,
22
+ total: 0
23
+ }
24
+ });
25
+ }
3
26
  };
4
27
  export {
5
28
  Store as default
@@ -74,14 +74,30 @@ var ApiController = class {
74
74
  await getStore().getAllRequests(this.extractPaginationParams(qs))
75
75
  );
76
76
  }
77
- static async getRequest({
78
- params
79
- }) {
77
+ static async getRequest({ params }) {
80
78
  const request = await getStore().find("request" /* REQUEST */, params.id);
81
79
  if (!request) {
82
80
  return this.notFoundResponse();
83
81
  }
84
- return this.resourceResponse(request);
82
+ const queries = await getStore().allByRequestId(
83
+ request.id,
84
+ "query" /* QUERY */
85
+ );
86
+ const cacheEntries = await getStore().allByRequestId(
87
+ request.id,
88
+ "cache" /* CACHE */
89
+ );
90
+ const exceptions = await getStore().allByRequestId(
91
+ request.id,
92
+ "exception" /* EXCEPTION */,
93
+ false
94
+ );
95
+ return this.resourceResponse({
96
+ request,
97
+ queries,
98
+ cacheEntries,
99
+ exceptions
100
+ });
85
101
  }
86
102
  static async getQueries({
87
103
  qs
@@ -100,6 +116,33 @@ var ApiController = class {
100
116
  }
101
117
  return this.resourceResponse(query);
102
118
  }
119
+ static async getCacheEntries({ qs }) {
120
+ return this.paginatedResponse(
121
+ await getStore().getAllCacheEntries(this.extractPaginationParams(qs))
122
+ );
123
+ }
124
+ static async getCacheEntry({ params }) {
125
+ const cacheEntry = await getStore().find("cache" /* CACHE */, params.id);
126
+ if (!cacheEntry) {
127
+ return this.notFoundResponse();
128
+ }
129
+ return this.resourceResponse(cacheEntry);
130
+ }
131
+ static async getExceptions({ qs }) {
132
+ return this.paginatedResponse(
133
+ await getStore().getAllExceptions(this.extractPaginationParams(qs))
134
+ );
135
+ }
136
+ static async getException({ params }) {
137
+ const exception = await getStore().find(
138
+ "exception" /* EXCEPTION */,
139
+ params.id
140
+ );
141
+ if (!exception) {
142
+ return this.notFoundResponse();
143
+ }
144
+ return this.resourceResponse(exception);
145
+ }
103
146
  static async truncate() {
104
147
  await getStore().truncate();
105
148
  return this.baseResponse({}, 200, "All entries cleared");
@@ -1,11 +1,15 @@
1
- import { RouteDefinitionHandler, ApiResponse, LensEntry } from '../types/index.cjs';
1
+ import { RouteDefinitionHandler, ApiResponse, LensEntry, Paginator } from '../types/index.cjs';
2
2
  import 'sql-formatter';
3
3
 
4
4
  declare class ApiController {
5
5
  static getRequests({ qs }: RouteDefinitionHandler): Promise<ApiResponse<Omit<LensEntry, "data">[]>>;
6
- static getRequest({ params, }: RouteDefinitionHandler): Promise<ApiResponse<LensEntry>>;
6
+ static getRequest({ params }: RouteDefinitionHandler): Promise<ApiResponse<Object>>;
7
7
  static getQueries({ qs, }: RouteDefinitionHandler): Promise<ApiResponse<LensEntry[]>>;
8
8
  static getQuery({ params, }: RouteDefinitionHandler): Promise<ApiResponse<LensEntry>>;
9
+ static getCacheEntries({ qs }: RouteDefinitionHandler): Promise<ApiResponse<Omit<LensEntry, "data">[]>>;
10
+ static getCacheEntry({ params }: RouteDefinitionHandler): Promise<ApiResponse<Object>>;
11
+ static getExceptions({ qs }: RouteDefinitionHandler): Promise<ApiResponse<Omit<LensEntry, "data">[]>>;
12
+ static getException({ params }: RouteDefinitionHandler): Promise<ApiResponse<Object>>;
9
13
  static truncate(): Promise<ApiResponse<{}>>;
10
14
  static fetchUiConfig(): {
11
15
  appName: string;
@@ -18,7 +22,7 @@ declare class ApiController {
18
22
  private static extractPaginationParams;
19
23
  private static resourceResponse;
20
24
  private static notFoundResponse;
21
- private static paginatedResponse;
25
+ static paginatedResponse<T extends Object>(data: Paginator<T>): ApiResponse<T>;
22
26
  private static baseResponse;
23
27
  }
24
28
 
@@ -1,11 +1,15 @@
1
- import { RouteDefinitionHandler, ApiResponse, LensEntry } from '../types/index.js';
1
+ import { RouteDefinitionHandler, ApiResponse, LensEntry, Paginator } from '../types/index.js';
2
2
  import 'sql-formatter';
3
3
 
4
4
  declare class ApiController {
5
5
  static getRequests({ qs }: RouteDefinitionHandler): Promise<ApiResponse<Omit<LensEntry, "data">[]>>;
6
- static getRequest({ params, }: RouteDefinitionHandler): Promise<ApiResponse<LensEntry>>;
6
+ static getRequest({ params }: RouteDefinitionHandler): Promise<ApiResponse<Object>>;
7
7
  static getQueries({ qs, }: RouteDefinitionHandler): Promise<ApiResponse<LensEntry[]>>;
8
8
  static getQuery({ params, }: RouteDefinitionHandler): Promise<ApiResponse<LensEntry>>;
9
+ static getCacheEntries({ qs }: RouteDefinitionHandler): Promise<ApiResponse<Omit<LensEntry, "data">[]>>;
10
+ static getCacheEntry({ params }: RouteDefinitionHandler): Promise<ApiResponse<Object>>;
11
+ static getExceptions({ qs }: RouteDefinitionHandler): Promise<ApiResponse<Omit<LensEntry, "data">[]>>;
12
+ static getException({ params }: RouteDefinitionHandler): Promise<ApiResponse<Object>>;
9
13
  static truncate(): Promise<ApiResponse<{}>>;
10
14
  static fetchUiConfig(): {
11
15
  appName: string;
@@ -18,7 +22,7 @@ declare class ApiController {
18
22
  private static extractPaginationParams;
19
23
  private static resourceResponse;
20
24
  private static notFoundResponse;
21
- private static paginatedResponse;
25
+ static paginatedResponse<T extends Object>(data: Paginator<T>): ApiResponse<T>;
22
26
  private static baseResponse;
23
27
  }
24
28
 
@@ -48,14 +48,30 @@ var ApiController = class {
48
48
  await getStore().getAllRequests(this.extractPaginationParams(qs))
49
49
  );
50
50
  }
51
- static async getRequest({
52
- params
53
- }) {
51
+ static async getRequest({ params }) {
54
52
  const request = await getStore().find("request" /* REQUEST */, params.id);
55
53
  if (!request) {
56
54
  return this.notFoundResponse();
57
55
  }
58
- return this.resourceResponse(request);
56
+ const queries = await getStore().allByRequestId(
57
+ request.id,
58
+ "query" /* QUERY */
59
+ );
60
+ const cacheEntries = await getStore().allByRequestId(
61
+ request.id,
62
+ "cache" /* CACHE */
63
+ );
64
+ const exceptions = await getStore().allByRequestId(
65
+ request.id,
66
+ "exception" /* EXCEPTION */,
67
+ false
68
+ );
69
+ return this.resourceResponse({
70
+ request,
71
+ queries,
72
+ cacheEntries,
73
+ exceptions
74
+ });
59
75
  }
60
76
  static async getQueries({
61
77
  qs
@@ -74,6 +90,33 @@ var ApiController = class {
74
90
  }
75
91
  return this.resourceResponse(query);
76
92
  }
93
+ static async getCacheEntries({ qs }) {
94
+ return this.paginatedResponse(
95
+ await getStore().getAllCacheEntries(this.extractPaginationParams(qs))
96
+ );
97
+ }
98
+ static async getCacheEntry({ params }) {
99
+ const cacheEntry = await getStore().find("cache" /* CACHE */, params.id);
100
+ if (!cacheEntry) {
101
+ return this.notFoundResponse();
102
+ }
103
+ return this.resourceResponse(cacheEntry);
104
+ }
105
+ static async getExceptions({ qs }) {
106
+ return this.paginatedResponse(
107
+ await getStore().getAllExceptions(this.extractPaginationParams(qs))
108
+ );
109
+ }
110
+ static async getException({ params }) {
111
+ const exception = await getStore().find(
112
+ "exception" /* EXCEPTION */,
113
+ params.id
114
+ );
115
+ if (!exception) {
116
+ return this.notFoundResponse();
117
+ }
118
+ return this.resourceResponse(exception);
119
+ }
77
120
  static async truncate() {
78
121
  await getStore().truncate();
79
122
  return this.baseResponse({}, 200, "All entries cleared");
@@ -84,14 +84,30 @@ var ApiController = class {
84
84
  await getStore().getAllRequests(this.extractPaginationParams(qs))
85
85
  );
86
86
  }
87
- static async getRequest({
88
- params
89
- }) {
87
+ static async getRequest({ params }) {
90
88
  const request = await getStore().find("request" /* REQUEST */, params.id);
91
89
  if (!request) {
92
90
  return this.notFoundResponse();
93
91
  }
94
- return this.resourceResponse(request);
92
+ const queries = await getStore().allByRequestId(
93
+ request.id,
94
+ "query" /* QUERY */
95
+ );
96
+ const cacheEntries = await getStore().allByRequestId(
97
+ request.id,
98
+ "cache" /* CACHE */
99
+ );
100
+ const exceptions = await getStore().allByRequestId(
101
+ request.id,
102
+ "exception" /* EXCEPTION */,
103
+ false
104
+ );
105
+ return this.resourceResponse({
106
+ request,
107
+ queries,
108
+ cacheEntries,
109
+ exceptions
110
+ });
95
111
  }
96
112
  static async getQueries({
97
113
  qs
@@ -110,6 +126,33 @@ var ApiController = class {
110
126
  }
111
127
  return this.resourceResponse(query);
112
128
  }
129
+ static async getCacheEntries({ qs }) {
130
+ return this.paginatedResponse(
131
+ await getStore().getAllCacheEntries(this.extractPaginationParams(qs))
132
+ );
133
+ }
134
+ static async getCacheEntry({ params }) {
135
+ const cacheEntry = await getStore().find("cache" /* CACHE */, params.id);
136
+ if (!cacheEntry) {
137
+ return this.notFoundResponse();
138
+ }
139
+ return this.resourceResponse(cacheEntry);
140
+ }
141
+ static async getExceptions({ qs }) {
142
+ return this.paginatedResponse(
143
+ await getStore().getAllExceptions(this.extractPaginationParams(qs))
144
+ );
145
+ }
146
+ static async getException({ params }) {
147
+ const exception = await getStore().find(
148
+ "exception" /* EXCEPTION */,
149
+ params.id
150
+ );
151
+ if (!exception) {
152
+ return this.notFoundResponse();
153
+ }
154
+ return this.resourceResponse(exception);
155
+ }
113
156
  static async truncate() {
114
157
  await getStore().truncate();
115
158
  return this.baseResponse({}, 200, "All entries cleared");
@@ -161,6 +204,29 @@ var path2 = __toESM(require("path"), 1);
161
204
 
162
205
  // src/abstracts/store.ts
163
206
  var Store = class {
207
+ getAllExceptions(_paginationParams) {
208
+ return this.defaultMinimalPaginate();
209
+ }
210
+ stringifyData(data) {
211
+ if (typeof data === "string") {
212
+ return data;
213
+ }
214
+ try {
215
+ return JSON.stringify(data);
216
+ } catch (e) {
217
+ console.error(`Failed to stringify lens data: ${e}`);
218
+ }
219
+ }
220
+ defaultMinimalPaginate() {
221
+ return Promise.resolve({
222
+ data: [],
223
+ meta: {
224
+ currentPage: 0,
225
+ lastPage: 0,
226
+ total: 0
227
+ }
228
+ });
229
+ }
164
230
  };
165
231
 
166
232
  // src/stores/better_sqlite.ts
@@ -183,11 +249,11 @@ var BetterSqliteStore = class extends Store {
183
249
  `INSERT INTO ${TABLE_NAME} (id, data, type, created_at, lens_entry_id, minimal_data) values($id, $data, $type, $created_at, $lens_entry_id, $minimalData)`
184
250
  ).run({
185
251
  id: entry.id ?? (0, import_crypto.randomUUID)(),
186
- data: JSON.stringify(entry.data),
252
+ data: this.stringifyData(entry.data),
187
253
  type: entry.type,
188
- created_at: entry.timestamp ?? (0, import_date.sqlDateTime)(),
254
+ created_at: entry.timestamp ?? (0, import_date.nowISO)(),
189
255
  lens_entry_id: entry.requestId || null,
190
- minimalData: JSON.stringify(entry.minimal_data ?? {})
256
+ minimalData: this.stringifyData(entry.minimal_data ?? {})
191
257
  });
192
258
  }
193
259
  async getAllQueries(pagination) {
@@ -196,11 +262,17 @@ var BetterSqliteStore = class extends Store {
196
262
  async getAllRequests(pagination) {
197
263
  return await this.paginate("request" /* REQUEST */, pagination, false);
198
264
  }
199
- async allByRequestId(requestId, type) {
265
+ async getAllCacheEntries(pagination) {
266
+ return await this.paginate("cache" /* CACHE */, pagination);
267
+ }
268
+ async getAllExceptions(pagination) {
269
+ return await this.paginate("exception" /* EXCEPTION */, pagination, false);
270
+ }
271
+ async allByRequestId(requestId, type, includeFullData = true) {
200
272
  const rows = this.connection.prepare(
201
- `${this.getSelectedColumns()} FROM ${TABLE_NAME} WHERE type = $type AND lens_entry_id = $requestId ORDER BY created_at DESC`
273
+ `${this.getSelectedColumns(includeFullData)} FROM ${TABLE_NAME} WHERE type = $type AND lens_entry_id = $requestId ORDER BY created_at DESC`
202
274
  ).all({ type, requestId });
203
- return this.mapRows(rows);
275
+ return this.mapRows(rows, includeFullData);
204
276
  }
205
277
  async paginate(type, { page, perPage }, includeFullData = true) {
206
278
  const offset = (page - 1) * perPage;
@@ -248,8 +320,13 @@ var BetterSqliteStore = class extends Store {
248
320
  CREATE INDEX IF NOT EXISTS lens_entries_id_type_index
249
321
  ON ${TABLE_NAME} (id, type);
250
322
  `;
323
+ const lensEntryIdIndex = `
324
+ CREATE INDEX IF NOT EXISTS lens_entry_id_index
325
+ ON ${TABLE_NAME} (lens_entry_id);
326
+ `;
251
327
  this.connection.exec(createTable);
252
328
  this.connection.exec(createIndex);
329
+ this.connection.exec(lensEntryIdIndex);
253
330
  }
254
331
  mapRow(row, includeFullData = true) {
255
332
  let data = includeFullData ? JSON.parse(row.data) : {};
@@ -356,6 +433,8 @@ var Lens = class {
356
433
  api: {
357
434
  requests: `/${config.basePath}/api/requests`,
358
435
  queries: `/${config.basePath}/api/queries`,
436
+ cache: `/${config.basePath}/api/cache`,
437
+ exceptions: `/${config.basePath}/api/exceptions`,
359
438
  truncate: `/${config.basePath}/api/truncate`
360
439
  }
361
440
  };
@@ -388,6 +467,26 @@ var Lens = class {
388
467
  path: `${basePath}/api/queries/:id`,
389
468
  handler: async (data) => await ApiController.getQuery(data)
390
469
  },
470
+ {
471
+ method: "GET",
472
+ path: `${basePath}/api/cache`,
473
+ handler: async (data) => await ApiController.getCacheEntries(data)
474
+ },
475
+ {
476
+ method: "GET",
477
+ path: `${basePath}/api/cache/:id`,
478
+ handler: async (data) => await ApiController.getCacheEntry(data)
479
+ },
480
+ {
481
+ method: "GET",
482
+ path: `${basePath}/api/exceptions`,
483
+ handler: async (data) => await ApiController.getExceptions(data)
484
+ },
485
+ {
486
+ method: "GET",
487
+ path: `${basePath}/api/exceptions/:id`,
488
+ handler: async (data) => await ApiController.getException(data)
489
+ },
391
490
  {
392
491
  method: "DELETE",
393
492
  path: `${basePath}/api/truncate`,