@red-hat-developer-hub/backstage-plugin-adoption-insights-backend 0.0.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +180 -0
  3. package/config.d.ts +47 -0
  4. package/dist/controllers/EventApiController.cjs.js +122 -0
  5. package/dist/controllers/EventApiController.cjs.js.map +1 -0
  6. package/dist/database/DatabaseFactory.cjs.js +21 -0
  7. package/dist/database/DatabaseFactory.cjs.js.map +1 -0
  8. package/dist/database/adapters/BaseAdapter.cjs.js +276 -0
  9. package/dist/database/adapters/BaseAdapter.cjs.js.map +1 -0
  10. package/dist/database/adapters/PostgresAdapter.cjs.js +92 -0
  11. package/dist/database/adapters/PostgresAdapter.cjs.js.map +1 -0
  12. package/dist/database/adapters/SqliteAdapter.cjs.js +61 -0
  13. package/dist/database/adapters/SqliteAdapter.cjs.js.map +1 -0
  14. package/dist/database/migration.cjs.js +19 -0
  15. package/dist/database/migration.cjs.js.map +1 -0
  16. package/dist/database/partition.cjs.js +40 -0
  17. package/dist/database/partition.cjs.js.map +1 -0
  18. package/dist/domain/EventBatchProcessor.cjs.js +87 -0
  19. package/dist/domain/EventBatchProcessor.cjs.js.map +1 -0
  20. package/dist/index.cjs.js +10 -0
  21. package/dist/index.cjs.js.map +1 -0
  22. package/dist/index.d.ts +10 -0
  23. package/dist/models/Event.cjs.js +41 -0
  24. package/dist/models/Event.cjs.js.map +1 -0
  25. package/dist/plugin.cjs.js +64 -0
  26. package/dist/plugin.cjs.js.map +1 -0
  27. package/dist/router.cjs.js +63 -0
  28. package/dist/router.cjs.js.map +1 -0
  29. package/dist/types/event-request.cjs.js +14 -0
  30. package/dist/types/event-request.cjs.js.map +1 -0
  31. package/dist/utils/config.cjs.js +19 -0
  32. package/dist/utils/config.cjs.js.map +1 -0
  33. package/dist/utils/date.cjs.js +46 -0
  34. package/dist/utils/date.cjs.js.map +1 -0
  35. package/dist/validation/ValidationError.cjs.js +13 -0
  36. package/dist/validation/ValidationError.cjs.js.map +1 -0
  37. package/dist/validation/event-request.cjs.js +53 -0
  38. package/dist/validation/event-request.cjs.js.map +1 -0
  39. package/dist/validation/event.cjs.js +19 -0
  40. package/dist/validation/event.cjs.js.map +1 -0
  41. package/migrations/20250227120154_init.js +71 -0
  42. package/migrations/20250301104959_failed_events.js +39 -0
  43. package/package.json +71 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ # @red-hat-developer-hub/backstage-plugin-adoption-insights-backend
2
+
3
+ ## 0.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 480aa8e: Release Adoption insights plugin
8
+ - Updated dependencies [480aa8e]
9
+ - @red-hat-developer-hub/backstage-plugin-adoption-insights-common@0.1.1
package/README.md ADDED
@@ -0,0 +1,180 @@
1
+ # adoption-insights
2
+
3
+ This plugin builds the backend for Adoption Insights Plugin. It helps store analytics events emitted by analytics API into the DB and provides an API layer for the frontend.
4
+
5
+ ## Installation
6
+
7
+ This plugin is installed via the `@red-hat-developer-hub/backstage-plugin-adoption-insights-backend` package. To install it to your backend package, run the following command:
8
+
9
+ ```bash
10
+ # From your root directory
11
+ yarn --cwd packages/backend add @red-hat-developer-hub/backstage-plugin-adoption-insights-backend
12
+ ```
13
+
14
+ Then add the plugin to your backend in `packages/backend/src/index.ts`:
15
+
16
+ ```ts
17
+ const backend = createBackend();
18
+ // ...
19
+ backend.add(
20
+ import('@red-hat-developer-hub/backstage-plugin-adoption-insights-backend'),
21
+ );
22
+ ```
23
+
24
+ ## Configuration
25
+
26
+ ```yaml
27
+ app:
28
+ analytics:
29
+ adoptionInsights:
30
+ maxBufferSize: 25
31
+ flushInterval: 6000
32
+ debug: false # enable this to debug
33
+ licensedUsers: 100 # Administrators can set this value to see the user adoption metrics.
34
+ ```
35
+
36
+ #### Permission Framework Support
37
+
38
+ The Adoption Insights Backend plugin has support for the permission framework.
39
+
40
+ - When [RBAC permission](https://github.com/backstage/community-plugins/tree/main/workspaces/rbac/plugins/rbac-backend#installation) framework is enabled, for non-admin users to access Adoption Insights backend API, the role associated with your user should have the following permission policies associated with it. Add the following in your permission policies configuration file named `rbac-policy.csv`:
41
+
42
+ ```CSV
43
+ p, role:default/team_a, adoption-insights.events.read, read, allow
44
+
45
+ g, user:default/<your-user-name>, role:default/team_a
46
+
47
+ ```
48
+
49
+ You can specify the path to this configuration file in your application configuration:
50
+
51
+ ```yaml
52
+ permission:
53
+ enabled: true
54
+ rbac:
55
+ policies-csv-file: /some/path/rbac-policy.csv
56
+ policyFileReload: true
57
+ ```
58
+
59
+ - When using the [permission policy](https://backstage.io/docs/permissions/writing-a-policy/) framework. To test the permission policy, we have created a AdoptionInsightsTestPermissionPolicy and a permissionsPolicyExtension.
60
+
61
+ 1. add the policy extension module in the `workspaces/adoption-insights/packages/backend/src/index.ts` and comment the Allow all Permission policy module as shown below.
62
+
63
+ ```diff
64
+ backend.add(import('@backstage/plugin-permission-backend'));
65
+ // See https://backstage.io/docs/permissions/getting-started for how to create your own permission policy
66
+ -backend.add(
67
+ - import('@backstage/plugin-permission-backend-module-allow-all-policy'),
68
+ -);
69
+
70
+ +backend.add(import('./extensions/PermissionPolicyExtension'));
71
+
72
+ // search plugin
73
+ backend.add(import('@backstage/plugin-search-backend'));
74
+ ```
75
+
76
+ 2. Make a simple change to our [AdoptionInsightsTestPermissionPolicy](https://github.com/redhat-developer/rhdh-plugins/blob/main/workspaces/adoption-insights/packages/backend/src/extensions/PermissionPolicyExtension.ts) to confirm that policy is indeed wired up correctly. With the below change all the event API requests will fail with `Unauthorized` error.
77
+
78
+ ```diff
79
+ class AdoptionInsightsTestPermissionPolicy implements PermissionPolicy {
80
+ isPermission(request.permission, adoptionInsightsEventsReadPermission)
81
+ ) {
82
+ return {
83
+ - result: AuthorizeResult.ALLOW,
84
+ + result: AuthorizeResult.DENY,
85
+ };
86
+ }
87
+ ```
88
+
89
+ 3. start the application by running `yarn dev` from `workspaces/adoption-insights` directory.
90
+
91
+ ## Development
92
+
93
+ This plugin backend can be started in a standalone mode from directly in this
94
+ package with `yarn start`. It is a limited setup that is most convenient when
95
+ developing the plugin backend itself.
96
+
97
+ If you want to run the entire project, including the frontend, run `yarn dev` from the root directory.
98
+
99
+ # Events API
100
+
101
+ ## Endpoint
102
+
103
+ `GET /api/adoption-insights/events`
104
+
105
+ ## Query Parameters
106
+
107
+ | Parameter | Type | Required | Description |
108
+ | ------------ | ------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
109
+ | `type` | string | Yes | Filter events by type (e.g., `total_users`, `active_users`,`top_plugins`,`top_templates`,`top_techdocs`,`top_searches`,`top_catalog_entities`). |
110
+ | `start_date` | string (YYYY-MM-DD) | Yes | Fetch events starting from this date. |
111
+ | `end_date` | string (YYYY-MM-DD) | Yes | Fetch events up to this date. |
112
+ | `limit` | integer | No | Limit the number of events returned (default: `3`). |
113
+ | `kind` | string | No | Filter the entities by kind. |
114
+ | `grouping` | string | No | Group API endpoint `(active_users,top_plugins and top_searches)` response by `hourly`, `daily`, `weekly`, and `monthly`. |
115
+ | `format` | string | No | Response format, either `json` (default) or `csv`. |
116
+
117
+ ## Example Request
118
+
119
+ ```http
120
+ GET /api/adoption-insights/events?type=top_plugins&start_date=2025-03-01&end_date=2025-03-02&limit=3
121
+ ```
122
+
123
+ ## Example Response
124
+
125
+ <details> <summary>Click to expand</summary>
126
+
127
+ ```json
128
+ {
129
+ "grouping": "daily",
130
+ "data": [
131
+ {
132
+ "plugin_id": "catalog",
133
+ "visit_count": "27",
134
+ "trend": [
135
+ {
136
+ "date": "2025-03-01",
137
+ "count": 10
138
+ },
139
+ {
140
+ "date": "2025-03-02",
141
+ "count": 17
142
+ }
143
+ ],
144
+ "trend_percentage": "70.00"
145
+ },
146
+ {
147
+ "plugin_id": "root",
148
+ "visit_count": "15",
149
+ "trend": [
150
+ {
151
+ "date": "2025-03-01",
152
+ "count": 9
153
+ },
154
+ {
155
+ "date": "2025-03-02",
156
+ "count": 6
157
+ }
158
+ ],
159
+ "trend_percentage": "-33.33"
160
+ },
161
+ {
162
+ "plugin_id": "kubernetes",
163
+ "visit_count": "9",
164
+ "trend": [
165
+ {
166
+ "date": "2025-03-01",
167
+ "count": 4
168
+ },
169
+ {
170
+ "date": "2025-03-02",
171
+ "count": 5
172
+ }
173
+ ],
174
+ "trend_percentage": "25.00"
175
+ }
176
+ ]
177
+ }
178
+ ```
179
+
180
+ </details>
package/config.d.ts ADDED
@@ -0,0 +1,47 @@
1
+ /*
2
+ * Copyright Red Hat, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ export interface Config {
18
+ app?: {
19
+ analytics: {
20
+ adoptionInsights: {
21
+ /**
22
+ * Maximum buffer size for event batching.
23
+ * default 20
24
+ * @visibility frontend
25
+ */
26
+ maxBufferSize?: number;
27
+ /**
28
+ * Flush interval in millisecond for event batching. All events will be flushed after this interval.
29
+ * default 5000ms
30
+ * @visibility frontend
31
+ */
32
+ flushInterval?: number;
33
+ /**
34
+ * Flag to enable Debug mode which logs every event in the browser console.
35
+ * default false
36
+ * @visibility frontend
37
+ */
38
+ debug?: boolean;
39
+ /**
40
+ * Total number of licensed users.
41
+ * @visibility backend
42
+ */
43
+ licensedUsers?: number;
44
+ };
45
+ };
46
+ };
47
+ }
@@ -0,0 +1,122 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var json2Csv = require('json-2-csv');
6
+ var Event = require('../models/Event.cjs.js');
7
+ var date = require('../utils/date.cjs.js');
8
+ var event = require('../validation/event.cjs.js');
9
+ var eventRequest = require('../validation/event-request.cjs.js');
10
+ var ValidationError = require('../validation/ValidationError.cjs.js');
11
+ var config = require('../utils/config.cjs.js');
12
+
13
+ class EventApiController {
14
+ database;
15
+ config;
16
+ processor;
17
+ constructor(eventDatabase, processor, config) {
18
+ this.database = eventDatabase;
19
+ this.processor = processor;
20
+ this.config = config;
21
+ }
22
+ async getBaseUrl(pluginId) {
23
+ return `${this.config.getString("backend.baseUrl")}/api/${pluginId}`;
24
+ }
25
+ processIncomingEvents(events) {
26
+ const proccessedEvents = events.filter((e) => !!e.context?.userId).map((event) => new Event.Event(event, this.database.isJsonSupported()));
27
+ proccessedEvents.forEach((event$1) => {
28
+ const result = event.EventSchema.safeParse(event$1);
29
+ if (!result.success) {
30
+ throw new ValidationError.ValidationError("Invalid event data", result.error.flatten());
31
+ }
32
+ return this.processor.addEvent(event$1);
33
+ });
34
+ }
35
+ trackEvents(req, res) {
36
+ const events = req.body;
37
+ try {
38
+ this.processIncomingEvents(events);
39
+ res.status(200).json({ success: true, message: "Event received" });
40
+ } catch (error) {
41
+ res.status(400).json({ message: error.message, errors: error.details.fieldErrors });
42
+ }
43
+ }
44
+ // Get insights based on the type of data requested
45
+ async getInsights(req, res) {
46
+ const parsed = eventRequest.EventRequestSchema.safeParse(req.query);
47
+ if (!parsed.success) {
48
+ res.status(400).json({
49
+ message: "Invalid query",
50
+ errors: parsed.error.flatten().fieldErrors
51
+ });
52
+ return;
53
+ }
54
+ const { type, format, ...params } = parsed.data;
55
+ const licensedUsers = config.getLicensedUsersCount(this.config);
56
+ const filters = {
57
+ ...params,
58
+ end_date: date.toEndOfDayUTC(params.end_date),
59
+ start_date: date.toStartOfDayUTC(params.start_date)
60
+ };
61
+ const db = this.database;
62
+ db.setFilters(filters);
63
+ db.setConfig({ licensedUsers });
64
+ const queryHandlers = {
65
+ total_users: () => db.getUsers(),
66
+ active_users: () => db.getDailyUsers(),
67
+ top_searches: () => db.getTopSearches(),
68
+ top_plugins: () => db.getTopPluginViews(),
69
+ top_techdocs: () => db.getTopTechDocsViews(),
70
+ top_templates: () => db.getTopTemplateViews(),
71
+ top_catalog_entities: () => db.getTopCatalogEntitiesViews()
72
+ };
73
+ try {
74
+ const result = await queryHandlers[type]();
75
+ if (type === "top_techdocs") {
76
+ await this.getTechdocsMetadata(req, result);
77
+ }
78
+ if (format === "csv" && result.data) {
79
+ const csv = json2Csv.json2csv(result.data);
80
+ res.header("Content-Type", "text/csv");
81
+ res.attachment(`adoption_insights_${type}.csv`);
82
+ res.send(csv);
83
+ return;
84
+ }
85
+ res.json(result);
86
+ } catch (error) {
87
+ res.status(500).json({ error: "Internal Server Error" });
88
+ return;
89
+ }
90
+ }
91
+ async getTechdocsMetadata(req, result) {
92
+ const promises = [];
93
+ const baseUrl = await this.getBaseUrl("techdocs");
94
+ result.data.forEach((row) => {
95
+ if (!row.namespace || !row.kind || !row.name) {
96
+ row.site_name = "";
97
+ } else {
98
+ promises.push(
99
+ fetch(
100
+ `${baseUrl}/metadata/techdocs/${row.namespace}/${row.kind}/${row.name}`,
101
+ {
102
+ headers: {
103
+ Accept: "application/json",
104
+ Authorization: req.headers.authorization
105
+ }
106
+ }
107
+ ).then(async (response) => {
108
+ const data = await response.json();
109
+ row.site_name = data.site_name ?? row.name;
110
+ }).catch((e) => {
111
+ console.warn(e);
112
+ row.site_name = row.name;
113
+ })
114
+ );
115
+ }
116
+ });
117
+ await Promise.all(promises);
118
+ }
119
+ }
120
+
121
+ exports.default = EventApiController;
122
+ //# sourceMappingURL=EventApiController.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EventApiController.cjs.js","sources":["../../src/controllers/EventApiController.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Request, Response } from 'express';\nimport { json2csv as Parser } from 'json-2-csv';\nimport { Knex } from 'knex';\nimport { AnalyticsEvent } from '@backstage/core-plugin-api';\nimport { EventDatabase, Filters } from '../database/event-database';\nimport { EventBatchProcessor } from '../domain/EventBatchProcessor';\nimport { Event } from '../models/Event';\nimport { QueryParams, QueryType } from '../types/event-request';\nimport { toEndOfDayUTC, toStartOfDayUTC } from '../utils/date';\nimport { EventSchema } from '../validation/event';\nimport { EventRequestSchema } from '../validation/event-request';\nimport { ValidationError } from '../validation/ValidationError';\nimport { RootConfigService } from '@backstage/backend-plugin-api';\nimport { getLicensedUsersCount } from '../utils/config';\nimport { TechDocsCount, TopTechDocsCount } from '../types/event';\n\nclass EventApiController {\n private readonly database: EventDatabase;\n private readonly config: RootConfigService;\n private readonly processor: EventBatchProcessor;\n\n constructor(\n eventDatabase: EventDatabase,\n processor: EventBatchProcessor,\n config: RootConfigService,\n ) {\n this.database = eventDatabase;\n this.processor = processor;\n this.config = config;\n }\n\n async getBaseUrl(pluginId: string): Promise<string> {\n return `${this.config.getString('backend.baseUrl')}/api/${pluginId}`;\n }\n\n private processIncomingEvents(events: AnalyticsEvent[]): void {\n const proccessedEvents = events\n .filter(e => !!e.context?.userId)\n .map(event => new Event(event, this.database.isJsonSupported()));\n\n proccessedEvents.forEach(event => {\n const result = EventSchema.safeParse(event);\n\n if (!result.success) {\n throw new ValidationError('Invalid event data', result.error.flatten());\n }\n\n return this.processor.addEvent(event);\n });\n }\n\n trackEvents(req: Request<{}, {}, AnalyticsEvent[]>, res: Response): void {\n const events = req.body;\n\n try {\n this.processIncomingEvents(events);\n res.status(200).json({ success: true, message: 'Event received' });\n } catch (error) {\n res\n .status(400)\n .json({ message: error.message, errors: error.details.fieldErrors });\n }\n }\n\n // Get insights based on the type of data requested\n async getInsights(\n req: Request<{}, {}, {}, QueryParams>,\n res: Response,\n ): Promise<void> {\n const parsed = EventRequestSchema.safeParse(req.query);\n if (!parsed.success) {\n res.status(400).json({\n message: 'Invalid query',\n errors: parsed.error.flatten().fieldErrors,\n });\n return;\n }\n const { type, format, ...params } = parsed.data;\n const licensedUsers = getLicensedUsersCount(this.config);\n const filters: Filters = {\n ...params,\n end_date: toEndOfDayUTC(params.end_date) as string,\n start_date: toStartOfDayUTC(params.start_date) as string,\n };\n const db = this.database;\n\n db.setFilters(filters);\n db.setConfig({ licensedUsers });\n const queryHandlers: Record<QueryType, () => Promise<Knex.QueryBuilder>> = {\n total_users: () => db.getUsers(),\n active_users: () => db.getDailyUsers(),\n top_searches: () => db.getTopSearches(),\n top_plugins: () => db.getTopPluginViews(),\n top_techdocs: () => db.getTopTechDocsViews(),\n top_templates: () => db.getTopTemplateViews(),\n top_catalog_entities: () => db.getTopCatalogEntitiesViews(),\n };\n\n try {\n const result = await queryHandlers[type as QueryType]();\n\n if (type === 'top_techdocs') {\n await this.getTechdocsMetadata(req, result);\n }\n\n if (format === 'csv' && result.data) {\n const csv = Parser(result.data);\n res.header('Content-Type', 'text/csv');\n res.attachment(`adoption_insights_${type}.csv`);\n res.send(csv);\n return;\n }\n res.json(result);\n } catch (error) {\n res.status(500).json({ error: 'Internal Server Error' });\n return;\n }\n }\n\n async getTechdocsMetadata(\n req: Request<{}, {}, {}, QueryParams>,\n result: TopTechDocsCount,\n ) {\n const promises: Promise<void>[] = [];\n const baseUrl = await this.getBaseUrl('techdocs');\n\n result.data.forEach((row: TechDocsCount) => {\n if (!row.namespace || !row.kind || !row.name) {\n row.site_name = '';\n } else {\n promises.push(\n fetch(\n `${baseUrl}/metadata/techdocs/${row.namespace}/${row.kind}/${row.name}`,\n {\n headers: {\n Accept: 'application/json',\n Authorization: req.headers.authorization as string,\n },\n },\n )\n .then(async response => {\n const data = await response.json();\n row.site_name = data.site_name ?? row.name;\n })\n .catch(e => {\n console.warn(e);\n row.site_name = row.name;\n }),\n );\n }\n });\n\n await Promise.all(promises);\n }\n}\n\nexport default EventApiController;\n"],"names":["Event","event","EventSchema","ValidationError","EventRequestSchema","getLicensedUsersCount","toEndOfDayUTC","toStartOfDayUTC","Parser"],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ 'use strict';
2
+
3
+ var PostgresAdapter = require('./adapters/PostgresAdapter.cjs.js');
4
+ var SqliteAdapter = require('./adapters/SqliteAdapter.cjs.js');
5
+
6
+ class DatabaseFactory {
7
+ static getDatabase(db, logger) {
8
+ const dbType = db.client.config.client;
9
+ switch (dbType) {
10
+ case "pg":
11
+ return new PostgresAdapter.PostgresAdapter(db, logger);
12
+ case "better-sqlite3":
13
+ return new SqliteAdapter.SqliteAdapter(db, logger);
14
+ default:
15
+ throw new Error(`Unsupported database type: ${dbType}`);
16
+ }
17
+ }
18
+ }
19
+
20
+ exports.DatabaseFactory = DatabaseFactory;
21
+ //# sourceMappingURL=DatabaseFactory.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DatabaseFactory.cjs.js","sources":["../../src/database/DatabaseFactory.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Knex } from 'knex';\nimport { PostgresAdapter } from './adapters/PostgresAdapter';\nimport { EventDatabase } from './event-database';\nimport { SqliteAdapter } from './adapters/SqliteAdapter';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nexport class DatabaseFactory {\n static getDatabase(db: Knex, logger: LoggerService): EventDatabase {\n const dbType = db.client.config.client;\n\n switch (dbType) {\n case 'pg':\n return new PostgresAdapter(db, logger);\n case 'better-sqlite3':\n return new SqliteAdapter(db, logger);\n default:\n throw new Error(`Unsupported database type: ${dbType}`);\n }\n }\n}\n"],"names":["PostgresAdapter","SqliteAdapter"],"mappings":";;;;;AAqBO,MAAM,eAAgB,CAAA;AAAA,EAC3B,OAAO,WAAY,CAAA,EAAA,EAAU,MAAsC,EAAA;AACjE,IAAM,MAAA,MAAA,GAAS,EAAG,CAAA,MAAA,CAAO,MAAO,CAAA,MAAA;AAEhC,IAAA,QAAQ,MAAQ;AAAA,MACd,KAAK,IAAA;AACH,QAAO,OAAA,IAAIA,+BAAgB,CAAA,EAAA,EAAI,MAAM,CAAA;AAAA,MACvC,KAAK,gBAAA;AACH,QAAO,OAAA,IAAIC,2BAAc,CAAA,EAAA,EAAI,MAAM,CAAA;AAAA,MACrC;AACE,QAAA,MAAM,IAAI,KAAA,CAAM,CAA8B,2BAAA,EAAA,MAAM,CAAE,CAAA,CAAA;AAAA;AAC1D;AAEJ;;;;"}