@kopai/api 0.2.3 → 0.4.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/index.cjs CHANGED
@@ -1,4 +1,5 @@
1
- //#region rolldown:runtime
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ //#region \0rolldown/runtime.js
2
3
  var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
4
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -33,12 +34,15 @@ let zod = require("zod");
33
34
  zod = __toESM(zod);
34
35
 
35
36
  //#region src/routes/errors.ts
36
- var SignalsApiError = class extends Error {
37
+ var ApiError = class extends Error {
37
38
  constructor(message, options) {
38
39
  super(message, options);
39
40
  Object.setPrototypeOf(this, new.target.prototype);
40
41
  }
41
42
  };
43
+ var DashboardNotFoundError = class extends ApiError {
44
+ code = "DASHBOARD_NOT_FOUND";
45
+ };
42
46
 
43
47
  //#endregion
44
48
  //#region src/routes/error-handler.ts
@@ -49,8 +53,17 @@ function errorHandler(error, request, reply) {
49
53
  title: "Invalid data",
50
54
  detail: error.message
51
55
  });
56
+ if (error instanceof DashboardNotFoundError) {
57
+ request.log.info(error.message);
58
+ return reply.status(404).send({
59
+ type: "https://docs.kopai.app/errors/dashboard-not-found",
60
+ status: 404,
61
+ title: "Dashboard not found",
62
+ detail: error.message
63
+ });
64
+ }
52
65
  request.log.error(error);
53
- if (error instanceof SignalsApiError) return reply.status(500).send({
66
+ if (error instanceof ApiError) return reply.status(500).send({
54
67
  type: "https://docs.kopai.app/errors/signals-api-internal-error",
55
68
  status: 500,
56
69
  title: "Internal server error",
@@ -95,7 +108,10 @@ const tracesRoutes = async function(fastify, opts) {
95
108
  }
96
109
  },
97
110
  handler: async (req, res) => {
98
- const result = await opts.readTracesDatasource.getTraces({ traceId: req.params.traceId });
111
+ const result = await opts.readTracesDatasource.getTraces({
112
+ traceId: req.params.traceId,
113
+ requestContext: req.requestContext
114
+ });
99
115
  res.send(result.data);
100
116
  }
101
117
  });
@@ -116,7 +132,10 @@ const tracesRoutes = async function(fastify, opts) {
116
132
  }
117
133
  },
118
134
  handler: async (req, res) => {
119
- const result = await opts.readTracesDatasource.getTraces(req.body);
135
+ const result = await opts.readTracesDatasource.getTraces({
136
+ ...req.body,
137
+ requestContext: req.requestContext
138
+ });
120
139
  res.send(result);
121
140
  }
122
141
  });
@@ -142,7 +161,10 @@ const logsRoutes = async function(fastify, opts) {
142
161
  }
143
162
  },
144
163
  handler: async (req, res) => {
145
- const result = await opts.readLogsDatasource.getLogs(req.body);
164
+ const result = await opts.readLogsDatasource.getLogs({
165
+ ...req.body,
166
+ requestContext: req.requestContext
167
+ });
146
168
  res.send(result);
147
169
  }
148
170
  });
@@ -168,7 +190,10 @@ const metricsRoutes = async function(fastify, opts) {
168
190
  }
169
191
  },
170
192
  handler: async (req, res) => {
171
- const result = await opts.readMetricsDatasource.getMetrics(req.body);
193
+ const result = await opts.readMetricsDatasource.getMetrics({
194
+ ...req.body,
195
+ requestContext: req.requestContext
196
+ });
172
197
  res.send(result);
173
198
  }
174
199
  });
@@ -183,8 +208,8 @@ const metricsRoutes = async function(fastify, opts) {
183
208
  "5xx": problemDetailsSchema
184
209
  }
185
210
  },
186
- handler: async (_req, res) => {
187
- const result = await opts.readMetricsDatasource.discoverMetrics();
211
+ handler: async (req, res) => {
212
+ const result = await opts.readMetricsDatasource.discoverMetrics({ requestContext: req.requestContext });
188
213
  res.send(result);
189
214
  }
190
215
  });
@@ -210,6 +235,102 @@ const discoveredMetricSchema = zod_v4.z.object({
210
235
  });
211
236
  const metricsDiscoveryResponseSchema = zod_v4.z.object({ metrics: zod_v4.z.array(discoveredMetricSchema) });
212
237
 
238
+ //#endregion
239
+ //#region src/routes/dashboards.ts
240
+ const dashboardsRoutes$1 = async function(fastify, opts) {
241
+ fastify.route({
242
+ method: "GET",
243
+ url: "/dashboards/schema",
244
+ schema: {
245
+ description: "Get UI tree schema as markdown prompt instructions for AI agents",
246
+ produces: ["text/markdown"],
247
+ response: {
248
+ 200: {
249
+ type: "string",
250
+ description: "Markdown prompt instructions"
251
+ },
252
+ 404: {
253
+ type: "string",
254
+ description: "Prompt instructions not configured"
255
+ }
256
+ }
257
+ },
258
+ handler: async (_req, reply) => {
259
+ if (!opts.promptInstructions) return reply.status(404).send("Dashboard schema not configured");
260
+ reply.type("text/markdown").send(opts.promptInstructions);
261
+ }
262
+ });
263
+ fastify.route({
264
+ method: "POST",
265
+ url: "/dashboards",
266
+ schema: {
267
+ description: "Create a dashboard containing a uiTree",
268
+ body: _kopai_core.dashboardDatasource.createDashboardParams,
269
+ response: {
270
+ 201: _kopai_core.dashboardDatasource.dashboardSchema,
271
+ "4xx": problemDetailsSchema,
272
+ "5xx": problemDetailsSchema
273
+ }
274
+ },
275
+ handler: async (req, res) => {
276
+ const result = await opts.dynamicDashboardDatasource.createDashboard({
277
+ ...req.body,
278
+ requestContext: req.requestContext
279
+ });
280
+ res.status(201).send(result);
281
+ }
282
+ });
283
+ fastify.route({
284
+ method: "GET",
285
+ url: "/dashboards/:dashboardId",
286
+ schema: {
287
+ description: "Get a dashboard containing a uiTree to be rendered",
288
+ params: zod_v4.z.object({ dashboardId: zod_v4.z.string() }),
289
+ response: {
290
+ 200: _kopai_core.dashboardDatasource.dashboardSchema,
291
+ "4xx": problemDetailsSchema,
292
+ "5xx": problemDetailsSchema
293
+ }
294
+ },
295
+ handler: async (req, res) => {
296
+ try {
297
+ const result = await opts.dynamicDashboardDatasource.getDashboard({
298
+ id: req.params.dashboardId,
299
+ requestContext: req.requestContext
300
+ });
301
+ res.send(result);
302
+ } catch (error) {
303
+ if ((error instanceof Error ? error.message.toLowerCase() : "").includes("not found")) throw new DashboardNotFoundError(`Dashboard not found: ${req.params.dashboardId}`, { cause: error });
304
+ throw error;
305
+ }
306
+ }
307
+ });
308
+ const searchResponseSchema = zod_v4.z.object({
309
+ data: zod_v4.z.array(_kopai_core.dashboardDatasource.dashboardSchema),
310
+ nextCursor: zod_v4.z.string().nullable()
311
+ });
312
+ fastify.route({
313
+ method: "POST",
314
+ url: "/dashboards/search",
315
+ schema: {
316
+ description: "Search dashboards matching a filter",
317
+ body: _kopai_core.dashboardDatasource.searchDashboardsFilter,
318
+ response: {
319
+ 200: searchResponseSchema,
320
+ "4xx": problemDetailsSchema,
321
+ "5xx": problemDetailsSchema
322
+ }
323
+ },
324
+ handler: async (req, res) => {
325
+ const result = await opts.dynamicDashboardDatasource.searchDashboards({
326
+ ...req.body,
327
+ requestContext: req.requestContext
328
+ });
329
+ res.send(result);
330
+ }
331
+ });
332
+ };
333
+
213
334
  //#endregion
214
335
  //#region src/index.ts
215
336
  const signalsRoutes = async function(fastify, opts) {
@@ -220,6 +341,16 @@ const signalsRoutes = async function(fastify, opts) {
220
341
  fastify.register(logsRoutes, { readLogsDatasource: opts.readTelemetryDatasource });
221
342
  fastify.register(metricsRoutes, { readMetricsDatasource: opts.readTelemetryDatasource });
222
343
  };
344
+ const dashboardsRoutes = async function(fastify, opts) {
345
+ fastify.setValidatorCompiler(fastify_type_provider_zod.validatorCompiler);
346
+ fastify.setSerializerCompiler(fastify_type_provider_zod.serializerCompiler);
347
+ fastify.setErrorHandler(errorHandler);
348
+ fastify.register(dashboardsRoutes$1, {
349
+ dynamicDashboardDatasource: opts.dynamicDashboardDatasource,
350
+ promptInstructions: opts.promptInstructions
351
+ });
352
+ };
223
353
 
224
354
  //#endregion
355
+ exports.dashboardsRoutes = dashboardsRoutes;
225
356
  exports.signalsRoutes = signalsRoutes;
package/dist/index.d.cts CHANGED
@@ -1,10 +1,19 @@
1
1
  import { FastifyPluginAsyncZod } from "fastify-type-provider-zod";
2
- import { datasource } from "@kopai/core";
2
+ import { dashboardDatasource, datasource } from "@kopai/core";
3
3
 
4
4
  //#region src/index.d.ts
5
5
  declare const signalsRoutes: FastifyPluginAsyncZod<{
6
6
  readTelemetryDatasource: datasource.ReadTelemetryDatasource;
7
7
  }>;
8
+ declare const dashboardsRoutes: FastifyPluginAsyncZod<{
9
+ dynamicDashboardDatasource: dashboardDatasource.DynamicDashboardDatasource;
10
+ promptInstructions?: string;
11
+ }>;
12
+ declare module "fastify" {
13
+ interface FastifyRequest {
14
+ requestContext?: unknown;
15
+ }
16
+ } //# sourceMappingURL=index.d.ts.map
8
17
  //#endregion
9
- export { signalsRoutes };
18
+ export { dashboardsRoutes, signalsRoutes };
10
19
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;;cAWa,aAAA,EAAe,qBAAA;EAC1B,uBAAA,EAAyB,UAAA,CAAW,uBAAA;AAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;;cAaa,aAAA,EAAe,qBAAA;EAC1B,uBAAA,EAAyB,UAAA,CAAW,uBAAA;AAAA;AAAA,cAmBzB,gBAAA,EAAkB,qBAAA;EAC7B,0BAAA,EAA4B,mBAAA,CAAoB,0BAAA;EAChD,kBAAA;AAAA;AAAA;EAAA,UAaU,cAAA;IACR,cAAA;EAAA;AAAA"}
package/dist/index.d.mts CHANGED
@@ -1,10 +1,19 @@
1
- import { datasource } from "@kopai/core";
1
+ import { dashboardDatasource, datasource } from "@kopai/core";
2
2
  import { FastifyPluginAsyncZod } from "fastify-type-provider-zod";
3
3
 
4
4
  //#region src/index.d.ts
5
5
  declare const signalsRoutes: FastifyPluginAsyncZod<{
6
6
  readTelemetryDatasource: datasource.ReadTelemetryDatasource;
7
7
  }>;
8
+ declare const dashboardsRoutes: FastifyPluginAsyncZod<{
9
+ dynamicDashboardDatasource: dashboardDatasource.DynamicDashboardDatasource;
10
+ promptInstructions?: string;
11
+ }>;
12
+ declare module "fastify" {
13
+ interface FastifyRequest {
14
+ requestContext?: unknown;
15
+ }
16
+ } //# sourceMappingURL=index.d.ts.map
8
17
  //#endregion
9
- export { signalsRoutes };
18
+ export { dashboardsRoutes, signalsRoutes };
10
19
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;cAWa,aAAA,EAAe,qBAAA;EAC1B,uBAAA,EAAyB,UAAA,CAAW,uBAAA;AAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;cAaa,aAAA,EAAe,qBAAA;EAC1B,uBAAA,EAAyB,UAAA,CAAW,uBAAA;AAAA;AAAA,cAmBzB,gBAAA,EAAkB,qBAAA;EAC7B,0BAAA,EAA4B,mBAAA,CAAoB,0BAAA;EAChD,kBAAA;AAAA;AAAA;EAAA,UAaU,cAAA;IACR,cAAA;EAAA;AAAA"}
package/dist/index.mjs CHANGED
@@ -1,16 +1,19 @@
1
- import { dataFilterSchemas, denormalizedSignals } from "@kopai/core";
1
+ import { dashboardDatasource, dataFilterSchemas, denormalizedSignals } from "@kopai/core";
2
2
  import { serializerCompiler, validatorCompiler } from "fastify-type-provider-zod";
3
3
  import "fastify";
4
4
  import { z } from "zod/v4";
5
5
  import z$1 from "zod";
6
6
 
7
7
  //#region src/routes/errors.ts
8
- var SignalsApiError = class extends Error {
8
+ var ApiError = class extends Error {
9
9
  constructor(message, options) {
10
10
  super(message, options);
11
11
  Object.setPrototypeOf(this, new.target.prototype);
12
12
  }
13
13
  };
14
+ var DashboardNotFoundError = class extends ApiError {
15
+ code = "DASHBOARD_NOT_FOUND";
16
+ };
14
17
 
15
18
  //#endregion
16
19
  //#region src/routes/error-handler.ts
@@ -21,8 +24,17 @@ function errorHandler(error, request, reply) {
21
24
  title: "Invalid data",
22
25
  detail: error.message
23
26
  });
27
+ if (error instanceof DashboardNotFoundError) {
28
+ request.log.info(error.message);
29
+ return reply.status(404).send({
30
+ type: "https://docs.kopai.app/errors/dashboard-not-found",
31
+ status: 404,
32
+ title: "Dashboard not found",
33
+ detail: error.message
34
+ });
35
+ }
24
36
  request.log.error(error);
25
- if (error instanceof SignalsApiError) return reply.status(500).send({
37
+ if (error instanceof ApiError) return reply.status(500).send({
26
38
  type: "https://docs.kopai.app/errors/signals-api-internal-error",
27
39
  status: 500,
28
40
  title: "Internal server error",
@@ -67,7 +79,10 @@ const tracesRoutes = async function(fastify, opts) {
67
79
  }
68
80
  },
69
81
  handler: async (req, res) => {
70
- const result = await opts.readTracesDatasource.getTraces({ traceId: req.params.traceId });
82
+ const result = await opts.readTracesDatasource.getTraces({
83
+ traceId: req.params.traceId,
84
+ requestContext: req.requestContext
85
+ });
71
86
  res.send(result.data);
72
87
  }
73
88
  });
@@ -88,7 +103,10 @@ const tracesRoutes = async function(fastify, opts) {
88
103
  }
89
104
  },
90
105
  handler: async (req, res) => {
91
- const result = await opts.readTracesDatasource.getTraces(req.body);
106
+ const result = await opts.readTracesDatasource.getTraces({
107
+ ...req.body,
108
+ requestContext: req.requestContext
109
+ });
92
110
  res.send(result);
93
111
  }
94
112
  });
@@ -114,7 +132,10 @@ const logsRoutes = async function(fastify, opts) {
114
132
  }
115
133
  },
116
134
  handler: async (req, res) => {
117
- const result = await opts.readLogsDatasource.getLogs(req.body);
135
+ const result = await opts.readLogsDatasource.getLogs({
136
+ ...req.body,
137
+ requestContext: req.requestContext
138
+ });
118
139
  res.send(result);
119
140
  }
120
141
  });
@@ -140,7 +161,10 @@ const metricsRoutes = async function(fastify, opts) {
140
161
  }
141
162
  },
142
163
  handler: async (req, res) => {
143
- const result = await opts.readMetricsDatasource.getMetrics(req.body);
164
+ const result = await opts.readMetricsDatasource.getMetrics({
165
+ ...req.body,
166
+ requestContext: req.requestContext
167
+ });
144
168
  res.send(result);
145
169
  }
146
170
  });
@@ -155,8 +179,8 @@ const metricsRoutes = async function(fastify, opts) {
155
179
  "5xx": problemDetailsSchema
156
180
  }
157
181
  },
158
- handler: async (_req, res) => {
159
- const result = await opts.readMetricsDatasource.discoverMetrics();
182
+ handler: async (req, res) => {
183
+ const result = await opts.readMetricsDatasource.discoverMetrics({ requestContext: req.requestContext });
160
184
  res.send(result);
161
185
  }
162
186
  });
@@ -182,6 +206,102 @@ const discoveredMetricSchema = z.object({
182
206
  });
183
207
  const metricsDiscoveryResponseSchema = z.object({ metrics: z.array(discoveredMetricSchema) });
184
208
 
209
+ //#endregion
210
+ //#region src/routes/dashboards.ts
211
+ const dashboardsRoutes$1 = async function(fastify, opts) {
212
+ fastify.route({
213
+ method: "GET",
214
+ url: "/dashboards/schema",
215
+ schema: {
216
+ description: "Get UI tree schema as markdown prompt instructions for AI agents",
217
+ produces: ["text/markdown"],
218
+ response: {
219
+ 200: {
220
+ type: "string",
221
+ description: "Markdown prompt instructions"
222
+ },
223
+ 404: {
224
+ type: "string",
225
+ description: "Prompt instructions not configured"
226
+ }
227
+ }
228
+ },
229
+ handler: async (_req, reply) => {
230
+ if (!opts.promptInstructions) return reply.status(404).send("Dashboard schema not configured");
231
+ reply.type("text/markdown").send(opts.promptInstructions);
232
+ }
233
+ });
234
+ fastify.route({
235
+ method: "POST",
236
+ url: "/dashboards",
237
+ schema: {
238
+ description: "Create a dashboard containing a uiTree",
239
+ body: dashboardDatasource.createDashboardParams,
240
+ response: {
241
+ 201: dashboardDatasource.dashboardSchema,
242
+ "4xx": problemDetailsSchema,
243
+ "5xx": problemDetailsSchema
244
+ }
245
+ },
246
+ handler: async (req, res) => {
247
+ const result = await opts.dynamicDashboardDatasource.createDashboard({
248
+ ...req.body,
249
+ requestContext: req.requestContext
250
+ });
251
+ res.status(201).send(result);
252
+ }
253
+ });
254
+ fastify.route({
255
+ method: "GET",
256
+ url: "/dashboards/:dashboardId",
257
+ schema: {
258
+ description: "Get a dashboard containing a uiTree to be rendered",
259
+ params: z.object({ dashboardId: z.string() }),
260
+ response: {
261
+ 200: dashboardDatasource.dashboardSchema,
262
+ "4xx": problemDetailsSchema,
263
+ "5xx": problemDetailsSchema
264
+ }
265
+ },
266
+ handler: async (req, res) => {
267
+ try {
268
+ const result = await opts.dynamicDashboardDatasource.getDashboard({
269
+ id: req.params.dashboardId,
270
+ requestContext: req.requestContext
271
+ });
272
+ res.send(result);
273
+ } catch (error) {
274
+ if ((error instanceof Error ? error.message.toLowerCase() : "").includes("not found")) throw new DashboardNotFoundError(`Dashboard not found: ${req.params.dashboardId}`, { cause: error });
275
+ throw error;
276
+ }
277
+ }
278
+ });
279
+ const searchResponseSchema = z.object({
280
+ data: z.array(dashboardDatasource.dashboardSchema),
281
+ nextCursor: z.string().nullable()
282
+ });
283
+ fastify.route({
284
+ method: "POST",
285
+ url: "/dashboards/search",
286
+ schema: {
287
+ description: "Search dashboards matching a filter",
288
+ body: dashboardDatasource.searchDashboardsFilter,
289
+ response: {
290
+ 200: searchResponseSchema,
291
+ "4xx": problemDetailsSchema,
292
+ "5xx": problemDetailsSchema
293
+ }
294
+ },
295
+ handler: async (req, res) => {
296
+ const result = await opts.dynamicDashboardDatasource.searchDashboards({
297
+ ...req.body,
298
+ requestContext: req.requestContext
299
+ });
300
+ res.send(result);
301
+ }
302
+ });
303
+ };
304
+
185
305
  //#endregion
186
306
  //#region src/index.ts
187
307
  const signalsRoutes = async function(fastify, opts) {
@@ -192,7 +312,16 @@ const signalsRoutes = async function(fastify, opts) {
192
312
  fastify.register(logsRoutes, { readLogsDatasource: opts.readTelemetryDatasource });
193
313
  fastify.register(metricsRoutes, { readMetricsDatasource: opts.readTelemetryDatasource });
194
314
  };
315
+ const dashboardsRoutes = async function(fastify, opts) {
316
+ fastify.setValidatorCompiler(validatorCompiler);
317
+ fastify.setSerializerCompiler(serializerCompiler);
318
+ fastify.setErrorHandler(errorHandler);
319
+ fastify.register(dashboardsRoutes$1, {
320
+ dynamicDashboardDatasource: opts.dynamicDashboardDatasource,
321
+ promptInstructions: opts.promptInstructions
322
+ });
323
+ };
195
324
 
196
325
  //#endregion
197
- export { signalsRoutes };
326
+ export { dashboardsRoutes, signalsRoutes };
198
327
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["z"],"sources":["../src/routes/errors.ts","../src/routes/error-handler.ts","../src/routes/error-schema-zod.ts","../src/routes/traces.ts","../src/routes/logs.ts","../src/routes/metrics.ts","../src/index.ts"],"sourcesContent":["export abstract class SignalsApiError extends Error {\n abstract readonly code: string;\n\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n","import {\n type FastifyError,\n type FastifyReply,\n type FastifyRequest,\n} from \"fastify\";\nimport { SignalsApiError } from \"./errors.js\";\nimport type { SignalsApiErrorResponse } from \"./error-schema-zod.js\";\nexport function errorHandler(\n error: FastifyError | Error | string,\n request: FastifyRequest,\n reply: FastifyReply\n) {\n if (isClientError(error)) {\n return reply.status(400).send({\n // https://datatracker.ietf.org/doc/html/rfc9457\n // HTTP/1.1 422 Unprocessable Content\n // Content-Type: application/problem+json\n // Content-Language: en\n //\n // {\n // \"type\": \"https://example.net/validation-error\",\n // \"title\": \"Your request is not valid.\",\n // \"errors\": [\n // {\n // \"detail\": \"must be a positive integer\",\n // \"pointer\": \"#/age\"\n // },\n // {\n // \"detail\": \"must be 'green', 'red' or 'blue'\",\n // \"pointer\": \"#/profile/color\"\n // }\n // ]\n // }\n type: \"https://docs.kopai.app/errors/signals-api-validation-error\", // TODO: document error\n status: 400,\n title: \"Invalid data\",\n detail: error.message,\n } satisfies SignalsApiErrorResponse);\n }\n\n request.log.error(error);\n if (error instanceof SignalsApiError) {\n return reply.status(500).send({\n type: \"https://docs.kopai.app/errors/signals-api-internal-error\", // TODO: document error\n status: 500,\n title: \"Internal server error\",\n detail: error.message,\n } satisfies SignalsApiErrorResponse);\n }\n\n return reply.status(500).send({\n type: \"https://docs.kopai.app/errors/signals-api-internal-error\", // TODO: document error\n status: 500,\n title: \"Internal server error\",\n } satisfies SignalsApiErrorResponse);\n}\n\nfunction isFastifyError(error: unknown): error is FastifyError {\n return (\n error instanceof Error &&\n \"code\" in error &&\n typeof (error as FastifyError).code === \"string\"\n );\n}\n\nfunction isClientError(error: unknown): error is FastifyError {\n return (\n isFastifyError(error) &&\n typeof error.statusCode === \"number\" &&\n error.statusCode >= 400 &&\n error.statusCode < 500\n );\n}\n","import z from \"zod\";\n\nexport const problemDetailsSchema = z.object({\n type: z\n .url()\n .default(\"about:blank\")\n .describe(\"URI reference identifying the problem type\"),\n status: z\n .number()\n .int()\n .min(100)\n .max(599)\n .optional()\n .describe(\"HTTP status code generated by the origin server\"),\n title: z\n .string()\n .optional()\n .describe(\"Short human-readable summary of the problem type\"),\n detail: z\n .string()\n .optional()\n .describe(\"Human-readable explanation specific to this occurrence\"),\n instance: z\n .string()\n .optional()\n .describe(\"URI reference identifying this specific occurrence\"),\n});\n\nexport type SignalsApiErrorResponse = z.infer<typeof problemDetailsSchema>;\n","import { z } from \"zod/v4\";\nimport type { FastifyPluginAsyncZod } from \"fastify-type-provider-zod\";\nimport {\n dataFilterSchemas,\n denormalizedSignals,\n type datasource,\n} from \"@kopai/core\";\nimport { problemDetailsSchema } from \"./error-schema-zod.js\";\n\nexport const tracesRoutes: FastifyPluginAsyncZod<{\n readTracesDatasource: datasource.ReadTracesDatasource;\n}> = async function (fastify, opts) {\n fastify.route({\n method: \"GET\",\n url: \"/signals/traces/:traceId\",\n schema: {\n description: \"Get all spans for a trace by traceId\",\n params: z.object({\n traceId: z.string().describe(\"A TraceId of the trace\"),\n }),\n response: {\n 200: z.array(denormalizedSignals.otelTracesSchema),\n \"4xx\": problemDetailsSchema,\n \"5xx\": problemDetailsSchema,\n },\n },\n handler: async (req, res) => {\n const result = await opts.readTracesDatasource.getTraces({\n traceId: req.params.traceId,\n });\n res.send(result.data);\n },\n });\n\n const searchResponseSchema = z.object({\n data: z.array(denormalizedSignals.otelTracesSchema),\n nextCursor: z.string().nullable(),\n });\n\n fastify.route({\n method: \"POST\",\n url: \"/signals/traces/search\",\n schema: {\n description: \"Search spans matching a filter\",\n body: dataFilterSchemas.tracesDataFilterSchema,\n response: {\n 200: searchResponseSchema,\n \"4xx\": problemDetailsSchema,\n \"5xx\": problemDetailsSchema,\n },\n },\n handler: async (req, res) => {\n const result = await opts.readTracesDatasource.getTraces(req.body);\n res.send(result);\n },\n });\n};\n","import { z } from \"zod/v4\";\nimport type { FastifyPluginAsyncZod } from \"fastify-type-provider-zod\";\nimport {\n dataFilterSchemas,\n denormalizedSignals,\n type datasource,\n} from \"@kopai/core\";\nimport { problemDetailsSchema } from \"./error-schema-zod.js\";\n\nexport const logsRoutes: FastifyPluginAsyncZod<{\n readLogsDatasource: datasource.ReadLogsDatasource;\n}> = async function (fastify, opts) {\n const searchResponseSchema = z.object({\n data: z.array(denormalizedSignals.otelLogsSchema),\n nextCursor: z.string().nullable(),\n });\n\n fastify.route({\n method: \"POST\",\n url: \"/signals/logs/search\",\n schema: {\n description: \"Search logs matching a filter\",\n body: dataFilterSchemas.logsDataFilterSchema,\n response: {\n 200: searchResponseSchema,\n \"4xx\": problemDetailsSchema,\n \"5xx\": problemDetailsSchema,\n },\n },\n handler: async (req, res) => {\n const result = await opts.readLogsDatasource.getLogs(req.body);\n res.send(result);\n },\n });\n};\n","import { z } from \"zod/v4\";\nimport type { FastifyPluginAsyncZod } from \"fastify-type-provider-zod\";\nimport {\n dataFilterSchemas,\n denormalizedSignals,\n type datasource,\n} from \"@kopai/core\";\nimport { problemDetailsSchema } from \"./error-schema-zod.js\";\n\nexport const metricsRoutes: FastifyPluginAsyncZod<{\n readMetricsDatasource: datasource.ReadMetricsDatasource;\n}> = async function (fastify, opts) {\n const searchResponseSchema = z.object({\n data: z.array(denormalizedSignals.otelMetricsSchema),\n nextCursor: z.string().nullable(),\n });\n\n fastify.route({\n method: \"POST\",\n url: \"/signals/metrics/search\",\n schema: {\n description: \"Search metrics matching a filter\",\n body: dataFilterSchemas.metricsDataFilterSchema,\n response: {\n 200: searchResponseSchema,\n \"4xx\": problemDetailsSchema,\n \"5xx\": problemDetailsSchema,\n },\n },\n handler: async (req, res) => {\n const result = await opts.readMetricsDatasource.getMetrics(req.body);\n res.send(result);\n },\n });\n\n fastify.route({\n method: \"GET\",\n url: \"/signals/metrics/discover\",\n schema: {\n description: \"Discover available metrics and their attributes\",\n response: {\n 200: metricsDiscoveryResponseSchema,\n \"4xx\": problemDetailsSchema,\n \"5xx\": problemDetailsSchema,\n },\n },\n handler: async (_req, res) => {\n const result = await opts.readMetricsDatasource.discoverMetrics();\n res.send(result);\n },\n });\n};\n\nconst metricTypeSchema = z.enum([\n \"Gauge\",\n \"Sum\",\n \"Histogram\",\n \"ExponentialHistogram\",\n \"Summary\",\n]);\n\nconst discoveredAttributesSchema = z.object({\n values: z\n .record(z.string(), z.array(z.string()))\n .describe(\"Attribute key/value pairs. Max 100 values per key.\"),\n _truncated: z\n .boolean()\n .optional()\n .describe(\"True if any attribute key exceeded 100 values.\"),\n});\n\nconst discoveredMetricSchema = z.object({\n name: z.string().describe(\"Metric name from MetricName field.\"),\n type: metricTypeSchema.describe(\n \"Metric type: Gauge, Sum, Histogram, ExponentialHistogram, or Summary.\"\n ),\n unit: z.string().optional().describe(\"Metric unit from MetricUnit field.\"),\n description: z\n .string()\n .optional()\n .describe(\"Metric description from MetricDescription field.\"),\n attributes: discoveredAttributesSchema.describe(\n \"Data point attributes aggregated across all data points.\"\n ),\n resourceAttributes: discoveredAttributesSchema.describe(\n \"Resource attributes aggregated across all data points.\"\n ),\n});\n\nconst metricsDiscoveryResponseSchema = z.object({\n metrics: z.array(discoveredMetricSchema),\n});\n","import type { FastifyPluginAsyncZod } from \"fastify-type-provider-zod\";\nimport { type datasource } from \"@kopai/core\";\nimport {\n serializerCompiler,\n validatorCompiler,\n} from \"fastify-type-provider-zod\";\nimport { errorHandler } from \"./routes/error-handler.js\";\nimport { tracesRoutes } from \"./routes/traces.js\";\nimport { logsRoutes } from \"./routes/logs.js\";\nimport { metricsRoutes } from \"./routes/metrics.js\";\n\nexport const signalsRoutes: FastifyPluginAsyncZod<{\n readTelemetryDatasource: datasource.ReadTelemetryDatasource;\n}> = async function (fastify, opts) {\n fastify.setValidatorCompiler(validatorCompiler);\n fastify.setSerializerCompiler(serializerCompiler);\n fastify.setErrorHandler(errorHandler);\n\n fastify.register(tracesRoutes, {\n readTracesDatasource: opts.readTelemetryDatasource,\n });\n\n fastify.register(logsRoutes, {\n readLogsDatasource: opts.readTelemetryDatasource,\n });\n\n fastify.register(metricsRoutes, {\n readMetricsDatasource: opts.readTelemetryDatasource,\n });\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["z","dashboardsRoutes","_dashboardsRoutes"],"sources":["../src/routes/errors.ts","../src/routes/error-handler.ts","../src/routes/error-schema-zod.ts","../src/routes/traces.ts","../src/routes/logs.ts","../src/routes/metrics.ts","../src/routes/dashboards.ts","../src/index.ts"],"sourcesContent":["export abstract class ApiError extends Error {\n abstract readonly code: string;\n\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport abstract class SignalsApiError extends ApiError {}\n\nexport class DashboardNotFoundError extends ApiError {\n readonly code = \"DASHBOARD_NOT_FOUND\";\n}\n","import {\n type FastifyError,\n type FastifyReply,\n type FastifyRequest,\n} from \"fastify\";\nimport { ApiError, DashboardNotFoundError } from \"./errors.js\";\nimport type { ApiErrorResponse } from \"./error-schema-zod.js\";\nexport function errorHandler(\n error: FastifyError | Error | string,\n request: FastifyRequest,\n reply: FastifyReply\n) {\n if (isClientError(error)) {\n return reply.status(400).send({\n // https://datatracker.ietf.org/doc/html/rfc9457\n // HTTP/1.1 422 Unprocessable Content\n // Content-Type: application/problem+json\n // Content-Language: en\n //\n // {\n // \"type\": \"https://example.net/validation-error\",\n // \"title\": \"Your request is not valid.\",\n // \"errors\": [\n // {\n // \"detail\": \"must be a positive integer\",\n // \"pointer\": \"#/age\"\n // },\n // {\n // \"detail\": \"must be 'green', 'red' or 'blue'\",\n // \"pointer\": \"#/profile/color\"\n // }\n // ]\n // }\n type: \"https://docs.kopai.app/errors/signals-api-validation-error\", // TODO: document error\n status: 400,\n title: \"Invalid data\",\n detail: error.message,\n } satisfies ApiErrorResponse);\n }\n\n if (error instanceof DashboardNotFoundError) {\n request.log.info(error.message);\n return reply.status(404).send({\n type: \"https://docs.kopai.app/errors/dashboard-not-found\",\n status: 404,\n title: \"Dashboard not found\",\n detail: error.message,\n } satisfies ApiErrorResponse);\n }\n request.log.error(error);\n if (error instanceof ApiError) {\n return reply.status(500).send({\n type: \"https://docs.kopai.app/errors/signals-api-internal-error\", // TODO: document error\n status: 500,\n title: \"Internal server error\",\n detail: error.message,\n } satisfies ApiErrorResponse);\n }\n\n return reply.status(500).send({\n type: \"https://docs.kopai.app/errors/signals-api-internal-error\", // TODO: document error\n status: 500,\n title: \"Internal server error\",\n } satisfies ApiErrorResponse);\n}\n\nfunction isFastifyError(error: unknown): error is FastifyError {\n return (\n error instanceof Error &&\n \"code\" in error &&\n typeof (error as FastifyError).code === \"string\"\n );\n}\n\nfunction isClientError(error: unknown): error is FastifyError {\n return (\n isFastifyError(error) &&\n typeof error.statusCode === \"number\" &&\n error.statusCode >= 400 &&\n error.statusCode < 500\n );\n}\n","import z from \"zod\";\n\nexport const problemDetailsSchema = z.object({\n type: z\n .url()\n .default(\"about:blank\")\n .describe(\"URI reference identifying the problem type\"),\n status: z\n .number()\n .int()\n .min(100)\n .max(599)\n .optional()\n .describe(\"HTTP status code generated by the origin server\"),\n title: z\n .string()\n .optional()\n .describe(\"Short human-readable summary of the problem type\"),\n detail: z\n .string()\n .optional()\n .describe(\"Human-readable explanation specific to this occurrence\"),\n instance: z\n .string()\n .optional()\n .describe(\"URI reference identifying this specific occurrence\"),\n});\n\nexport type ApiErrorResponse = z.infer<typeof problemDetailsSchema>;\n","import { z } from \"zod/v4\";\nimport type { FastifyPluginAsyncZod } from \"fastify-type-provider-zod\";\nimport {\n dataFilterSchemas,\n denormalizedSignals,\n type datasource,\n} from \"@kopai/core\";\nimport { problemDetailsSchema } from \"./error-schema-zod.js\";\n\nexport const tracesRoutes: FastifyPluginAsyncZod<{\n readTracesDatasource: datasource.ReadTracesDatasource;\n}> = async function (fastify, opts) {\n fastify.route({\n method: \"GET\",\n url: \"/signals/traces/:traceId\",\n schema: {\n description: \"Get all spans for a trace by traceId\",\n params: z.object({\n traceId: z.string().describe(\"A TraceId of the trace\"),\n }),\n response: {\n 200: z.array(denormalizedSignals.otelTracesSchema),\n \"4xx\": problemDetailsSchema,\n \"5xx\": problemDetailsSchema,\n },\n },\n handler: async (req, res) => {\n const result = await opts.readTracesDatasource.getTraces({\n traceId: req.params.traceId,\n requestContext: req.requestContext,\n });\n res.send(result.data);\n },\n });\n\n const searchResponseSchema = z.object({\n data: z.array(denormalizedSignals.otelTracesSchema),\n nextCursor: z.string().nullable(),\n });\n\n fastify.route({\n method: \"POST\",\n url: \"/signals/traces/search\",\n schema: {\n description: \"Search spans matching a filter\",\n body: dataFilterSchemas.tracesDataFilterSchema,\n response: {\n 200: searchResponseSchema,\n \"4xx\": problemDetailsSchema,\n \"5xx\": problemDetailsSchema,\n },\n },\n handler: async (req, res) => {\n const result = await opts.readTracesDatasource.getTraces({\n ...req.body,\n requestContext: req.requestContext,\n });\n res.send(result);\n },\n });\n};\n","import { z } from \"zod/v4\";\nimport type { FastifyPluginAsyncZod } from \"fastify-type-provider-zod\";\nimport {\n dataFilterSchemas,\n denormalizedSignals,\n type datasource,\n} from \"@kopai/core\";\nimport { problemDetailsSchema } from \"./error-schema-zod.js\";\n\nexport const logsRoutes: FastifyPluginAsyncZod<{\n readLogsDatasource: datasource.ReadLogsDatasource;\n}> = async function (fastify, opts) {\n const searchResponseSchema = z.object({\n data: z.array(denormalizedSignals.otelLogsSchema),\n nextCursor: z.string().nullable(),\n });\n\n fastify.route({\n method: \"POST\",\n url: \"/signals/logs/search\",\n schema: {\n description: \"Search logs matching a filter\",\n body: dataFilterSchemas.logsDataFilterSchema,\n response: {\n 200: searchResponseSchema,\n \"4xx\": problemDetailsSchema,\n \"5xx\": problemDetailsSchema,\n },\n },\n handler: async (req, res) => {\n const result = await opts.readLogsDatasource.getLogs({\n ...req.body,\n requestContext: req.requestContext,\n });\n res.send(result);\n },\n });\n};\n","import { z } from \"zod/v4\";\nimport type { FastifyPluginAsyncZod } from \"fastify-type-provider-zod\";\nimport {\n dataFilterSchemas,\n denormalizedSignals,\n type datasource,\n} from \"@kopai/core\";\nimport { problemDetailsSchema } from \"./error-schema-zod.js\";\n\nexport const metricsRoutes: FastifyPluginAsyncZod<{\n readMetricsDatasource: datasource.ReadMetricsDatasource;\n}> = async function (fastify, opts) {\n const searchResponseSchema = z.object({\n data: z.array(denormalizedSignals.otelMetricsSchema),\n nextCursor: z.string().nullable(),\n });\n\n fastify.route({\n method: \"POST\",\n url: \"/signals/metrics/search\",\n schema: {\n description: \"Search metrics matching a filter\",\n body: dataFilterSchemas.metricsDataFilterSchema,\n response: {\n 200: searchResponseSchema,\n \"4xx\": problemDetailsSchema,\n \"5xx\": problemDetailsSchema,\n },\n },\n handler: async (req, res) => {\n const result = await opts.readMetricsDatasource.getMetrics({\n ...req.body,\n requestContext: req.requestContext,\n });\n res.send(result);\n },\n });\n\n fastify.route({\n method: \"GET\",\n url: \"/signals/metrics/discover\",\n schema: {\n description: \"Discover available metrics and their attributes\",\n response: {\n 200: metricsDiscoveryResponseSchema,\n \"4xx\": problemDetailsSchema,\n \"5xx\": problemDetailsSchema,\n },\n },\n handler: async (req, res) => {\n const result = await opts.readMetricsDatasource.discoverMetrics({\n requestContext: req.requestContext,\n });\n res.send(result);\n },\n });\n};\n\nconst metricTypeSchema = z.enum([\n \"Gauge\",\n \"Sum\",\n \"Histogram\",\n \"ExponentialHistogram\",\n \"Summary\",\n]);\n\nconst discoveredAttributesSchema = z.object({\n values: z\n .record(z.string(), z.array(z.string()))\n .describe(\"Attribute key/value pairs. Max 100 values per key.\"),\n _truncated: z\n .boolean()\n .optional()\n .describe(\"True if any attribute key exceeded 100 values.\"),\n});\n\nconst discoveredMetricSchema = z.object({\n name: z.string().describe(\"Metric name from MetricName field.\"),\n type: metricTypeSchema.describe(\n \"Metric type: Gauge, Sum, Histogram, ExponentialHistogram, or Summary.\"\n ),\n unit: z.string().optional().describe(\"Metric unit from MetricUnit field.\"),\n description: z\n .string()\n .optional()\n .describe(\"Metric description from MetricDescription field.\"),\n attributes: discoveredAttributesSchema.describe(\n \"Data point attributes aggregated across all data points.\"\n ),\n resourceAttributes: discoveredAttributesSchema.describe(\n \"Resource attributes aggregated across all data points.\"\n ),\n});\n\nconst metricsDiscoveryResponseSchema = z.object({\n metrics: z.array(discoveredMetricSchema),\n});\n","import { z } from \"zod/v4\";\nimport type { FastifyPluginAsyncZod } from \"fastify-type-provider-zod\";\nimport { dashboardDatasource } from \"@kopai/core\";\nimport { problemDetailsSchema } from \"./error-schema-zod.js\";\nimport { DashboardNotFoundError } from \"./errors.js\";\n\nexport const dashboardsRoutes: FastifyPluginAsyncZod<{\n dynamicDashboardDatasource: dashboardDatasource.DynamicDashboardDatasource;\n promptInstructions?: string;\n}> = async function (fastify, opts) {\n fastify.route({\n method: \"GET\",\n url: \"/dashboards/schema\",\n schema: {\n description:\n \"Get UI tree schema as markdown prompt instructions for AI agents\",\n produces: [\"text/markdown\"],\n response: {\n 200: { type: \"string\", description: \"Markdown prompt instructions\" },\n 404: {\n type: \"string\",\n description: \"Prompt instructions not configured\",\n },\n },\n },\n handler: async (_req, reply) => {\n if (!opts.promptInstructions) {\n return reply.status(404).send(\"Dashboard schema not configured\");\n }\n reply.type(\"text/markdown\").send(opts.promptInstructions);\n },\n });\n\n fastify.route({\n method: \"POST\",\n url: \"/dashboards\",\n schema: {\n description: \"Create a dashboard containing a uiTree\",\n body: dashboardDatasource.createDashboardParams,\n response: {\n 201: dashboardDatasource.dashboardSchema,\n \"4xx\": problemDetailsSchema,\n \"5xx\": problemDetailsSchema,\n },\n },\n handler: async (req, res) => {\n const result = await opts.dynamicDashboardDatasource.createDashboard({\n ...req.body,\n requestContext: req.requestContext,\n });\n res.status(201).send(result);\n },\n });\n\n fastify.route({\n method: \"GET\",\n url: \"/dashboards/:dashboardId\",\n schema: {\n description: \"Get a dashboard containing a uiTree to be rendered\",\n params: z.object({\n dashboardId: z.string(),\n }),\n response: {\n 200: dashboardDatasource.dashboardSchema,\n \"4xx\": problemDetailsSchema,\n \"5xx\": problemDetailsSchema,\n },\n },\n handler: async (req, res) => {\n try {\n const result = await opts.dynamicDashboardDatasource.getDashboard({\n id: req.params.dashboardId,\n requestContext: req.requestContext,\n });\n res.send(result);\n } catch (error) {\n const msg = error instanceof Error ? error.message.toLowerCase() : \"\";\n if (msg.includes(\"not found\")) {\n throw new DashboardNotFoundError(\n `Dashboard not found: ${req.params.dashboardId}`,\n { cause: error }\n );\n }\n throw error;\n }\n },\n });\n\n const searchResponseSchema = z.object({\n data: z.array(dashboardDatasource.dashboardSchema),\n nextCursor: z.string().nullable(),\n });\n\n fastify.route({\n method: \"POST\",\n url: \"/dashboards/search\",\n schema: {\n description: \"Search dashboards matching a filter\",\n body: dashboardDatasource.searchDashboardsFilter,\n response: {\n 200: searchResponseSchema,\n \"4xx\": problemDetailsSchema,\n \"5xx\": problemDetailsSchema,\n },\n },\n handler: async (req, res) => {\n const result = await opts.dynamicDashboardDatasource.searchDashboards({\n ...req.body,\n requestContext: req.requestContext,\n });\n res.send(result);\n },\n });\n};\n","import type { FastifyPluginAsyncZod } from \"fastify-type-provider-zod\";\nimport { type datasource, type dashboardDatasource } from \"@kopai/core\";\n\nimport {\n serializerCompiler,\n validatorCompiler,\n} from \"fastify-type-provider-zod\";\nimport { errorHandler } from \"./routes/error-handler.js\";\nimport { tracesRoutes } from \"./routes/traces.js\";\nimport { logsRoutes } from \"./routes/logs.js\";\nimport { metricsRoutes } from \"./routes/metrics.js\";\nimport { dashboardsRoutes as _dashboardsRoutes } from \"./routes/dashboards.js\";\n\nexport const signalsRoutes: FastifyPluginAsyncZod<{\n readTelemetryDatasource: datasource.ReadTelemetryDatasource;\n}> = async function (fastify, opts) {\n fastify.setValidatorCompiler(validatorCompiler);\n fastify.setSerializerCompiler(serializerCompiler);\n fastify.setErrorHandler(errorHandler);\n\n fastify.register(tracesRoutes, {\n readTracesDatasource: opts.readTelemetryDatasource,\n });\n\n fastify.register(logsRoutes, {\n readLogsDatasource: opts.readTelemetryDatasource,\n });\n\n fastify.register(metricsRoutes, {\n readMetricsDatasource: opts.readTelemetryDatasource,\n });\n};\n\nexport const dashboardsRoutes: FastifyPluginAsyncZod<{\n dynamicDashboardDatasource: dashboardDatasource.DynamicDashboardDatasource;\n promptInstructions?: string;\n}> = async function (fastify, opts) {\n fastify.setValidatorCompiler(validatorCompiler);\n fastify.setSerializerCompiler(serializerCompiler);\n fastify.setErrorHandler(errorHandler);\n\n fastify.register(_dashboardsRoutes, {\n dynamicDashboardDatasource: opts.dynamicDashboardDatasource,\n promptInstructions: opts.promptInstructions,\n });\n};\n\ndeclare module \"fastify\" {\n interface FastifyRequest {\n requestContext?: unknown;\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kopai/api",
3
- "version": "0.2.3",
3
+ "version": "0.4.0",
4
4
  "license": "Apache-2.0",
5
5
  "author": "Vladimir Adamic",
6
6
  "repository": {
@@ -27,17 +27,17 @@
27
27
  "dist"
28
28
  ],
29
29
  "peerDependencies": {
30
- "fastify": "^5.0.0",
30
+ "fastify": "^5.7.4",
31
31
  "zod": "^4.0.0"
32
32
  },
33
33
  "dependencies": {
34
34
  "fastify-type-provider-zod": "^6.1.0",
35
- "@kopai/core": "0.5.0"
35
+ "@kopai/core": "0.7.0"
36
36
  },
37
37
  "devDependencies": {
38
- "@fastify/swagger": "^9.6.1",
38
+ "@fastify/swagger": "^9.7.0",
39
39
  "@fastify/swagger-ui": "^5.2.5",
40
- "tsdown": "^0.20.1",
40
+ "tsdown": "^0.20.3",
41
41
  "@kopai/tsconfig": "0.2.0"
42
42
  },
43
43
  "scripts": {