@agentlensai/server 0.2.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/LICENSE +21 -0
- package/dist/__tests__/agents-stats.test.d.ts +5 -0
- package/dist/__tests__/agents-stats.test.d.ts.map +1 -0
- package/dist/__tests__/agents-stats.test.js +134 -0
- package/dist/__tests__/agents-stats.test.js.map +1 -0
- package/dist/__tests__/api-keys.test.d.ts +5 -0
- package/dist/__tests__/api-keys.test.d.ts.map +1 -0
- package/dist/__tests__/api-keys.test.js +118 -0
- package/dist/__tests__/api-keys.test.js.map +1 -0
- package/dist/__tests__/auth-no-db.test.d.ts +2 -0
- package/dist/__tests__/auth-no-db.test.d.ts.map +1 -0
- package/dist/__tests__/auth-no-db.test.js +43 -0
- package/dist/__tests__/auth-no-db.test.js.map +1 -0
- package/dist/__tests__/auth.test.d.ts +5 -0
- package/dist/__tests__/auth.test.d.ts.map +1 -0
- package/dist/__tests__/auth.test.js +86 -0
- package/dist/__tests__/auth.test.js.map +1 -0
- package/dist/__tests__/config.test.d.ts +2 -0
- package/dist/__tests__/config.test.d.ts.map +1 -0
- package/dist/__tests__/config.test.js +37 -0
- package/dist/__tests__/config.test.js.map +1 -0
- package/dist/__tests__/events-ingest.test.d.ts +5 -0
- package/dist/__tests__/events-ingest.test.d.ts.map +1 -0
- package/dist/__tests__/events-ingest.test.js +248 -0
- package/dist/__tests__/events-ingest.test.js.map +1 -0
- package/dist/__tests__/events-query.test.d.ts +5 -0
- package/dist/__tests__/events-query.test.d.ts.map +1 -0
- package/dist/__tests__/events-query.test.js +205 -0
- package/dist/__tests__/events-query.test.js.map +1 -0
- package/dist/__tests__/health.test.d.ts +5 -0
- package/dist/__tests__/health.test.d.ts.map +1 -0
- package/dist/__tests__/health.test.js +40 -0
- package/dist/__tests__/health.test.js.map +1 -0
- package/dist/__tests__/sessions.test.d.ts +5 -0
- package/dist/__tests__/sessions.test.d.ts.map +1 -0
- package/dist/__tests__/sessions.test.js +176 -0
- package/dist/__tests__/sessions.test.js.map +1 -0
- package/dist/__tests__/test-helpers.d.ts +24 -0
- package/dist/__tests__/test-helpers.d.ts.map +1 -0
- package/dist/__tests__/test-helpers.js +45 -0
- package/dist/__tests__/test-helpers.js.map +1 -0
- package/dist/config.d.ts +20 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +20 -0
- package/dist/config.js.map +1 -0
- package/dist/db/__tests__/init.test.d.ts +2 -0
- package/dist/db/__tests__/init.test.d.ts.map +1 -0
- package/dist/db/__tests__/init.test.js +73 -0
- package/dist/db/__tests__/init.test.js.map +1 -0
- package/dist/db/__tests__/sqlite-store-read.test.d.ts +2 -0
- package/dist/db/__tests__/sqlite-store-read.test.d.ts.map +1 -0
- package/dist/db/__tests__/sqlite-store-read.test.js +749 -0
- package/dist/db/__tests__/sqlite-store-read.test.js.map +1 -0
- package/dist/db/__tests__/sqlite-store-write.test.d.ts +2 -0
- package/dist/db/__tests__/sqlite-store-write.test.d.ts.map +1 -0
- package/dist/db/__tests__/sqlite-store-write.test.js +418 -0
- package/dist/db/__tests__/sqlite-store-write.test.js.map +1 -0
- package/dist/db/errors.d.ts +16 -0
- package/dist/db/errors.d.ts.map +1 -0
- package/dist/db/errors.js +22 -0
- package/dist/db/errors.js.map +1 -0
- package/dist/db/index.d.ts +33 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +44 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/migrate.d.ts +26 -0
- package/dist/db/migrate.d.ts.map +1 -0
- package/dist/db/migrate.js +128 -0
- package/dist/db/migrate.js.map +1 -0
- package/dist/db/schema.sqlite.d.ts +1009 -0
- package/dist/db/schema.sqlite.d.ts.map +1 -0
- package/dist/db/schema.sqlite.js +96 -0
- package/dist/db/schema.sqlite.js.map +1 -0
- package/dist/db/sqlite-store.d.ts +68 -0
- package/dist/db/sqlite-store.d.ts.map +1 -0
- package/dist/db/sqlite-store.js +753 -0
- package/dist/db/sqlite-store.js.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +182 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/__tests__/retention.test.d.ts +2 -0
- package/dist/lib/__tests__/retention.test.d.ts.map +1 -0
- package/dist/lib/__tests__/retention.test.js +238 -0
- package/dist/lib/__tests__/retention.test.js.map +1 -0
- package/dist/lib/retention.d.ts +31 -0
- package/dist/lib/retention.d.ts.map +1 -0
- package/dist/lib/retention.js +47 -0
- package/dist/lib/retention.js.map +1 -0
- package/dist/middleware/auth.d.ts +37 -0
- package/dist/middleware/auth.d.ts.map +1 -0
- package/dist/middleware/auth.js +78 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/routes/agents.d.ts +13 -0
- package/dist/routes/agents.d.ts.map +1 -0
- package/dist/routes/agents.js +34 -0
- package/dist/routes/agents.js.map +1 -0
- package/dist/routes/api-keys.d.ts +14 -0
- package/dist/routes/api-keys.d.ts.map +1 -0
- package/dist/routes/api-keys.js +81 -0
- package/dist/routes/api-keys.js.map +1 -0
- package/dist/routes/config.d.ts +39 -0
- package/dist/routes/config.d.ts.map +1 -0
- package/dist/routes/config.js +97 -0
- package/dist/routes/config.js.map +1 -0
- package/dist/routes/events.d.ts +14 -0
- package/dist/routes/events.d.ts.map +1 -0
- package/dist/routes/events.js +164 -0
- package/dist/routes/events.js.map +1 -0
- package/dist/routes/sessions.d.ts +14 -0
- package/dist/routes/sessions.d.ts.map +1 -0
- package/dist/routes/sessions.js +72 -0
- package/dist/routes/sessions.js.map +1 -0
- package/dist/routes/stats.d.ts +12 -0
- package/dist/routes/stats.d.ts.map +1 -0
- package/dist/routes/stats.js +16 -0
- package/dist/routes/stats.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retention.js","sourceRoot":"","sources":["../../src/lib/retention.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH,MAAM,sBAAsB,GAAG,EAAE,CAAC;AAElC;;GAEG;AACH,MAAM,UAAU,kBAAkB;IAChC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC9C,MAAM,aAAa,GAAG,OAAO,KAAK,SAAS;QACzC,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;QACvB,CAAC,CAAC,sBAAsB,CAAC;IAE3B,OAAO;QACL,aAAa,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,aAAa;KAC7E,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,KAAkB,EAClB,MAAwB;IAExB,MAAM,cAAc,GAAG,MAAM,IAAI,kBAAkB,EAAE,CAAC;IAEtD,sCAAsC;IACtC,IAAI,cAAc,CAAC,aAAa,KAAK,CAAC,EAAE,CAAC;QACvC,OAAO,EAAE,YAAY,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC5C,CAAC;IAED,IAAI,cAAc,CAAC,aAAa,GAAG,CAAC,EAAE,CAAC;QACrC,OAAO,EAAE,YAAY,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC5C,CAAC;IAED,iCAAiC;IACjC,MAAM,UAAU,GAAG,IAAI,IAAI,EAAE,CAAC;IAC9B,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,cAAc,CAAC,aAAa,CAAC,CAAC;IACxE,MAAM,SAAS,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;IAE3C,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;IAErD,OAAO,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC/D,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Key Authentication Middleware (Story 4.2)
|
|
3
|
+
*
|
|
4
|
+
* Validates `Authorization: Bearer als_xxx` header by hashing the key
|
|
5
|
+
* with SHA-256 and looking it up in the apiKeys table.
|
|
6
|
+
*
|
|
7
|
+
* When AUTH_DISABLED=true, authentication is skipped (dev mode).
|
|
8
|
+
*/
|
|
9
|
+
import type { SqliteDb } from '../db/index.js';
|
|
10
|
+
/**
|
|
11
|
+
* API key info attached to the Hono context.
|
|
12
|
+
*/
|
|
13
|
+
export interface ApiKeyInfo {
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
scopes: string[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Type augmentation for Hono context variables.
|
|
20
|
+
*/
|
|
21
|
+
export type AuthVariables = {
|
|
22
|
+
apiKey: ApiKeyInfo;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* SHA-256 hash a raw API key string.
|
|
26
|
+
*/
|
|
27
|
+
export declare function hashApiKey(raw: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Create the auth middleware.
|
|
30
|
+
*
|
|
31
|
+
* @param db - Drizzle SQLite database instance
|
|
32
|
+
* @param authDisabled - If true, skip authentication (dev mode)
|
|
33
|
+
*/
|
|
34
|
+
export declare function authMiddleware(db: SqliteDb, authDisabled: boolean): import("hono").MiddlewareHandler<{
|
|
35
|
+
Variables: AuthVariables;
|
|
36
|
+
}, string, {}, Response>;
|
|
37
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAI/C;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,UAAU,CAAC;CACpB,CAAC;AAEF;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO;eAC3B,aAAa;yBA0DnD"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Key Authentication Middleware (Story 4.2)
|
|
3
|
+
*
|
|
4
|
+
* Validates `Authorization: Bearer als_xxx` header by hashing the key
|
|
5
|
+
* with SHA-256 and looking it up in the apiKeys table.
|
|
6
|
+
*
|
|
7
|
+
* When AUTH_DISABLED=true, authentication is skipped (dev mode).
|
|
8
|
+
*/
|
|
9
|
+
import { createHash } from 'node:crypto';
|
|
10
|
+
import { createMiddleware } from 'hono/factory';
|
|
11
|
+
import { apiKeys } from '../db/schema.sqlite.js';
|
|
12
|
+
import { eq, and, isNull } from 'drizzle-orm';
|
|
13
|
+
/**
|
|
14
|
+
* SHA-256 hash a raw API key string.
|
|
15
|
+
*/
|
|
16
|
+
export function hashApiKey(raw) {
|
|
17
|
+
return createHash('sha256').update(raw).digest('hex');
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Create the auth middleware.
|
|
21
|
+
*
|
|
22
|
+
* @param db - Drizzle SQLite database instance
|
|
23
|
+
* @param authDisabled - If true, skip authentication (dev mode)
|
|
24
|
+
*/
|
|
25
|
+
export function authMiddleware(db, authDisabled) {
|
|
26
|
+
return createMiddleware(async (c, next) => {
|
|
27
|
+
// Dev mode: skip auth
|
|
28
|
+
if (authDisabled) {
|
|
29
|
+
c.set('apiKey', { id: 'dev', name: 'dev-mode', scopes: ['*'] });
|
|
30
|
+
return next();
|
|
31
|
+
}
|
|
32
|
+
const authHeader = c.req.header('Authorization');
|
|
33
|
+
if (!authHeader) {
|
|
34
|
+
return c.json({ error: 'Missing Authorization header', status: 401 }, 401);
|
|
35
|
+
}
|
|
36
|
+
const match = authHeader.match(/^Bearer\s+(als_\w+)$/);
|
|
37
|
+
if (!match) {
|
|
38
|
+
return c.json({ error: 'Invalid Authorization header format. Expected: Bearer als_xxx', status: 401 }, 401);
|
|
39
|
+
}
|
|
40
|
+
const rawKey = match[1];
|
|
41
|
+
const keyHash = hashApiKey(rawKey);
|
|
42
|
+
// Look up the key by hash (not revoked)
|
|
43
|
+
const row = db
|
|
44
|
+
.select()
|
|
45
|
+
.from(apiKeys)
|
|
46
|
+
.where(and(eq(apiKeys.keyHash, keyHash), isNull(apiKeys.revokedAt)))
|
|
47
|
+
.get();
|
|
48
|
+
if (!row) {
|
|
49
|
+
return c.json({ error: 'Invalid or revoked API key', status: 401 }, 401);
|
|
50
|
+
}
|
|
51
|
+
// Fire-and-forget lastUsedAt update
|
|
52
|
+
const now = Math.floor(Date.now() / 1000);
|
|
53
|
+
try {
|
|
54
|
+
db.update(apiKeys)
|
|
55
|
+
.set({ lastUsedAt: now })
|
|
56
|
+
.where(eq(apiKeys.id, row.id))
|
|
57
|
+
.run();
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// Non-critical — don't fail the request
|
|
61
|
+
}
|
|
62
|
+
const scopes = (() => {
|
|
63
|
+
try {
|
|
64
|
+
return JSON.parse(row.scopes);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
})();
|
|
70
|
+
c.set('apiKey', {
|
|
71
|
+
id: row.id,
|
|
72
|
+
name: row.name,
|
|
73
|
+
scopes,
|
|
74
|
+
});
|
|
75
|
+
return next();
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Endpoints (Story 4.7)
|
|
3
|
+
*
|
|
4
|
+
* GET /api/agents — list all agents (with error rate from sessions)
|
|
5
|
+
* GET /api/agents/:id — single agent
|
|
6
|
+
*/
|
|
7
|
+
import { Hono } from 'hono';
|
|
8
|
+
import type { IEventStore } from '@agentlens/core';
|
|
9
|
+
import type { AuthVariables } from '../middleware/auth.js';
|
|
10
|
+
export declare function agentsRoutes(store: IEventStore): Hono<{
|
|
11
|
+
Variables: AuthVariables;
|
|
12
|
+
}, import("hono/types").BlankSchema, "/">;
|
|
13
|
+
//# sourceMappingURL=agents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/routes/agents.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW;eACX,aAAa;0CAiChD"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Endpoints (Story 4.7)
|
|
3
|
+
*
|
|
4
|
+
* GET /api/agents — list all agents (with error rate from sessions)
|
|
5
|
+
* GET /api/agents/:id — single agent
|
|
6
|
+
*/
|
|
7
|
+
import { Hono } from 'hono';
|
|
8
|
+
export function agentsRoutes(store) {
|
|
9
|
+
const app = new Hono();
|
|
10
|
+
// GET /api/agents — list all agents with computed error rates
|
|
11
|
+
app.get('/', async (c) => {
|
|
12
|
+
const agents = await store.listAgents();
|
|
13
|
+
// Enrich agents with error rate computed from their sessions
|
|
14
|
+
const enriched = await Promise.all(agents.map(async (agent) => {
|
|
15
|
+
const { sessions } = await store.querySessions({ agentId: agent.id, limit: 10000 });
|
|
16
|
+
const totalErrors = sessions.reduce((sum, s) => sum + s.errorCount, 0);
|
|
17
|
+
const totalEvents = sessions.reduce((sum, s) => sum + s.eventCount, 0);
|
|
18
|
+
const errorRate = totalEvents > 0 ? totalErrors / totalEvents : 0;
|
|
19
|
+
return { ...agent, errorRate };
|
|
20
|
+
}));
|
|
21
|
+
return c.json({ agents: enriched });
|
|
22
|
+
});
|
|
23
|
+
// GET /api/agents/:id — single agent
|
|
24
|
+
app.get('/:id', async (c) => {
|
|
25
|
+
const id = c.req.param('id');
|
|
26
|
+
const agent = await store.getAgent(id);
|
|
27
|
+
if (!agent) {
|
|
28
|
+
return c.json({ error: 'Agent not found', status: 404 }, 404);
|
|
29
|
+
}
|
|
30
|
+
return c.json(agent);
|
|
31
|
+
});
|
|
32
|
+
return app;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=agents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/routes/agents.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAI5B,MAAM,UAAU,YAAY,CAAC,KAAkB;IAC7C,MAAM,GAAG,GAAG,IAAI,IAAI,EAAgC,CAAC;IAErD,8DAA8D;IAC9D,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACvB,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,UAAU,EAAE,CAAC;QAExC,6DAA6D;QAC7D,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAChC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACzB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,KAAK,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;YACpF,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YACvE,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YACvE,MAAM,SAAS,GAAG,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;YAClE,OAAO,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,CAAC;QACjC,CAAC,CAAC,CACH,CAAC;QAEF,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,qCAAqC;IACrC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC1B,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAEvC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC;QAChE,CAAC;QAED,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Key Management Endpoints (Story 4.3)
|
|
3
|
+
*
|
|
4
|
+
* POST /api/keys — create a new API key
|
|
5
|
+
* GET /api/keys — list all keys (no raw key exposed)
|
|
6
|
+
* DELETE /api/keys/:id — revoke (soft delete) a key
|
|
7
|
+
*/
|
|
8
|
+
import { Hono } from 'hono';
|
|
9
|
+
import type { SqliteDb } from '../db/index.js';
|
|
10
|
+
import { type AuthVariables } from '../middleware/auth.js';
|
|
11
|
+
export declare function apiKeysRoutes(db: SqliteDb): Hono<{
|
|
12
|
+
Variables: AuthVariables;
|
|
13
|
+
}, import("hono/types").BlankSchema, "/">;
|
|
14
|
+
//# sourceMappingURL=api-keys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-keys.d.ts","sourceRoot":"","sources":["../../src/routes/api-keys.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG/C,OAAO,EAAc,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEvE,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ;eACN,aAAa;0CAyEhD"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Key Management Endpoints (Story 4.3)
|
|
3
|
+
*
|
|
4
|
+
* POST /api/keys — create a new API key
|
|
5
|
+
* GET /api/keys — list all keys (no raw key exposed)
|
|
6
|
+
* DELETE /api/keys/:id — revoke (soft delete) a key
|
|
7
|
+
*/
|
|
8
|
+
import { Hono } from 'hono';
|
|
9
|
+
import { randomBytes } from 'node:crypto';
|
|
10
|
+
import { ulid } from 'ulid';
|
|
11
|
+
import { apiKeys } from '../db/schema.sqlite.js';
|
|
12
|
+
import { eq } from 'drizzle-orm';
|
|
13
|
+
import { hashApiKey } from '../middleware/auth.js';
|
|
14
|
+
export function apiKeysRoutes(db) {
|
|
15
|
+
const app = new Hono();
|
|
16
|
+
// POST /api/keys — create a new API key
|
|
17
|
+
app.post('/', async (c) => {
|
|
18
|
+
const body = await c.req.json().catch(() => ({}));
|
|
19
|
+
const name = body.name;
|
|
20
|
+
const scopes = body.scopes;
|
|
21
|
+
const id = ulid();
|
|
22
|
+
const rawKey = `als_${randomBytes(32).toString('hex')}`;
|
|
23
|
+
const keyHash = hashApiKey(rawKey);
|
|
24
|
+
const now = Math.floor(Date.now() / 1000);
|
|
25
|
+
db.insert(apiKeys)
|
|
26
|
+
.values({
|
|
27
|
+
id,
|
|
28
|
+
keyHash,
|
|
29
|
+
name: name ?? 'Unnamed Key',
|
|
30
|
+
scopes: JSON.stringify(scopes ?? ['*']),
|
|
31
|
+
createdAt: now,
|
|
32
|
+
})
|
|
33
|
+
.run();
|
|
34
|
+
return c.json({
|
|
35
|
+
id,
|
|
36
|
+
key: rawKey,
|
|
37
|
+
name: name ?? 'Unnamed Key',
|
|
38
|
+
scopes: scopes ?? ['*'],
|
|
39
|
+
createdAt: new Date(now * 1000).toISOString(),
|
|
40
|
+
}, 201);
|
|
41
|
+
});
|
|
42
|
+
// GET /api/keys — list all keys
|
|
43
|
+
app.get('/', (c) => {
|
|
44
|
+
const rows = db.select().from(apiKeys).all();
|
|
45
|
+
const keys = rows.map((row) => ({
|
|
46
|
+
id: row.id,
|
|
47
|
+
name: row.name,
|
|
48
|
+
scopes: (() => {
|
|
49
|
+
try {
|
|
50
|
+
return JSON.parse(row.scopes);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
})(),
|
|
56
|
+
createdAt: new Date(row.createdAt * 1000).toISOString(),
|
|
57
|
+
lastUsedAt: row.lastUsedAt ? new Date(row.lastUsedAt * 1000).toISOString() : null,
|
|
58
|
+
revokedAt: row.revokedAt ? new Date(row.revokedAt * 1000).toISOString() : null,
|
|
59
|
+
}));
|
|
60
|
+
return c.json({ keys });
|
|
61
|
+
});
|
|
62
|
+
// DELETE /api/keys/:id — revoke a key
|
|
63
|
+
app.delete('/:id', (c) => {
|
|
64
|
+
const id = c.req.param('id');
|
|
65
|
+
const now = Math.floor(Date.now() / 1000);
|
|
66
|
+
const existing = db.select().from(apiKeys).where(eq(apiKeys.id, id)).get();
|
|
67
|
+
if (!existing) {
|
|
68
|
+
return c.json({ error: 'API key not found', status: 404 }, 404);
|
|
69
|
+
}
|
|
70
|
+
if (existing.revokedAt) {
|
|
71
|
+
return c.json({ error: 'API key already revoked', status: 409 }, 409);
|
|
72
|
+
}
|
|
73
|
+
db.update(apiKeys)
|
|
74
|
+
.set({ revokedAt: now })
|
|
75
|
+
.where(eq(apiKeys.id, id))
|
|
76
|
+
.run();
|
|
77
|
+
return c.json({ id, revoked: true });
|
|
78
|
+
});
|
|
79
|
+
return app;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=api-keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-keys.js","sourceRoot":"","sources":["../../src/routes/api-keys.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config Endpoints (Story 8.4)
|
|
3
|
+
*
|
|
4
|
+
* GET /api/config — get current configuration
|
|
5
|
+
* PUT /api/config — update configuration values
|
|
6
|
+
*
|
|
7
|
+
* Configuration values are stored in a simple key-value table.
|
|
8
|
+
* Falls back to environment defaults when no override exists.
|
|
9
|
+
*/
|
|
10
|
+
import { Hono } from 'hono';
|
|
11
|
+
import { z } from 'zod';
|
|
12
|
+
import type { AuthVariables } from '../middleware/auth.js';
|
|
13
|
+
import type { SqliteDb } from '../db/index.js';
|
|
14
|
+
/** Schema for config update request */
|
|
15
|
+
declare const configUpdateSchema: z.ZodObject<{
|
|
16
|
+
retentionDays: z.ZodOptional<z.ZodNumber>;
|
|
17
|
+
agentGateUrl: z.ZodOptional<z.ZodString>;
|
|
18
|
+
agentGateSecret: z.ZodOptional<z.ZodString>;
|
|
19
|
+
formBridgeUrl: z.ZodOptional<z.ZodString>;
|
|
20
|
+
formBridgeSecret: z.ZodOptional<z.ZodString>;
|
|
21
|
+
}, "strip", z.ZodTypeAny, {
|
|
22
|
+
retentionDays?: number | undefined;
|
|
23
|
+
agentGateUrl?: string | undefined;
|
|
24
|
+
agentGateSecret?: string | undefined;
|
|
25
|
+
formBridgeUrl?: string | undefined;
|
|
26
|
+
formBridgeSecret?: string | undefined;
|
|
27
|
+
}, {
|
|
28
|
+
retentionDays?: number | undefined;
|
|
29
|
+
agentGateUrl?: string | undefined;
|
|
30
|
+
agentGateSecret?: string | undefined;
|
|
31
|
+
formBridgeUrl?: string | undefined;
|
|
32
|
+
formBridgeSecret?: string | undefined;
|
|
33
|
+
}>;
|
|
34
|
+
export type ConfigValues = z.infer<typeof configUpdateSchema>;
|
|
35
|
+
export declare function configRoutes(db: SqliteDb): Hono<{
|
|
36
|
+
Variables: AuthVariables;
|
|
37
|
+
}, import("hono/types").BlankSchema, "/">;
|
|
38
|
+
export {};
|
|
39
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/routes/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG/C,uCAAuC;AACvC,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;EAMtB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAoC9D,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ;eACL,aAAa;0CAuDhD"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config Endpoints (Story 8.4)
|
|
3
|
+
*
|
|
4
|
+
* GET /api/config — get current configuration
|
|
5
|
+
* PUT /api/config — update configuration values
|
|
6
|
+
*
|
|
7
|
+
* Configuration values are stored in a simple key-value table.
|
|
8
|
+
* Falls back to environment defaults when no override exists.
|
|
9
|
+
*/
|
|
10
|
+
import { Hono } from 'hono';
|
|
11
|
+
import { sql } from 'drizzle-orm';
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import { getConfig } from '../config.js';
|
|
14
|
+
/** Schema for config update request */
|
|
15
|
+
const configUpdateSchema = z.object({
|
|
16
|
+
retentionDays: z.number().int().min(0).max(3650).optional(),
|
|
17
|
+
agentGateUrl: z.string().max(2048).optional(),
|
|
18
|
+
agentGateSecret: z.string().max(512).optional(),
|
|
19
|
+
formBridgeUrl: z.string().max(2048).optional(),
|
|
20
|
+
formBridgeSecret: z.string().max(512).optional(),
|
|
21
|
+
});
|
|
22
|
+
/**
|
|
23
|
+
* Ensure the config_kv table exists (simple key-value store).
|
|
24
|
+
*/
|
|
25
|
+
function ensureConfigTable(db) {
|
|
26
|
+
db.run(sql `CREATE TABLE IF NOT EXISTS config_kv (key TEXT PRIMARY KEY, value TEXT NOT NULL)`);
|
|
27
|
+
}
|
|
28
|
+
function getConfigValue(db, key) {
|
|
29
|
+
const row = db.get(sql `SELECT value FROM config_kv WHERE key = ${key}`);
|
|
30
|
+
return row?.value ?? null;
|
|
31
|
+
}
|
|
32
|
+
function setConfigValue(db, key, value) {
|
|
33
|
+
db.run(sql `INSERT INTO config_kv (key, value) VALUES (${key}, ${value}) ON CONFLICT(key) DO UPDATE SET value = ${value}`);
|
|
34
|
+
}
|
|
35
|
+
function getAllConfig(db) {
|
|
36
|
+
const serverConfig = getConfig();
|
|
37
|
+
return {
|
|
38
|
+
retentionDays: (() => {
|
|
39
|
+
const v = getConfigValue(db, 'retentionDays');
|
|
40
|
+
return v !== null ? parseInt(v, 10) : serverConfig.retentionDays;
|
|
41
|
+
})(),
|
|
42
|
+
agentGateUrl: getConfigValue(db, 'agentGateUrl') ?? '',
|
|
43
|
+
agentGateSecret: getConfigValue(db, 'agentGateSecret') ?? '',
|
|
44
|
+
formBridgeUrl: getConfigValue(db, 'formBridgeUrl') ?? '',
|
|
45
|
+
formBridgeSecret: getConfigValue(db, 'formBridgeSecret') ?? '',
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export function configRoutes(db) {
|
|
49
|
+
const app = new Hono();
|
|
50
|
+
ensureConfigTable(db);
|
|
51
|
+
// GET /api/config — current config
|
|
52
|
+
app.get('/', (c) => {
|
|
53
|
+
const config = getAllConfig(db);
|
|
54
|
+
// Mask secrets in response
|
|
55
|
+
return c.json({
|
|
56
|
+
retentionDays: config.retentionDays,
|
|
57
|
+
agentGateUrl: config.agentGateUrl,
|
|
58
|
+
agentGateSecret: config.agentGateSecret ? '••••••••' : '',
|
|
59
|
+
formBridgeUrl: config.formBridgeUrl,
|
|
60
|
+
formBridgeSecret: config.formBridgeSecret ? '••••••••' : '',
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
// PUT /api/config — update config values
|
|
64
|
+
app.put('/', async (c) => {
|
|
65
|
+
const rawBody = await c.req.json().catch(() => null);
|
|
66
|
+
if (!rawBody) {
|
|
67
|
+
return c.json({ error: 'Invalid JSON body', status: 400 }, 400);
|
|
68
|
+
}
|
|
69
|
+
const parseResult = configUpdateSchema.safeParse(rawBody);
|
|
70
|
+
if (!parseResult.success) {
|
|
71
|
+
return c.json({
|
|
72
|
+
error: 'Validation failed',
|
|
73
|
+
status: 400,
|
|
74
|
+
details: parseResult.error.issues,
|
|
75
|
+
}, 400);
|
|
76
|
+
}
|
|
77
|
+
const updates = parseResult.data;
|
|
78
|
+
if (updates.retentionDays !== undefined) {
|
|
79
|
+
setConfigValue(db, 'retentionDays', String(updates.retentionDays));
|
|
80
|
+
}
|
|
81
|
+
if (updates.agentGateUrl !== undefined) {
|
|
82
|
+
setConfigValue(db, 'agentGateUrl', updates.agentGateUrl);
|
|
83
|
+
}
|
|
84
|
+
if (updates.agentGateSecret !== undefined) {
|
|
85
|
+
setConfigValue(db, 'agentGateSecret', updates.agentGateSecret);
|
|
86
|
+
}
|
|
87
|
+
if (updates.formBridgeUrl !== undefined) {
|
|
88
|
+
setConfigValue(db, 'formBridgeUrl', updates.formBridgeUrl);
|
|
89
|
+
}
|
|
90
|
+
if (updates.formBridgeSecret !== undefined) {
|
|
91
|
+
setConfigValue(db, 'formBridgeSecret', updates.formBridgeSecret);
|
|
92
|
+
}
|
|
93
|
+
return c.json({ ok: true });
|
|
94
|
+
});
|
|
95
|
+
return app;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/routes/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event Endpoints (Stories 4.4 + 4.5)
|
|
3
|
+
*
|
|
4
|
+
* POST /api/events — ingest events
|
|
5
|
+
* GET /api/events — query events with filters
|
|
6
|
+
* GET /api/events/:id — get single event
|
|
7
|
+
*/
|
|
8
|
+
import { Hono } from 'hono';
|
|
9
|
+
import type { IEventStore } from '@agentlens/core';
|
|
10
|
+
import type { AuthVariables } from '../middleware/auth.js';
|
|
11
|
+
export declare function eventsRoutes(store: IEventStore): Hono<{
|
|
12
|
+
Variables: AuthVariables;
|
|
13
|
+
}, import("hono/types").BlankSchema, "/">;
|
|
14
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/routes/events.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAW5B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAO3D,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW;eACX,aAAa;0CAyKhD"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event Endpoints (Stories 4.4 + 4.5)
|
|
3
|
+
*
|
|
4
|
+
* POST /api/events — ingest events
|
|
5
|
+
* GET /api/events — query events with filters
|
|
6
|
+
* GET /api/events/:id — get single event
|
|
7
|
+
*/
|
|
8
|
+
import { Hono } from 'hono';
|
|
9
|
+
import { ulid } from 'ulid';
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import { ingestEventSchema, computeEventHash, truncatePayload, DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE, } from '@agentlens/core';
|
|
12
|
+
/** Schema for the batch ingestion request body */
|
|
13
|
+
const ingestBatchSchema = z.object({
|
|
14
|
+
events: z.array(ingestEventSchema).min(1).max(1000),
|
|
15
|
+
});
|
|
16
|
+
export function eventsRoutes(store) {
|
|
17
|
+
const app = new Hono();
|
|
18
|
+
// POST /api/events — ingest events
|
|
19
|
+
app.post('/', async (c) => {
|
|
20
|
+
const rawBody = await c.req.json().catch(() => null);
|
|
21
|
+
if (!rawBody) {
|
|
22
|
+
return c.json({ error: 'Invalid JSON body', status: 400 }, 400);
|
|
23
|
+
}
|
|
24
|
+
const parseResult = ingestBatchSchema.safeParse(rawBody);
|
|
25
|
+
if (!parseResult.success) {
|
|
26
|
+
return c.json({
|
|
27
|
+
error: 'Validation failed',
|
|
28
|
+
status: 400,
|
|
29
|
+
details: parseResult.error.issues.map((issue) => ({
|
|
30
|
+
path: issue.path.join('.'),
|
|
31
|
+
message: issue.message,
|
|
32
|
+
})),
|
|
33
|
+
}, 400);
|
|
34
|
+
}
|
|
35
|
+
const { events: inputEvents } = parseResult.data;
|
|
36
|
+
// Group events by sessionId to handle per-session hash chains
|
|
37
|
+
const bySession = new Map();
|
|
38
|
+
for (const ev of inputEvents) {
|
|
39
|
+
const arr = bySession.get(ev.sessionId) ?? [];
|
|
40
|
+
arr.push(ev);
|
|
41
|
+
bySession.set(ev.sessionId, arr);
|
|
42
|
+
}
|
|
43
|
+
const allProcessed = [];
|
|
44
|
+
// Phase 1: Build all events (validate and compute hashes) without writing
|
|
45
|
+
for (const [sessionId, sessionEvents] of bySession) {
|
|
46
|
+
// Get the last event hash for this session to chain from
|
|
47
|
+
const timeline = await store.getSessionTimeline(sessionId);
|
|
48
|
+
let prevHash = timeline.length > 0 ? timeline[timeline.length - 1].hash : null;
|
|
49
|
+
for (const input of sessionEvents) {
|
|
50
|
+
const id = ulid();
|
|
51
|
+
const timestamp = input.timestamp ?? new Date().toISOString();
|
|
52
|
+
const severity = input.severity ?? 'info';
|
|
53
|
+
const metadata = input.metadata ?? {};
|
|
54
|
+
const payload = truncatePayload(input.payload);
|
|
55
|
+
const hash = computeEventHash({
|
|
56
|
+
id,
|
|
57
|
+
timestamp,
|
|
58
|
+
sessionId: input.sessionId,
|
|
59
|
+
agentId: input.agentId,
|
|
60
|
+
eventType: input.eventType,
|
|
61
|
+
severity,
|
|
62
|
+
payload,
|
|
63
|
+
metadata,
|
|
64
|
+
prevHash,
|
|
65
|
+
});
|
|
66
|
+
const event = {
|
|
67
|
+
id,
|
|
68
|
+
timestamp,
|
|
69
|
+
sessionId: input.sessionId,
|
|
70
|
+
agentId: input.agentId,
|
|
71
|
+
eventType: input.eventType,
|
|
72
|
+
severity: severity,
|
|
73
|
+
payload,
|
|
74
|
+
metadata,
|
|
75
|
+
prevHash,
|
|
76
|
+
hash,
|
|
77
|
+
};
|
|
78
|
+
allProcessed.push(event);
|
|
79
|
+
prevHash = hash;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Phase 2: Insert all events atomically per session group.
|
|
83
|
+
// Group by session for hash-chain integrity, but insertEvents already
|
|
84
|
+
// runs inside a transaction, and if any session group fails the whole
|
|
85
|
+
// request is an error (no partial success).
|
|
86
|
+
const sessionGroups = new Map();
|
|
87
|
+
for (const event of allProcessed) {
|
|
88
|
+
const arr = sessionGroups.get(event.sessionId) ?? [];
|
|
89
|
+
arr.push(event);
|
|
90
|
+
sessionGroups.set(event.sessionId, arr);
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
for (const [, sessionProcessed] of sessionGroups) {
|
|
94
|
+
await store.insertEvents(sessionProcessed);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
// If any session group fails, the entire batch is rejected
|
|
99
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
100
|
+
return c.json({ error: `Batch insert failed: ${message}`, status: 500 }, 500);
|
|
101
|
+
}
|
|
102
|
+
return c.json({
|
|
103
|
+
ingested: allProcessed.length,
|
|
104
|
+
events: allProcessed.map((e) => ({ id: e.id, hash: e.hash })),
|
|
105
|
+
}, 201);
|
|
106
|
+
});
|
|
107
|
+
// GET /api/events — query events
|
|
108
|
+
app.get('/', async (c) => {
|
|
109
|
+
const query = {};
|
|
110
|
+
const sessionId = c.req.query('sessionId');
|
|
111
|
+
if (sessionId)
|
|
112
|
+
query.sessionId = sessionId;
|
|
113
|
+
const agentId = c.req.query('agentId');
|
|
114
|
+
if (agentId)
|
|
115
|
+
query.agentId = agentId;
|
|
116
|
+
const eventType = c.req.query('eventType');
|
|
117
|
+
if (eventType) {
|
|
118
|
+
query.eventType = eventType.includes(',')
|
|
119
|
+
? eventType.split(',')
|
|
120
|
+
: eventType;
|
|
121
|
+
}
|
|
122
|
+
const severity = c.req.query('severity');
|
|
123
|
+
if (severity) {
|
|
124
|
+
query.severity = severity.includes(',')
|
|
125
|
+
? severity.split(',')
|
|
126
|
+
: severity;
|
|
127
|
+
}
|
|
128
|
+
const from = c.req.query('from');
|
|
129
|
+
if (from)
|
|
130
|
+
query.from = from;
|
|
131
|
+
const to = c.req.query('to');
|
|
132
|
+
if (to)
|
|
133
|
+
query.to = to;
|
|
134
|
+
const search = c.req.query('search');
|
|
135
|
+
if (search)
|
|
136
|
+
query.search = search;
|
|
137
|
+
const limitStr = c.req.query('limit');
|
|
138
|
+
query.limit = limitStr
|
|
139
|
+
? Math.max(1, Math.min(parseInt(limitStr, 10) || DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE))
|
|
140
|
+
: DEFAULT_PAGE_SIZE;
|
|
141
|
+
const offsetStr = c.req.query('offset');
|
|
142
|
+
query.offset = offsetStr ? Math.max(0, parseInt(offsetStr, 10) || 0) : 0;
|
|
143
|
+
const order = c.req.query('order');
|
|
144
|
+
if (order === 'asc' || order === 'desc')
|
|
145
|
+
query.order = order;
|
|
146
|
+
const result = await store.queryEvents(query);
|
|
147
|
+
return c.json({
|
|
148
|
+
events: result.events,
|
|
149
|
+
total: result.total,
|
|
150
|
+
hasMore: result.hasMore,
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
// GET /api/events/:id — single event
|
|
154
|
+
app.get('/:id', async (c) => {
|
|
155
|
+
const id = c.req.param('id');
|
|
156
|
+
const event = await store.getEvent(id);
|
|
157
|
+
if (!event) {
|
|
158
|
+
return c.json({ error: 'Event not found', status: 404 }, 404);
|
|
159
|
+
}
|
|
160
|
+
return c.json(event);
|
|
161
|
+
});
|
|
162
|
+
return app;
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/routes/events.ts"],"names":[],"mappings":"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"}
|