@kopai/app 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -58,7 +58,7 @@ if (values.help || command === "help" || !command) {
58
58
  showHelp();
59
59
  process.exit(0);
60
60
  }
61
- if (command === "start") Promise.resolve().then(() => require("./server-C0Z3uYgw.cjs"));
61
+ if (command === "start") Promise.resolve().then(() => require("./server-0ZM-SoLL.cjs"));
62
62
  else {
63
63
  console.error(`Unknown command: ${command}`);
64
64
  showHelp();
package/dist/cli.mjs CHANGED
@@ -56,7 +56,7 @@ if (values.help || command === "help" || !command) {
56
56
  showHelp();
57
57
  process.exit(0);
58
58
  }
59
- if (command === "start") import("./server-DOf6Bn7W.mjs");
59
+ if (command === "start") import("./server-Cr4zeULt.mjs");
60
60
  else {
61
61
  console.error(`Unknown command: ${command}`);
62
62
  showHelp();
@@ -87,6 +87,9 @@ function printStartupBanner({ host, port, collectorPort, version }) {
87
87
  //#endregion
88
88
  //#region src/server.ts
89
89
  const __dirname$1 = (0, node_path.dirname)((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
90
+ function hasComponentSchemas(doc) {
91
+ return typeof doc === "object" && doc !== null && "components" in doc && typeof doc.components === "object" && doc.components !== null && "schemas" in doc.components && typeof doc.components.schemas === "object" && doc.components.schemas !== null;
92
+ }
90
93
  const apiServer = (0, fastify.default)({ logger: { level: "warn" } });
91
94
  apiServer.setValidatorCompiler(fastify_type_provider_zod.validatorCompiler);
92
95
  apiServer.setSerializerCompiler(fastify_type_provider_zod.serializerCompiler);
@@ -111,7 +114,25 @@ apiServer.register(_fastify_swagger.default, {
111
114
  ...rest
112
115
  });
113
116
  },
114
- transformObject: fastify_type_provider_zod.jsonSchemaTransformObject
117
+ transformObject: (input) => {
118
+ const result = (0, fastify_type_provider_zod.jsonSchemaTransformObject)(input);
119
+ const renamed = JSON.stringify(result).replaceAll("#/components/schemas/schema0", "#/components/schemas/AttributeValue");
120
+ const patched = JSON.parse(renamed);
121
+ if (hasComponentSchemas(patched) && !patched.components.schemas.AttributeValue) patched.components.schemas.AttributeValue = { anyOf: [
122
+ { type: "string" },
123
+ { type: "number" },
124
+ { type: "boolean" },
125
+ {
126
+ type: "array",
127
+ items: { $ref: "#/components/schemas/AttributeValue" }
128
+ },
129
+ {
130
+ type: "object",
131
+ additionalProperties: { $ref: "#/components/schemas/AttributeValue" }
132
+ }
133
+ ] };
134
+ return patched;
135
+ }
115
136
  });
116
137
  apiServer.register(_fastify_swagger_ui.default, {
117
138
  routePrefix: "/documentation",
@@ -82,6 +82,9 @@ function printStartupBanner({ host, port, collectorPort, version }) {
82
82
  //#endregion
83
83
  //#region src/server.ts
84
84
  const __dirname = dirname(fileURLToPath(import.meta.url));
85
+ function hasComponentSchemas(doc) {
86
+ return typeof doc === "object" && doc !== null && "components" in doc && typeof doc.components === "object" && doc.components !== null && "schemas" in doc.components && typeof doc.components.schemas === "object" && doc.components.schemas !== null;
87
+ }
85
88
  const apiServer = fastify({ logger: { level: "warn" } });
86
89
  apiServer.setValidatorCompiler(validatorCompiler);
87
90
  apiServer.setSerializerCompiler(serializerCompiler);
@@ -106,7 +109,25 @@ apiServer.register(fastifySwagger, {
106
109
  ...rest
107
110
  });
108
111
  },
109
- transformObject: jsonSchemaTransformObject
112
+ transformObject: (input) => {
113
+ const result = jsonSchemaTransformObject(input);
114
+ const renamed = JSON.stringify(result).replaceAll("#/components/schemas/schema0", "#/components/schemas/AttributeValue");
115
+ const patched = JSON.parse(renamed);
116
+ if (hasComponentSchemas(patched) && !patched.components.schemas.AttributeValue) patched.components.schemas.AttributeValue = { anyOf: [
117
+ { type: "string" },
118
+ { type: "number" },
119
+ { type: "boolean" },
120
+ {
121
+ type: "array",
122
+ items: { $ref: "#/components/schemas/AttributeValue" }
123
+ },
124
+ {
125
+ type: "object",
126
+ additionalProperties: { $ref: "#/components/schemas/AttributeValue" }
127
+ }
128
+ ] };
129
+ return patched;
130
+ }
110
131
  });
111
132
  apiServer.register(fastifySwaggerUI, {
112
133
  routePrefix: "/documentation",
@@ -188,4 +209,4 @@ closeWithGrace(async ({ signal, err }) => {
188
209
 
189
210
  //#endregion
190
211
  export { };
191
- //# sourceMappingURL=server-DOf6Bn7W.mjs.map
212
+ //# sourceMappingURL=server-Cr4zeULt.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-Cr4zeULt.mjs","names":[],"sources":["../src/routes/index.ts","../src/collector/index.ts","../src/startup-banner.ts","../src/server.ts"],"sourcesContent":["import type { FastifyPluginAsyncZod } from \"fastify-type-provider-zod\";\nimport { signalsRoutes } from \"@kopai/api\";\nimport { type datasource } from \"@kopai/core\";\n\nexport const apiRoutes: FastifyPluginAsyncZod<{\n readTelemetryDatasource: datasource.ReadTelemetryDatasource;\n}> = async function (fastify, opts) {\n fastify.register(signalsRoutes, {\n readTelemetryDatasource: opts.readTelemetryDatasource,\n });\n};\n","import type { FastifyPluginAsyncZod } from \"fastify-type-provider-zod\";\nimport { collectorRoutes } from \"@kopai/collector\";\nimport type { datasource } from \"@kopai/core\";\n\nexport const otelCollectorRoutes: FastifyPluginAsyncZod<{\n telemetryDatasource: datasource.WriteTelemetryDatasource;\n}> = async function (fastify, opts) {\n fastify.register(collectorRoutes, opts);\n};\n","import { networkInterfaces } from \"node:os\";\n\nconst isTTY = process.stdout.isTTY;\nconst bold = isTTY ? \"\\x1b[1m\" : \"\";\nconst dim = isTTY ? \"\\x1b[2m\" : \"\";\nconst green = isTTY ? \"\\x1b[32m\" : \"\";\nconst cyan = isTTY ? \"\\x1b[36m\" : \"\";\nconst reset = isTTY ? \"\\x1b[0m\" : \"\";\n\nfunction getNetworkAddress(): string | undefined {\n const nets = networkInterfaces();\n for (const interfaces of Object.values(nets)) {\n if (!interfaces) continue;\n for (const net of interfaces) {\n if (net.family === \"IPv4\" && !net.internal) {\n return net.address;\n }\n }\n }\n return undefined;\n}\n\nexport function printStartupBanner({\n host,\n port,\n collectorPort,\n version,\n}: {\n host: string;\n port: number;\n collectorPort: number;\n version: string;\n}) {\n const localHost = host === \"0.0.0.0\" || host === \"::\" ? \"localhost\" : host;\n const networkAddress = getNetworkAddress();\n\n const lines: string[] = [\n \"\",\n ` ${bold}${green}|--k> @kopai/app${reset} ${dim}v${version}${reset}`,\n \"\",\n ];\n\n const rows: [string, string, string][] = [\n [\"Dashboard\", `http://${localHost}:${port}`, \"\"],\n [\"API Docs\", `http://${localHost}:${port}/documentation`, \"/documentation\"],\n [\"Collector\", `http://${localHost}:${collectorPort}`, \"\"],\n ];\n\n const maxLocalLen = Math.max(...rows.map(([, url]) => url.length));\n\n for (const [label, localUrl, path] of rows) {\n const padded = localUrl.padEnd(maxLocalLen);\n let line = ` ${green}▸${reset} ${bold}${label.padEnd(16)}${reset}${cyan}${padded}${reset}`;\n if (networkAddress) {\n const netPort = label === \"Collector\" ? collectorPort : port;\n const netUrl = `http://${networkAddress}:${netPort}${path}`;\n line += ` ${dim}${cyan}${netUrl}${reset}`;\n }\n lines.push(line);\n }\n\n lines.push(\"\");\n console.log(lines.join(\"\\n\"));\n}\n","import fastify from \"fastify\";\nimport {\n jsonSchemaTransformObject,\n jsonSchemaTransform,\n serializerCompiler,\n validatorCompiler,\n} from \"fastify-type-provider-zod\";\nimport fastifySwagger from \"@fastify/swagger\";\nimport fastifySwaggerUI from \"@fastify/swagger-ui\";\nimport closeWithGrace from \"close-with-grace\";\n\nimport { env } from \"./config.js\";\nimport { version } from \"./version.js\";\nimport { apiRoutes } from \"./routes/index.js\";\nimport { otelCollectorRoutes } from \"./collector/index.js\";\nimport {\n initializeDatabase,\n createOptimizedDatasource,\n} from \"@kopai/sqlite-datasource\";\nimport { resolve, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport FastifyVite from \"@fastify/vite\";\nimport { printStartupBanner } from \"./startup-banner.js\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nfunction hasComponentSchemas(\n doc: unknown\n): doc is { components: { schemas: Record<string, object> } } {\n return (\n typeof doc === \"object\" &&\n doc !== null &&\n \"components\" in doc &&\n typeof doc.components === \"object\" &&\n doc.components !== null &&\n \"schemas\" in doc.components &&\n typeof doc.components.schemas === \"object\" &&\n doc.components.schemas !== null\n );\n}\n\nconst apiServer = fastify({\n logger: { level: \"warn\" },\n});\n\n// Add schema validator and serializer\napiServer.setValidatorCompiler(validatorCompiler);\napiServer.setSerializerCompiler(serializerCompiler);\n\nconst uiRoutes = [\"/\", \"/*\"];\napiServer.register(fastifySwagger, {\n openapi: {\n info: {\n title: \"Kopai App\",\n description: \"Kopai App documentation\",\n version,\n },\n servers: [],\n },\n transform: ({ schema, url, ...rest }) => {\n if (uiRoutes.includes(url)) return { schema: { hide: true }, url };\n return jsonSchemaTransform({ schema, url, ...rest });\n },\n transformObject: (input) => {\n const result = jsonSchemaTransformObject(input);\n // Fix: z.lazy() recursive schemas generate $ref to schema0\n // but fastify-type-provider-zod doesn't define it in components.\n // Inject the missing schema definition and rename schema0 → AttributeValue.\n const raw = JSON.stringify(result);\n const renamed = raw.replaceAll(\n \"#/components/schemas/schema0\",\n \"#/components/schemas/AttributeValue\"\n );\n const patched: unknown = JSON.parse(renamed);\n if (\n hasComponentSchemas(patched) &&\n !patched.components.schemas.AttributeValue\n ) {\n patched.components.schemas.AttributeValue = {\n anyOf: [\n { type: \"string\" },\n { type: \"number\" },\n { type: \"boolean\" },\n {\n type: \"array\",\n items: { $ref: \"#/components/schemas/AttributeValue\" },\n },\n {\n type: \"object\",\n additionalProperties: {\n $ref: \"#/components/schemas/AttributeValue\",\n },\n },\n ],\n };\n }\n return patched as ReturnType<typeof jsonSchemaTransformObject>;\n },\n});\n\napiServer.register(fastifySwaggerUI, {\n routePrefix: \"/documentation\",\n logo: {\n type: \"image/svg+xml\",\n content: Buffer.from(\n \"PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNjAgNDAiIGZpbGw9Im5vbmUiPjx0ZXh0IHg9IjAiIHk9IjI4IiBmb250LWZhbWlseT0idWktbW9ub3NwYWNlLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjAiIGZvbnQtd2VpZ2h0PSI0MDAiIGZpbGw9IiNmYWZhZmEiPnwtLWsmZ3Q7IGtvcGFpPC90ZXh0Pjwvc3ZnPg==\",\n \"base64\"\n ),\n href: \"/documentation\",\n target: \"_blank\",\n },\n theme: {\n favicon: [\n {\n filename: \"favicon.svg\",\n rel: \"icon\",\n sizes: \"32x32\",\n type: \"image/svg+xml\",\n content: Buffer.from(\n \"PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMiAzMiIgZmlsbD0ibm9uZSI+PHJlY3Qgd2lkdGg9IjMyIiBoZWlnaHQ9IjMyIiByeD0iNCIgZmlsbD0iIzBhMGEwYSIvPjx0ZXh0IHg9IjMiIHk9IjIyIiBmb250LWZhbWlseT0idWktbW9ub3NwYWNlLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTYiIGZvbnQtd2VpZ2h0PSI0MDAiIGZpbGw9IiNmYWZhZmEiPmsmZ3Q7PC90ZXh0Pjwvc3ZnPg==\",\n \"base64\"\n ),\n },\n ],\n },\n});\n\nconst sqliteDatabase = initializeDatabase(env.SQLITE_DB_FILE_PATH);\nconst telemetryDatasource = createOptimizedDatasource(sqliteDatabase);\n\napiServer.after(() => {\n apiServer.register(apiRoutes, {\n readTelemetryDatasource: telemetryDatasource,\n });\n apiServer.register(async (fastify) => {\n await fastify.register(FastifyVite, {\n root: resolve(__dirname, \"..\"),\n distDir: \"dist\",\n dev: false,\n spa: true,\n });\n fastify.get(\"/\", (_req, reply) => reply.html());\n fastify.get(\"/*\", (_req, reply) => reply.html());\n await fastify.vite.ready();\n });\n});\n\nconst collectorServer = fastify({\n logger: { level: \"warn\" },\n});\n\ncollectorServer.setValidatorCompiler(validatorCompiler);\ncollectorServer.setSerializerCompiler(serializerCompiler);\n\ncollectorServer.after(() => {\n collectorServer.register(otelCollectorRoutes, {\n telemetryDatasource,\n });\n});\n\nasync function run() {\n await apiServer.ready();\n await collectorServer.ready();\n\n const host = env.HOST || \"localhost\";\n const port = env.PORT;\n const collectorPort = 4318;\n\n await apiServer.listen({ port, host });\n await collectorServer.listen({ port: collectorPort, host });\n\n printStartupBanner({ host, port, collectorPort, version });\n\n apiServer.log.level = \"info\";\n collectorServer.log.level = \"info\";\n}\n\nrun().catch((err) => {\n console.error(err);\n process.exit(1);\n});\n\ncloseWithGrace(async ({ signal, err }) => {\n if (err) {\n collectorServer.log.fatal(\n { err },\n \"Closing OTEL collector server with error\"\n );\n apiServer.log.fatal({ err }, \"Closing API server with error\");\n } else {\n collectorServer.log.info(\n `Received signal ${signal}, closing OTEL collector server`\n );\n apiServer.log.info(`Received signal ${signal}, closing API server`);\n }\n\n await collectorServer.close();\n sqliteDatabase?.close();\n await apiServer.close();\n});\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kopai/app",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "Local OpenTelemetry backend for testing instrumentation - no Docker, no config, just npx",
5
5
  "keywords": [
6
6
  "opentelemetry",
@@ -56,8 +56,8 @@
56
56
  "zod": "^4.3.6",
57
57
  "@kopai/api": "0.2.3",
58
58
  "@kopai/collector": "0.5.0",
59
- "@kopai/core": "0.5.0",
60
59
  "@kopai/sqlite-datasource": "0.6.0",
60
+ "@kopai/core": "0.5.0",
61
61
  "@kopai/ui": "0.3.0"
62
62
  },
63
63
  "devDependencies": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"server-DOf6Bn7W.mjs","names":[],"sources":["../src/routes/index.ts","../src/collector/index.ts","../src/startup-banner.ts","../src/server.ts"],"sourcesContent":["import type { FastifyPluginAsyncZod } from \"fastify-type-provider-zod\";\nimport { signalsRoutes } from \"@kopai/api\";\nimport { type datasource } from \"@kopai/core\";\n\nexport const apiRoutes: FastifyPluginAsyncZod<{\n readTelemetryDatasource: datasource.ReadTelemetryDatasource;\n}> = async function (fastify, opts) {\n fastify.register(signalsRoutes, {\n readTelemetryDatasource: opts.readTelemetryDatasource,\n });\n};\n","import type { FastifyPluginAsyncZod } from \"fastify-type-provider-zod\";\nimport { collectorRoutes } from \"@kopai/collector\";\nimport type { datasource } from \"@kopai/core\";\n\nexport const otelCollectorRoutes: FastifyPluginAsyncZod<{\n telemetryDatasource: datasource.WriteTelemetryDatasource;\n}> = async function (fastify, opts) {\n fastify.register(collectorRoutes, opts);\n};\n","import { networkInterfaces } from \"node:os\";\n\nconst isTTY = process.stdout.isTTY;\nconst bold = isTTY ? \"\\x1b[1m\" : \"\";\nconst dim = isTTY ? \"\\x1b[2m\" : \"\";\nconst green = isTTY ? \"\\x1b[32m\" : \"\";\nconst cyan = isTTY ? \"\\x1b[36m\" : \"\";\nconst reset = isTTY ? \"\\x1b[0m\" : \"\";\n\nfunction getNetworkAddress(): string | undefined {\n const nets = networkInterfaces();\n for (const interfaces of Object.values(nets)) {\n if (!interfaces) continue;\n for (const net of interfaces) {\n if (net.family === \"IPv4\" && !net.internal) {\n return net.address;\n }\n }\n }\n return undefined;\n}\n\nexport function printStartupBanner({\n host,\n port,\n collectorPort,\n version,\n}: {\n host: string;\n port: number;\n collectorPort: number;\n version: string;\n}) {\n const localHost = host === \"0.0.0.0\" || host === \"::\" ? \"localhost\" : host;\n const networkAddress = getNetworkAddress();\n\n const lines: string[] = [\n \"\",\n ` ${bold}${green}|--k> @kopai/app${reset} ${dim}v${version}${reset}`,\n \"\",\n ];\n\n const rows: [string, string, string][] = [\n [\"Dashboard\", `http://${localHost}:${port}`, \"\"],\n [\"API Docs\", `http://${localHost}:${port}/documentation`, \"/documentation\"],\n [\"Collector\", `http://${localHost}:${collectorPort}`, \"\"],\n ];\n\n const maxLocalLen = Math.max(...rows.map(([, url]) => url.length));\n\n for (const [label, localUrl, path] of rows) {\n const padded = localUrl.padEnd(maxLocalLen);\n let line = ` ${green}▸${reset} ${bold}${label.padEnd(16)}${reset}${cyan}${padded}${reset}`;\n if (networkAddress) {\n const netPort = label === \"Collector\" ? collectorPort : port;\n const netUrl = `http://${networkAddress}:${netPort}${path}`;\n line += ` ${dim}${cyan}${netUrl}${reset}`;\n }\n lines.push(line);\n }\n\n lines.push(\"\");\n console.log(lines.join(\"\\n\"));\n}\n","import fastify from \"fastify\";\nimport {\n jsonSchemaTransformObject,\n jsonSchemaTransform,\n serializerCompiler,\n validatorCompiler,\n} from \"fastify-type-provider-zod\";\nimport fastifySwagger from \"@fastify/swagger\";\nimport fastifySwaggerUI from \"@fastify/swagger-ui\";\nimport closeWithGrace from \"close-with-grace\";\n\nimport { env } from \"./config.js\";\nimport { version } from \"./version.js\";\nimport { apiRoutes } from \"./routes/index.js\";\nimport { otelCollectorRoutes } from \"./collector/index.js\";\nimport {\n initializeDatabase,\n createOptimizedDatasource,\n} from \"@kopai/sqlite-datasource\";\nimport { resolve, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport FastifyVite from \"@fastify/vite\";\nimport { printStartupBanner } from \"./startup-banner.js\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nconst apiServer = fastify({\n logger: { level: \"warn\" },\n});\n\n// Add schema validator and serializer\napiServer.setValidatorCompiler(validatorCompiler);\napiServer.setSerializerCompiler(serializerCompiler);\n\nconst uiRoutes = [\"/\", \"/*\"];\napiServer.register(fastifySwagger, {\n openapi: {\n info: {\n title: \"Kopai App\",\n description: \"Kopai App documentation\",\n version,\n },\n servers: [],\n },\n transform: ({ schema, url, ...rest }) => {\n if (uiRoutes.includes(url)) return { schema: { hide: true }, url };\n return jsonSchemaTransform({ schema, url, ...rest });\n },\n transformObject: jsonSchemaTransformObject,\n});\n\napiServer.register(fastifySwaggerUI, {\n routePrefix: \"/documentation\",\n logo: {\n type: \"image/svg+xml\",\n content: Buffer.from(\n \"PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNjAgNDAiIGZpbGw9Im5vbmUiPjx0ZXh0IHg9IjAiIHk9IjI4IiBmb250LWZhbWlseT0idWktbW9ub3NwYWNlLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjAiIGZvbnQtd2VpZ2h0PSI0MDAiIGZpbGw9IiNmYWZhZmEiPnwtLWsmZ3Q7IGtvcGFpPC90ZXh0Pjwvc3ZnPg==\",\n \"base64\"\n ),\n href: \"/documentation\",\n target: \"_blank\",\n },\n theme: {\n favicon: [\n {\n filename: \"favicon.svg\",\n rel: \"icon\",\n sizes: \"32x32\",\n type: \"image/svg+xml\",\n content: Buffer.from(\n \"PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMiAzMiIgZmlsbD0ibm9uZSI+PHJlY3Qgd2lkdGg9IjMyIiBoZWlnaHQ9IjMyIiByeD0iNCIgZmlsbD0iIzBhMGEwYSIvPjx0ZXh0IHg9IjMiIHk9IjIyIiBmb250LWZhbWlseT0idWktbW9ub3NwYWNlLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTYiIGZvbnQtd2VpZ2h0PSI0MDAiIGZpbGw9IiNmYWZhZmEiPmsmZ3Q7PC90ZXh0Pjwvc3ZnPg==\",\n \"base64\"\n ),\n },\n ],\n },\n});\n\nconst sqliteDatabase = initializeDatabase(env.SQLITE_DB_FILE_PATH);\nconst telemetryDatasource = createOptimizedDatasource(sqliteDatabase);\n\napiServer.after(() => {\n apiServer.register(apiRoutes, {\n readTelemetryDatasource: telemetryDatasource,\n });\n apiServer.register(async (fastify) => {\n await fastify.register(FastifyVite, {\n root: resolve(__dirname, \"..\"),\n distDir: \"dist\",\n dev: false,\n spa: true,\n });\n fastify.get(\"/\", (_req, reply) => reply.html());\n fastify.get(\"/*\", (_req, reply) => reply.html());\n await fastify.vite.ready();\n });\n});\n\nconst collectorServer = fastify({\n logger: { level: \"warn\" },\n});\n\ncollectorServer.setValidatorCompiler(validatorCompiler);\ncollectorServer.setSerializerCompiler(serializerCompiler);\n\ncollectorServer.after(() => {\n collectorServer.register(otelCollectorRoutes, {\n telemetryDatasource,\n });\n});\n\nasync function run() {\n await apiServer.ready();\n await collectorServer.ready();\n\n const host = env.HOST || \"localhost\";\n const port = env.PORT;\n const collectorPort = 4318;\n\n await apiServer.listen({ port, host });\n await collectorServer.listen({ port: collectorPort, host });\n\n printStartupBanner({ host, port, collectorPort, version });\n\n apiServer.log.level = \"info\";\n collectorServer.log.level = \"info\";\n}\n\nrun().catch((err) => {\n console.error(err);\n process.exit(1);\n});\n\ncloseWithGrace(async ({ signal, err }) => {\n if (err) {\n collectorServer.log.fatal(\n { err },\n \"Closing OTEL collector server with error\"\n );\n apiServer.log.fatal({ err }, \"Closing API server with error\");\n } else {\n collectorServer.log.info(\n `Received signal ${signal}, closing OTEL collector server`\n );\n apiServer.log.info(`Received signal ${signal}, closing API server`);\n }\n\n await collectorServer.close();\n sqliteDatabase?.close();\n await apiServer.close();\n});\n"],"mappings":"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"}