@pga-ai/server 0.8.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.
@@ -0,0 +1,67 @@
1
+ import { type FastifyInstance } from 'fastify';
2
+ import { GenomeInstance } from '@pga-ai/core';
3
+ import type { LLMAdapter, StorageAdapter, WrapOptions } from '@pga-ai/core';
4
+ import type { GeneCategory } from '@pga-ai/core';
5
+ export interface PGAServerConfig {
6
+ storage?: StorageAdapter;
7
+ llm?: LLMAdapter;
8
+ adminApiKey: string;
9
+ port?: number;
10
+ host?: string;
11
+ logger?: boolean;
12
+ rateLimit?: {
13
+ max: number;
14
+ timeWindow: string;
15
+ };
16
+ }
17
+ export interface RegisterGenomeOptions {
18
+ name: string;
19
+ systemPrompt: string;
20
+ protect?: string[];
21
+ evolve?: Array<string | {
22
+ category: GeneCategory;
23
+ content: string;
24
+ }>;
25
+ adapt?: Array<string | {
26
+ trait: string;
27
+ content: string;
28
+ }>;
29
+ evolution?: WrapOptions['evolution'];
30
+ }
31
+ export interface GenomeEntry {
32
+ instance: GenomeInstance;
33
+ secret: string;
34
+ name: string;
35
+ createdAt: Date;
36
+ }
37
+ export declare class PGAServer {
38
+ private config;
39
+ private app;
40
+ private pga;
41
+ private genomes;
42
+ private storage;
43
+ private llm;
44
+ private startTime;
45
+ readonly adminApiKey: string;
46
+ readonly port: number;
47
+ constructor(config: PGAServerConfig);
48
+ start(port?: number): Promise<void>;
49
+ stop(): Promise<void>;
50
+ getApp(): FastifyInstance;
51
+ registerGenome(options: RegisterGenomeOptions): Promise<{
52
+ genomeId: string;
53
+ secret: string;
54
+ }>;
55
+ removeGenome(genomeId: string): Promise<boolean>;
56
+ getGenomeEntry(genomeId: string): GenomeEntry | undefined;
57
+ listGenomes(): Array<{
58
+ genomeId: string;
59
+ name: string;
60
+ createdAt: Date;
61
+ }>;
62
+ getUptime(): number;
63
+ getGenomeCount(): number;
64
+ verifyAdminKey(key: string | undefined): boolean;
65
+ verifyGenomeSecret(genomeId: string, bearer: string | undefined): boolean;
66
+ }
67
+ //# sourceMappingURL=PGAServer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PGAServer.d.ts","sourceRoot":"","sources":["../src/PGAServer.ts"],"names":[],"mappings":"AAkBA,OAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,EAAO,cAAc,EAAyC,MAAM,cAAc,CAAC;AAC1F,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AASjD,MAAM,WAAW,eAAe;IAE5B,OAAO,CAAC,EAAE,cAAc,CAAC;IAEzB,GAAG,CAAC,EAAE,UAAU,CAAC;IAEjB,WAAW,EAAE,MAAM,CAAC;IAEpB,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,SAAS,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;CACnD;AAED,MAAM,WAAW,qBAAqB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG;QAAE,QAAQ,EAAE,YAAY,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrE,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3D,SAAS,CAAC,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,WAAW;IACxB,QAAQ,EAAE,cAAc,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,IAAI,CAAC;CACnB;AAcD,qBAAa,SAAS;IAWN,OAAO,CAAC,MAAM;IAV1B,OAAO,CAAC,GAAG,CAAkB;IAC7B,OAAO,CAAC,GAAG,CAAO;IAClB,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,GAAG,CAAa;IACxB,OAAO,CAAC,SAAS,CAAc;IAE/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEF,MAAM,EAAE,eAAe;IAYrC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiCnC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ3B,MAAM,IAAI,eAAe;IASnB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAkC7F,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAYtD,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAOzD,WAAW,IAAI,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,IAAI,CAAA;KAAE,CAAC;IAWzE,SAAS,IAAI,MAAM;IAOnB,cAAc,IAAI,MAAM;IASxB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO;IAWhD,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO;CAU5E"}
@@ -0,0 +1,133 @@
1
+ import { timingSafeEqual } from 'node:crypto';
2
+ import Fastify from 'fastify';
3
+ import { PGA, GenomeBuilder, InMemoryStorageAdapter } from '@pga-ai/core';
4
+ import { HMACVerifier } from './auth/HMACVerifier.js';
5
+ import { registerHealthRoutes } from './routes/health.js';
6
+ import { registerGenomeRoutes } from './routes/genomes.js';
7
+ import { registerPromptRoutes } from './routes/prompts.js';
8
+ import { registerReportRoutes } from './routes/reports.js';
9
+ class NoopLLMAdapter {
10
+ name = 'noop';
11
+ model = 'noop';
12
+ async chat() {
13
+ return { content: '', usage: { inputTokens: 0, outputTokens: 0 } };
14
+ }
15
+ }
16
+ export class PGAServer {
17
+ config;
18
+ app;
19
+ pga;
20
+ genomes = new Map();
21
+ storage;
22
+ llm;
23
+ startTime = Date.now();
24
+ adminApiKey;
25
+ port;
26
+ constructor(config) {
27
+ this.config = config;
28
+ this.adminApiKey = config.adminApiKey;
29
+ this.port = config.port ?? 4444;
30
+ this.storage = config.storage ?? new InMemoryStorageAdapter();
31
+ this.llm = config.llm ?? new NoopLLMAdapter();
32
+ this.app = Fastify({ logger: config.logger ?? true });
33
+ }
34
+ async start(port) {
35
+ const listenPort = port ?? this.port;
36
+ this.pga = new PGA({
37
+ llm: this.llm,
38
+ storage: this.storage,
39
+ monitoring: { enabled: true, enableCostTracking: true, enableAuditLogs: true },
40
+ });
41
+ await this.pga.initialize();
42
+ if (this.config.rateLimit) {
43
+ const rateLimitPlugin = await import('@fastify/rate-limit');
44
+ await this.app.register(rateLimitPlugin.default, {
45
+ max: this.config.rateLimit.max,
46
+ timeWindow: this.config.rateLimit.timeWindow,
47
+ });
48
+ }
49
+ registerHealthRoutes(this.app, this);
50
+ registerGenomeRoutes(this.app, this);
51
+ registerPromptRoutes(this.app, this);
52
+ registerReportRoutes(this.app, this);
53
+ await this.app.listen({ port: listenPort, host: this.config.host ?? '127.0.0.1' });
54
+ this.startTime = Date.now();
55
+ }
56
+ async stop() {
57
+ await this.app.close();
58
+ this.pga.shutdown();
59
+ }
60
+ getApp() {
61
+ return this.app;
62
+ }
63
+ async registerGenome(options) {
64
+ const genome = GenomeBuilder.build({
65
+ name: options.name,
66
+ systemPrompt: options.systemPrompt,
67
+ protect: options.protect,
68
+ evolve: options.evolve,
69
+ adapt: options.adapt,
70
+ evolution: options.evolution,
71
+ });
72
+ await this.storage.saveGenome(genome);
73
+ const instance = await this.pga.loadGenome(genome.id);
74
+ if (!instance) {
75
+ throw new Error(`Failed to create genome: ${options.name}`);
76
+ }
77
+ const secret = HMACVerifier.generateSecret();
78
+ this.genomes.set(genome.id, {
79
+ instance,
80
+ secret,
81
+ name: options.name,
82
+ createdAt: new Date(),
83
+ });
84
+ return { genomeId: genome.id, secret };
85
+ }
86
+ async removeGenome(genomeId) {
87
+ const entry = this.genomes.get(genomeId);
88
+ if (!entry)
89
+ return false;
90
+ await this.pga.deleteGenome(genomeId);
91
+ this.genomes.delete(genomeId);
92
+ return true;
93
+ }
94
+ getGenomeEntry(genomeId) {
95
+ return this.genomes.get(genomeId);
96
+ }
97
+ listGenomes() {
98
+ return Array.from(this.genomes.entries()).map(([id, entry]) => ({
99
+ genomeId: id,
100
+ name: entry.name,
101
+ createdAt: entry.createdAt,
102
+ }));
103
+ }
104
+ getUptime() {
105
+ return Math.floor((Date.now() - this.startTime) / 1000);
106
+ }
107
+ getGenomeCount() {
108
+ return this.genomes.size;
109
+ }
110
+ verifyAdminKey(key) {
111
+ if (!key)
112
+ return false;
113
+ const a = Buffer.from(key);
114
+ const b = Buffer.from(this.adminApiKey);
115
+ if (a.length !== b.length)
116
+ return false;
117
+ return timingSafeEqual(a, b);
118
+ }
119
+ verifyGenomeSecret(genomeId, bearer) {
120
+ if (!bearer)
121
+ return false;
122
+ const token = bearer.startsWith('Bearer ') ? bearer.slice(7) : bearer;
123
+ const entry = this.genomes.get(genomeId);
124
+ if (!entry)
125
+ return false;
126
+ const a = Buffer.from(token);
127
+ const b = Buffer.from(entry.secret);
128
+ if (a.length !== b.length)
129
+ return false;
130
+ return timingSafeEqual(a, b);
131
+ }
132
+ }
133
+ //# sourceMappingURL=PGAServer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PGAServer.js","sourceRoot":"","sources":["../src/PGAServer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare class HMACVerifier {
2
+ static generateSecret(): string;
3
+ static sign(secret: string, payload: string): string;
4
+ static verify(secret: string, payload: string, signature: string): boolean;
5
+ }
6
+ //# sourceMappingURL=HMACVerifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HMACVerifier.d.ts","sourceRoot":"","sources":["../../src/auth/HMACVerifier.ts"],"names":[],"mappings":"AAeA,qBAAa,YAAY;IAIrB,MAAM,CAAC,cAAc,IAAI,MAAM;IAW/B,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAiBpD,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;CAa7E"}
@@ -0,0 +1,19 @@
1
+ import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto';
2
+ export class HMACVerifier {
3
+ static generateSecret() {
4
+ return randomBytes(32).toString('hex');
5
+ }
6
+ static sign(secret, payload) {
7
+ return createHmac('sha256', secret)
8
+ .update(payload)
9
+ .digest('hex');
10
+ }
11
+ static verify(secret, payload, signature) {
12
+ const expected = HMACVerifier.sign(secret, payload);
13
+ if (expected.length !== signature.length) {
14
+ return false;
15
+ }
16
+ return timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(signature, 'hex'));
17
+ }
18
+ }
19
+ //# sourceMappingURL=HMACVerifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HMACVerifier.js","sourceRoot":"","sources":["../../src/auth/HMACVerifier.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEvE,MAAM,OAAO,YAAY;IAIrB,MAAM,CAAC,cAAc;QACjB,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;IASD,MAAM,CAAC,IAAI,CAAC,MAAc,EAAE,OAAe;QACvC,OAAO,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC;aAC9B,MAAM,CAAC,OAAO,CAAC;aACf,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IAaD,MAAM,CAAC,MAAM,CAAC,MAAc,EAAE,OAAe,EAAE,SAAiB;QAC5D,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAGpD,IAAI,QAAQ,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM,EAAE,CAAC;YACvC,OAAO,KAAK,CAAC;QACjB,CAAC;QAED,OAAO,eAAe,CAClB,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,EAC5B,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAChC,CAAC;IACN,CAAC;CACJ"}
@@ -0,0 +1,4 @@
1
+ export { PGAServer } from './PGAServer.js';
2
+ export type { PGAServerConfig, RegisterGenomeOptions, GenomeEntry } from './PGAServer.js';
3
+ export { HMACVerifier } from './auth/HMACVerifier.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,YAAY,EAAE,eAAe,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC1F,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { PGAServer } from './PGAServer.js';
2
+ export { HMACVerifier } from './auth/HMACVerifier.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ import type { PGAServer } from '../PGAServer.js';
3
+ export declare function registerGenomeRoutes(app: FastifyInstance, server: PGAServer): void;
4
+ //# sourceMappingURL=genomes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"genomes.d.ts","sourceRoot":"","sources":["../../src/routes/genomes.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,eAAe,EAAE,MAAM,EAAE,SAAS,GAAG,IAAI,CAkHlF"}
@@ -0,0 +1,78 @@
1
+ export function registerGenomeRoutes(app, server) {
2
+ app.post('/api/genomes', async (request, reply) => {
3
+ const apiKey = request.headers['x-pga-admin-key'];
4
+ if (!server.verifyAdminKey(apiKey)) {
5
+ return reply.status(401).send({ error: 'Invalid or missing admin API key' });
6
+ }
7
+ const body = request.body;
8
+ if (!body.name || !body.systemPrompt) {
9
+ return reply.status(400).send({ error: 'name and systemPrompt are required' });
10
+ }
11
+ const result = await server.registerGenome({
12
+ name: body.name,
13
+ systemPrompt: body.systemPrompt,
14
+ protect: body.protect,
15
+ evolve: body.evolve,
16
+ adapt: body.adapt,
17
+ });
18
+ return reply.status(201).send(result);
19
+ });
20
+ app.get('/api/genomes', async (request, reply) => {
21
+ const apiKey = request.headers['x-pga-admin-key'];
22
+ if (!server.verifyAdminKey(apiKey)) {
23
+ return reply.status(401).send({ error: 'Invalid or missing admin API key' });
24
+ }
25
+ return server.listGenomes();
26
+ });
27
+ app.get('/api/genomes/:id', async (request, reply) => {
28
+ const apiKey = request.headers['x-pga-admin-key'];
29
+ if (!server.verifyAdminKey(apiKey)) {
30
+ return reply.status(401).send({ error: 'Invalid or missing admin API key' });
31
+ }
32
+ const entry = server.getGenomeEntry(request.params.id);
33
+ if (!entry) {
34
+ return reply.status(404).send({ error: 'Genome not found' });
35
+ }
36
+ const analytics = await entry.instance.getAnalytics();
37
+ return {
38
+ genomeId: request.params.id,
39
+ name: entry.name,
40
+ createdAt: entry.createdAt,
41
+ analytics,
42
+ };
43
+ });
44
+ app.delete('/api/genomes/:id', async (request, reply) => {
45
+ const apiKey = request.headers['x-pga-admin-key'];
46
+ if (!server.verifyAdminKey(apiKey)) {
47
+ return reply.status(401).send({ error: 'Invalid or missing admin API key' });
48
+ }
49
+ const removed = await server.removeGenome(request.params.id);
50
+ if (!removed) {
51
+ return reply.status(404).send({ error: 'Genome not found' });
52
+ }
53
+ return { deleted: true };
54
+ });
55
+ app.get('/api/genomes/:id/drift', async (request, reply) => {
56
+ const apiKey = request.headers['x-pga-admin-key'];
57
+ if (!server.verifyAdminKey(apiKey)) {
58
+ return reply.status(401).send({ error: 'Invalid or missing admin API key' });
59
+ }
60
+ const entry = server.getGenomeEntry(request.params.id);
61
+ if (!entry) {
62
+ return reply.status(404).send({ error: 'Genome not found' });
63
+ }
64
+ return entry.instance.getDriftAnalysis();
65
+ });
66
+ app.get('/api/genomes/:id/health', async (request, reply) => {
67
+ const apiKey = request.headers['x-pga-admin-key'];
68
+ if (!server.verifyAdminKey(apiKey)) {
69
+ return reply.status(401).send({ error: 'Invalid or missing admin API key' });
70
+ }
71
+ const entry = server.getGenomeEntry(request.params.id);
72
+ if (!entry) {
73
+ return reply.status(404).send({ error: 'Genome not found' });
74
+ }
75
+ return entry.instance.getEvolutionHealth();
76
+ });
77
+ }
78
+ //# sourceMappingURL=genomes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"genomes.js","sourceRoot":"","sources":["../../src/routes/genomes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ import type { PGAServer } from '../PGAServer.js';
3
+ export declare function registerHealthRoutes(app: FastifyInstance, server: PGAServer): void;
4
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/routes/health.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,eAAe,EAAE,MAAM,EAAE,SAAS,GAAG,IAAI,CAQlF"}
@@ -0,0 +1,10 @@
1
+ export function registerHealthRoutes(app, server) {
2
+ app.get('/api/health', async () => {
3
+ return {
4
+ status: 'ok',
5
+ genomes: server.getGenomeCount(),
6
+ uptime: server.getUptime(),
7
+ };
8
+ });
9
+ }
10
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/routes/health.ts"],"names":[],"mappings":"AAYA,MAAM,UAAU,oBAAoB,CAAC,GAAoB,EAAE,MAAiB;IACxE,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,IAAI,EAAE;QAC9B,OAAO;YACH,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,MAAM,CAAC,cAAc,EAAE;YAChC,MAAM,EAAE,MAAM,CAAC,SAAS,EAAE;SAC7B,CAAC;IACN,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ import type { PGAServer } from '../PGAServer.js';
3
+ export declare function registerPromptRoutes(app: FastifyInstance, server: PGAServer): void;
4
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/routes/prompts.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,eAAe,EAAE,MAAM,EAAE,SAAS,GAAG,IAAI,CAmClF"}
@@ -0,0 +1,21 @@
1
+ export function registerPromptRoutes(app, server) {
2
+ app.get('/api/genomes/:id/prompt', async (request, reply) => {
3
+ const { id } = request.params;
4
+ const auth = request.headers.authorization;
5
+ if (!server.verifyGenomeSecret(id, auth)) {
6
+ return reply.status(401).send({ error: 'Invalid or missing genome secret' });
7
+ }
8
+ const entry = server.getGenomeEntry(id);
9
+ if (!entry) {
10
+ return reply.status(404).send({ error: 'Genome not found' });
11
+ }
12
+ const { userId, taskType } = request.query;
13
+ const prompt = await entry.instance.assemblePrompt({ userId, taskType }, '');
14
+ reply.header('Cache-Control', 'private, max-age=60');
15
+ return {
16
+ prompt,
17
+ genomeId: id,
18
+ };
19
+ });
20
+ }
21
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/routes/prompts.ts"],"names":[],"mappings":"AAgBA,MAAM,UAAU,oBAAoB,CAAC,GAAoB,EAAE,MAAiB;IAExE,GAAG,CAAC,GAAG,CAGJ,yBAAyB,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACnD,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;QAG9B,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC;QAC3C,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC;YACvC,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,kCAAkC,EAAE,CAAC,CAAC;QACjF,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;QACxC,IAAI,CAAC,KAAK,EAAE,CAAC;YACT,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC;QACjE,CAAC;QAED,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,KAA+C,CAAC;QAGrF,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,cAAc,CAC9C,EAAE,MAAM,EAAE,QAAQ,EAAE,EACpB,EAAE,CACL,CAAC;QAGF,KAAK,CAAC,MAAM,CAAC,eAAe,EAAE,qBAAqB,CAAC,CAAC;QAErD,OAAO;YACH,MAAM;YACN,QAAQ,EAAE,EAAE;SACf,CAAC;IACN,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ import type { PGAServer } from '../PGAServer.js';
3
+ export declare function registerReportRoutes(app: FastifyInstance, server: PGAServer): void;
4
+ //# sourceMappingURL=reports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reports.d.ts","sourceRoot":"","sources":["../../src/routes/reports.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGjD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,eAAe,EAAE,MAAM,EAAE,SAAS,GAAG,IAAI,CAwDlF"}
@@ -0,0 +1,40 @@
1
+ import { HMACVerifier } from '../auth/HMACVerifier.js';
2
+ export function registerReportRoutes(app, server) {
3
+ app.post('/api/genomes/:id/report', async (request, reply) => {
4
+ const { id } = request.params;
5
+ const entry = server.getGenomeEntry(id);
6
+ if (!entry) {
7
+ return reply.status(404).send({ error: 'Genome not found' });
8
+ }
9
+ const signature = request.headers['x-pga-signature'];
10
+ if (!signature) {
11
+ return reply.status(401).send({ error: 'Missing X-PGA-Signature header' });
12
+ }
13
+ const rawBody = JSON.stringify(request.body);
14
+ if (!HMACVerifier.verify(entry.secret, rawBody, signature)) {
15
+ return reply.status(401).send({ error: 'Invalid HMAC signature' });
16
+ }
17
+ const body = request.body;
18
+ if (typeof body.success !== 'boolean' || typeof body.latencyMs !== 'number') {
19
+ return reply.status(400).send({ error: 'success (boolean) and latencyMs (number) are required' });
20
+ }
21
+ try {
22
+ await entry.instance.reportExternalMetrics({
23
+ userId: body.userId,
24
+ success: body.success,
25
+ latencyMs: body.latencyMs,
26
+ inputTokens: body.inputTokens ?? 0,
27
+ outputTokens: body.outputTokens ?? 0,
28
+ taskType: body.taskType,
29
+ quality: body.quality,
30
+ feedback: body.feedback,
31
+ });
32
+ }
33
+ catch (err) {
34
+ request.log.error(err, 'Failed to process metrics');
35
+ return reply.status(500).send({ error: 'Failed to process metrics' });
36
+ }
37
+ return { recorded: true };
38
+ });
39
+ }
40
+ //# sourceMappingURL=reports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reports.js","sourceRoot":"","sources":["../../src/routes/reports.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,MAAM,UAAU,oBAAoB,CAAC,GAAoB,EAAE,MAAiB;IAExE,GAAG,CAAC,IAAI,CAA6B,yBAAyB,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACrF,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;QAE9B,MAAM,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;QACxC,IAAI,CAAC,KAAK,EAAE,CAAC;YACT,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC;QACjE,CAAC;QAGD,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAuB,CAAC;QAC3E,IAAI,CAAC,SAAS,EAAE,CAAC;YACb,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,gCAAgC,EAAE,CAAC,CAAC;QAC/E,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC;YACzD,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,wBAAwB,EAAE,CAAC,CAAC;QACvE,CAAC;QAED,MAAM,IAAI,GAAG,OAAO,CAAC,IASpB,CAAC;QAGF,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;YAC1E,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,uDAAuD,EAAE,CAAC,CAAC;QACtG,CAAC;QAGD,IAAI,CAAC;YACD,MAAM,KAAK,CAAC,QAAQ,CAAC,qBAAqB,CAAC;gBACvC,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,CAAC;gBAClC,YAAY,EAAE,IAAI,CAAC,YAAY,IAAI,CAAC;gBACpC,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ;aAC1B,CAAC,CAAC;QACP,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,2BAA2B,CAAC,CAAC;YACpD,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,2BAA2B,EAAE,CAAC,CAAC;QAC1E,CAAC;QAED,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC9B,CAAC,CAAC,CAAC;AACP,CAAC"}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@pga-ai/server",
3
+ "version": "0.8.0",
4
+ "description": "GSEP Evolution Server — Secure Pull/Push API for external agents",
5
+ "author": "Luis Alfredo Velasquez Duran <contact@gsepcore.com>",
6
+ "license": "MIT",
7
+ "homepage": "https://gsepcore.com",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/LuisvelMarketer/pga-platform",
11
+ "directory": "packages/server"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/LuisvelMarketer/pga-platform/issues"
15
+ },
16
+ "type": "module",
17
+ "main": "./dist/index.js",
18
+ "types": "./dist/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "import": "./dist/index.js",
22
+ "types": "./dist/index.d.ts"
23
+ }
24
+ },
25
+ "files": [
26
+ "dist"
27
+ ],
28
+ "scripts": {
29
+ "build": "tsc",
30
+ "dev": "tsc --watch",
31
+ "test": "vitest run",
32
+ "test:watch": "vitest",
33
+ "clean": "rm -rf dist",
34
+ "typecheck": "tsc --noEmit"
35
+ },
36
+ "dependencies": {
37
+ "@pga-ai/core": "*",
38
+ "fastify": "^5.3.3",
39
+ "@fastify/rate-limit": "^10.2.0"
40
+ },
41
+ "devDependencies": {
42
+ "typescript": "^5.4.5",
43
+ "vitest": "^3.2.4"
44
+ },
45
+ "publishConfig": {
46
+ "access": "public"
47
+ }
48
+ }