@reaatech/prompt-version-control-server 0.1.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.
Files changed (136) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/LICENSE +21 -0
  3. package/README.md +261 -0
  4. package/dist/api/routes/deployments.d.ts +4 -0
  5. package/dist/api/routes/deployments.d.ts.map +1 -0
  6. package/dist/api/routes/deployments.js +48 -0
  7. package/dist/api/routes/deployments.js.map +1 -0
  8. package/dist/api/routes/docs.d.ts +4 -0
  9. package/dist/api/routes/docs.d.ts.map +1 -0
  10. package/dist/api/routes/docs.js +75 -0
  11. package/dist/api/routes/docs.js.map +1 -0
  12. package/dist/api/routes/evaluations.d.ts +4 -0
  13. package/dist/api/routes/evaluations.d.ts.map +1 -0
  14. package/dist/api/routes/evaluations.js +63 -0
  15. package/dist/api/routes/evaluations.js.map +1 -0
  16. package/dist/api/routes/metrics.d.ts +4 -0
  17. package/dist/api/routes/metrics.d.ts.map +1 -0
  18. package/dist/api/routes/metrics.js +38 -0
  19. package/dist/api/routes/metrics.js.map +1 -0
  20. package/dist/api/routes/promotions.d.ts +4 -0
  21. package/dist/api/routes/promotions.d.ts.map +1 -0
  22. package/dist/api/routes/promotions.js +95 -0
  23. package/dist/api/routes/promotions.js.map +1 -0
  24. package/dist/api/routes/prompts.d.ts +4 -0
  25. package/dist/api/routes/prompts.d.ts.map +1 -0
  26. package/dist/api/routes/prompts.js +80 -0
  27. package/dist/api/routes/prompts.js.map +1 -0
  28. package/dist/api/routes/render.d.ts +4 -0
  29. package/dist/api/routes/render.d.ts.map +1 -0
  30. package/dist/api/routes/render.js +44 -0
  31. package/dist/api/routes/render.js.map +1 -0
  32. package/dist/api/routes/tags.d.ts +4 -0
  33. package/dist/api/routes/tags.d.ts.map +1 -0
  34. package/dist/api/routes/tags.js +41 -0
  35. package/dist/api/routes/tags.js.map +1 -0
  36. package/dist/api/routes/webhooks.d.ts +4 -0
  37. package/dist/api/routes/webhooks.d.ts.map +1 -0
  38. package/dist/api/routes/webhooks.js +49 -0
  39. package/dist/api/routes/webhooks.js.map +1 -0
  40. package/dist/db/client.d.ts +3 -0
  41. package/dist/db/client.d.ts.map +1 -0
  42. package/dist/db/client.js +21 -0
  43. package/dist/db/client.js.map +1 -0
  44. package/dist/db/redis.d.ts +3 -0
  45. package/dist/db/redis.d.ts.map +1 -0
  46. package/dist/db/redis.js +18 -0
  47. package/dist/db/redis.js.map +1 -0
  48. package/dist/errors.d.ts +22 -0
  49. package/dist/errors.d.ts.map +1 -0
  50. package/dist/errors.js +39 -0
  51. package/dist/errors.js.map +1 -0
  52. package/dist/index.d.ts +4 -0
  53. package/dist/index.d.ts.map +1 -0
  54. package/dist/index.js +83 -0
  55. package/dist/index.js.map +1 -0
  56. package/dist/middleware/audit.d.ts +3 -0
  57. package/dist/middleware/audit.d.ts.map +1 -0
  58. package/dist/middleware/audit.js +39 -0
  59. package/dist/middleware/audit.js.map +1 -0
  60. package/dist/middleware/auth.d.ts +3 -0
  61. package/dist/middleware/auth.d.ts.map +1 -0
  62. package/dist/middleware/auth.js +49 -0
  63. package/dist/middleware/auth.js.map +1 -0
  64. package/dist/middleware/error-handler.d.ts +3 -0
  65. package/dist/middleware/error-handler.d.ts.map +1 -0
  66. package/dist/middleware/error-handler.js +36 -0
  67. package/dist/middleware/error-handler.js.map +1 -0
  68. package/dist/middleware/metrics.d.ts +3 -0
  69. package/dist/middleware/metrics.d.ts.map +1 -0
  70. package/dist/middleware/metrics.js +13 -0
  71. package/dist/middleware/metrics.js.map +1 -0
  72. package/dist/middleware/rate-limit.d.ts +8 -0
  73. package/dist/middleware/rate-limit.d.ts.map +1 -0
  74. package/dist/middleware/rate-limit.js +89 -0
  75. package/dist/middleware/rate-limit.js.map +1 -0
  76. package/dist/middleware/request-id.d.ts +3 -0
  77. package/dist/middleware/request-id.d.ts.map +1 -0
  78. package/dist/middleware/request-id.js +10 -0
  79. package/dist/middleware/request-id.js.map +1 -0
  80. package/dist/services/audit.service.d.ts +6 -0
  81. package/dist/services/audit.service.d.ts.map +1 -0
  82. package/dist/services/audit.service.js +26 -0
  83. package/dist/services/audit.service.js.map +1 -0
  84. package/dist/services/deployment.service.d.ts +101 -0
  85. package/dist/services/deployment.service.d.ts.map +1 -0
  86. package/dist/services/deployment.service.js +127 -0
  87. package/dist/services/deployment.service.js.map +1 -0
  88. package/dist/services/diff.engine.d.ts +13 -0
  89. package/dist/services/diff.engine.d.ts.map +1 -0
  90. package/dist/services/diff.engine.js +101 -0
  91. package/dist/services/diff.engine.js.map +1 -0
  92. package/dist/services/eval.service.d.ts +55 -0
  93. package/dist/services/eval.service.d.ts.map +1 -0
  94. package/dist/services/eval.service.js +151 -0
  95. package/dist/services/eval.service.js.map +1 -0
  96. package/dist/services/event.bus.d.ts +18 -0
  97. package/dist/services/event.bus.d.ts.map +1 -0
  98. package/dist/services/event.bus.js +35 -0
  99. package/dist/services/event.bus.js.map +1 -0
  100. package/dist/services/metric.service.d.ts +33 -0
  101. package/dist/services/metric.service.d.ts.map +1 -0
  102. package/dist/services/metric.service.js +64 -0
  103. package/dist/services/metric.service.js.map +1 -0
  104. package/dist/services/prometheus.service.d.ts +7 -0
  105. package/dist/services/prometheus.service.d.ts.map +1 -0
  106. package/dist/services/prometheus.service.js +27 -0
  107. package/dist/services/prometheus.service.js.map +1 -0
  108. package/dist/services/prompt.service.d.ts +59 -0
  109. package/dist/services/prompt.service.d.ts.map +1 -0
  110. package/dist/services/prompt.service.js +144 -0
  111. package/dist/services/prompt.service.js.map +1 -0
  112. package/dist/services/tag.service.d.ts +46 -0
  113. package/dist/services/tag.service.d.ts.map +1 -0
  114. package/dist/services/tag.service.js +84 -0
  115. package/dist/services/tag.service.js.map +1 -0
  116. package/dist/services/webhook.service.d.ts +50 -0
  117. package/dist/services/webhook.service.d.ts.map +1 -0
  118. package/dist/services/webhook.service.js +196 -0
  119. package/dist/services/webhook.service.js.map +1 -0
  120. package/dist/types/hono.d.ts +10 -0
  121. package/dist/types/hono.d.ts.map +1 -0
  122. package/dist/types/hono.js +2 -0
  123. package/dist/types/hono.js.map +1 -0
  124. package/dist/utils/context.d.ts +3 -0
  125. package/dist/utils/context.d.ts.map +1 -0
  126. package/dist/utils/context.js +9 -0
  127. package/dist/utils/context.js.map +1 -0
  128. package/dist/utils/logger.d.ts +3 -0
  129. package/dist/utils/logger.d.ts.map +1 -0
  130. package/dist/utils/logger.js +20 -0
  131. package/dist/utils/logger.js.map +1 -0
  132. package/dist/utils/pagination.d.ts +10 -0
  133. package/dist/utils/pagination.d.ts.map +1 -0
  134. package/dist/utils/pagination.js +10 -0
  135. package/dist/utils/pagination.js.map +1 -0
  136. package/package.json +74 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,14 @@
1
+ # @reaatech/prompt-version-control-server
2
+
3
+ ## 0.1.0
4
+
5
+ ### Initial release
6
+
7
+ - Hono-based API server with Prisma + PostgreSQL persistence and Redis caching
8
+ - Prompt and version CRUD with SHA-256 checksums and automatic version numbering
9
+ - Tag-based lifecycle (`draft`, `staging`, `production`) with eval-gated promotion
10
+ - A/B deployments with weighted traffic splitting and sticky sessions
11
+ - Semantic diffing with line-level diffs and impact scoring
12
+ - Per-version metrics ingestion (cost, latency, quality)
13
+ - Structured Pino logging and a Prometheus `/metrics` endpoint
14
+ - OpenAPI 3.0 spec served at `/api/v1/docs`
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 prompt-version-control contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,261 @@
1
+ # @reaatech/prompt-version-control-server
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@reaatech/prompt-version-control-server.svg)](https://www.npmjs.com/package/@reaatech/prompt-version-control-server)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/reaatech/prompt-version-control/blob/main/LICENSE)
5
+ [![CI](https://img.shields.io/github/actions/workflow/status/reaatech/prompt-version-control/ci.yml?branch=main&label=CI)](https://github.com/reaatech/prompt-version-control/actions/workflows/ci.yml)
6
+
7
+ > **Status:** Pre-1.0 — APIs may change in minor versions. Pin to a specific version in production.
8
+
9
+ Prompt Version Control API server providing Git-like versioning for AI prompts with eval-gated promotion, A/B deployment, metrics collection, and webhook integrations. Built on [Hono 4](https://hono.dev) with [Prisma](https://prisma.io) and PostgreSQL.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ npm install @reaatech/prompt-version-control-server
15
+ # or
16
+ pnpm add @reaatech/prompt-version-control-server
17
+ ```
18
+
19
+ ## Feature Overview
20
+
21
+ - **Prompt CRUD** — create, read, update, and archive prompts with automatic version numbering
22
+ - **Version management** — store and track prompt versions with SHA-256 checksums for deduplication
23
+ - **Tag-based lifecycle** — resolve versions by `draft`, `staging`, and `production` tags
24
+ - **Evaluation gates** — block staging→production promotion on eval harness results
25
+ - **A/B deployments** — serve multiple versions with weighted traffic splitting and sticky sessions
26
+ - **Semantic diffing** — compare versions with line-level diffs and semantic impact scoring
27
+ - **Metrics ingestion** — track per-version cost, latency, and quality metrics
28
+ - **Promotion workflows** — promote/rollback production with audit trails
29
+ - **Webhook subscriptions** — notify external systems on version creation, tag changes, and evaluations
30
+ - **Structured logging** — Pino-based JSON logging with automatic pretty-printing in development
31
+ - **Prometheus metrics** — built-in `/metrics` endpoint for monitoring
32
+ - **API key auth** — scoped API keys with HMAC verification and audit logging
33
+ - **Swagger UI** — OpenAPI 3.0 spec served at `/api/v1/docs`
34
+
35
+ ## Quick Start
36
+
37
+ ### Development
38
+
39
+ ```bash
40
+ # Set up environment
41
+ cp .env.example .env
42
+
43
+ # Install dependencies
44
+ pnpm install
45
+
46
+ # Generate Prisma client
47
+ pnpm --filter @reaatech/prompt-version-control-server db:generate
48
+
49
+ # Run migrations
50
+ pnpm --filter @reaatech/prompt-version-control-server db:migrate
51
+
52
+ # Seed the database
53
+ pnpm --filter @reaatech/prompt-version-control-server db:seed
54
+
55
+ # Start development server with hot reload
56
+ pnpm --filter @reaatech/prompt-version-control-server dev
57
+ ```
58
+
59
+ ### Programmatic
60
+
61
+ ```typescript
62
+ import { app } from "@reaatech/prompt-version-control-server";
63
+ import { serve } from "@hono/node-server";
64
+
65
+ serve({ fetch: app.fetch, port: 3000 }, (info) => {
66
+ console.log(`Server running on http://localhost:${info.port}`);
67
+ });
68
+ ```
69
+
70
+ ## API Reference
71
+
72
+ ### Infrastructure Endpoints
73
+
74
+ | Method | Path | Description |
75
+ |--------|------|-------------|
76
+ | `GET` | `/health` | Health check — returns `{ status: "ok", timestamp }` |
77
+ | `GET` | `/ready` | Readiness check — returns `{ status: "ready" }` |
78
+ | `GET` | `/metrics` | Prometheus text-format metrics |
79
+ | `GET` | `/api/v1/docs` | Swagger UI |
80
+ | `GET` | `/api/v1/docs/openapi.yaml` | Raw OpenAPI 3.0 spec |
81
+
82
+ All API routes are prefixed with `/api/v1` and require `Authorization: Bearer <api-key>` unless noted.
83
+
84
+ ### Prompts
85
+
86
+ | Method | Path | Description |
87
+ |--------|------|-------------|
88
+ | `GET` | `/api/v1/prompts` | List prompts (paginated: `?limit=20&cursor=...`) |
89
+ | `POST` | `/api/v1/prompts` | Create prompt |
90
+ | `GET` | `/api/v1/prompts/:id` | Get prompt by ID |
91
+ | `PUT` | `/api/v1/prompts/:id` | Update prompt |
92
+ | `DELETE` | `/api/v1/prompts/:id` | Archive prompt |
93
+ | `GET` | `/api/v1/prompts/:id/versions` | List versions for prompt (paginated) |
94
+ | `POST` | `/api/v1/prompts/:id/versions` | Create version (auto-increments `number`) |
95
+ | `GET` | `/api/v1/prompts/:id/versions/:vid` | Get specific version |
96
+ | `GET` | `/api/v1/prompts/:id/production` | Get production-tagged version |
97
+ | `GET` | `/api/v1/prompts/:id/diff` | Diff two versions (`?fromVersion=X&toVersion=Y`) |
98
+
99
+ ### Tags
100
+
101
+ | Method | Path | Description |
102
+ |--------|------|-------------|
103
+ | `GET` | `/api/v1/prompts/:id/tags` | List tags for prompt |
104
+ | `POST` | `/api/v1/prompts/:id/tags/:name` | Set tag to a version (`{ versionId }` in body) |
105
+ | `GET` | `/api/v1/prompts/:id/tags/:name` | Get tag details |
106
+ | `DELETE` | `/api/v1/prompts/:id/tags/:name` | Remove tag |
107
+
108
+ Tag names: `draft`, `staging`, `production`. Only one version can hold a given tag at a time.
109
+
110
+ ### Promotions
111
+
112
+ | Method | Path | Description |
113
+ |--------|------|-------------|
114
+ | `POST` | `/api/v1/prompts/:id/promote` | Promote staging → production (gated by eval) |
115
+ | `POST` | `/api/v1/prompts/:id/promote/override` | Force-promote a specific version (`{ versionId }` in body) |
116
+ | `POST` | `/api/v1/prompts/:id/rollback` | Rollback production to previous version |
117
+
118
+ The `promote` endpoint checks the evaluation gate: if the staging version has failed evaluations, the promotion is blocked.
119
+
120
+ ### Evaluations
121
+
122
+ | Method | Path | Description |
123
+ |--------|------|-------------|
124
+ | `POST` | `/api/v1/evaluations/webhook` | Receive eval harness webhook (public, HMAC-authenticated) |
125
+ | `POST` | `/api/v1/evaluations/trigger` | Trigger evaluation (`{ versionId }` in body) |
126
+ | `GET` | `/api/v1/evaluations/versions/:versionId` | List evaluations for a version |
127
+ | `GET` | `/api/v1/evaluations/versions/:versionId/gate` | Get promotion gate status |
128
+
129
+ ### Metrics
130
+
131
+ | Method | Path | Description |
132
+ |--------|------|-------------|
133
+ | `POST` | `/api/v1/metrics/ingest` | Ingest metrics (array of metric objects in body) |
134
+ | `GET` | `/api/v1/metrics/versions/:versionId` | Get metrics for version (`?hours=24` optional) |
135
+ | `GET` | `/api/v1/metrics/prompts/:promptId` | Get metrics for prompt (`?hours=24` optional) |
136
+
137
+ Metric types: `cost`, `latency`, `quality`.
138
+
139
+ ### Deployments
140
+
141
+ | Method | Path | Description |
142
+ |--------|------|-------------|
143
+ | `POST` | `/api/v1/deployments` | Create deployment with weighted variants |
144
+ | `GET` | `/api/v1/deployments` | List deployments (`?promptId=` filter optional) |
145
+ | `GET` | `/api/v1/deployments/:id/resolve` | Resolve version for session (`?sessionId=`) |
146
+ | `PUT` | `/api/v1/deployments/:id` | Update deployment status (`active`/`paused`/`archived`) |
147
+
148
+ ### Render
149
+
150
+ | Method | Path | Description |
151
+ |--------|------|-------------|
152
+ | `POST` | `/api/v1/prompts/:id/versions/:number/render` | Render specific version with variables |
153
+ | `POST` | `/api/v1/prompts/:id/render` | Render production version with variables |
154
+
155
+ Both accept `{ variables: Record<string, unknown> }` in the body and return the rendered output with variable usage metadata.
156
+
157
+ ### Webhooks
158
+
159
+ | Method | Path | Description |
160
+ |--------|------|-------------|
161
+ | `POST` | `/api/v1/webhooks` | Create webhook subscription |
162
+ | `GET` | `/api/v1/webhooks` | List subscriptions |
163
+ | `DELETE` | `/api/v1/webhooks/:id` | Delete subscription |
164
+ | `POST` | `/api/v1/webhooks/:id/test` | Test delivery |
165
+
166
+ ### Middleware Stack
167
+
168
+ All API routes pass through:
169
+
170
+ | Middleware | Description |
171
+ |------------|-------------|
172
+ | `requestIdMiddleware` | Assigns `requestId` to every request context |
173
+ | `compress()` | gzip/deflate response compression |
174
+ | `cors()` | Configurable via `CORS_ALLOWED_ORIGINS` env var |
175
+ | `rateLimit()` | 100 requests per 60-second window per IP |
176
+ | `metricsMiddleware` | Prometheus metrics collection |
177
+ | `auth` | Bearer API key verification via HMAC |
178
+
179
+ ### Environment Variables
180
+
181
+ | Variable | Required | Default | Description |
182
+ |----------|----------|---------|-------------|
183
+ | `DATABASE_URL` | Yes | — | PostgreSQL connection string |
184
+ | `REDIS_URL` | Yes | — | Redis connection string |
185
+ | `NODE_ENV` | No | `development` | Environment (`development` enables pretty logging) |
186
+ | `PORT` | No | `3000` | Server listen port |
187
+ | `LOG_LEVEL` | No | `info` | Pino log level |
188
+ | `JWT_SECRET` | No | — | HMAC pepper for API key hashing |
189
+ | `API_KEY_PEPPER` | No | — | Additional pepper for API key HMAC |
190
+ | `EVAL_WEBHOOK_SECRET` | No | — | HMAC secret for eval webhook verification |
191
+ | `CORS_ALLOWED_ORIGINS` | No | `*` | CORS allowed origins |
192
+
193
+ ## Usage Patterns
194
+
195
+ ### Create a Prompt with Versions
196
+
197
+ ```bash
198
+ # Create a prompt
199
+ curl -X POST http://localhost:3000/api/v1/prompts \
200
+ -H "Authorization: Bearer pvc_your-api-key" \
201
+ -H "Content-Type: application/json" \
202
+ -d '{
203
+ "name": "customer-support",
204
+ "template": "You are a helpful support agent. Help with: {{issue}}"
205
+ }'
206
+
207
+ # Create a version
208
+ curl -X POST http://localhost:3000/api/v1/prompts/<promptId>/versions \
209
+ -H "Authorization: Bearer pvc_your-api-key" \
210
+ -H "Content-Type: application/json" \
211
+ -d '{
212
+ "content": "You are a senior support agent. Help with: {{issue}}"
213
+ }'
214
+
215
+ # Tag as production
216
+ curl -X POST http://localhost:3000/api/v1/prompts/<promptId>/tags/production \
217
+ -H "Authorization: Bearer pvc_your-api-key" \
218
+ -H "Content-Type: application/json" \
219
+ -d '{ "versionId": "<versionId>" }'
220
+ ```
221
+
222
+ ### Render a Prompt with Variables
223
+
224
+ ```bash
225
+ curl -X POST http://localhost:3000/api/v1/prompts/<promptId>/render \
226
+ -H "Authorization: Bearer pvc_your-api-key" \
227
+ -H "Content-Type: application/json" \
228
+ -d '{
229
+ "variables": { "issue": "I cannot log in to my account" }
230
+ }'
231
+ ```
232
+
233
+ ### A/B Deployment
234
+
235
+ ```bash
236
+ curl -X POST http://localhost:3000/api/v1/deployments \
237
+ -H "Authorization: Bearer pvc_your-api-key" \
238
+ -H "Content-Type: application/json" \
239
+ -d '{
240
+ "promptId": "<promptId>",
241
+ "variants": [
242
+ { "versionId": "<versionA>", "weight": 90 },
243
+ { "versionId": "<versionB>", "weight": 10 }
244
+ ]
245
+ }'
246
+
247
+ # Resolve for a session
248
+ curl "http://localhost:3000/api/v1/deployments/<deploymentId>/resolve?sessionId=user-123" \
249
+ -H "Authorization: Bearer pvc_your-api-key"
250
+ ```
251
+
252
+ ## Related Packages
253
+
254
+ - [`@reaatech/prompt-version-control-shared`](https://www.npmjs.com/package/@reaatech/prompt-version-control-shared) — Shared types and schemas
255
+ - [`@reaatech/prompt-version-control`](https://www.npmjs.com/package/@reaatech/prompt-version-control) — TypeScript SDK
256
+ - [`@reaatech/prompt-version-control-cli`](https://www.npmjs.com/package/@reaatech/prompt-version-control-cli) — CLI tool
257
+ - [`@reaatech/prompt-version-control-mcp`](https://www.npmjs.com/package/@reaatech/prompt-version-control-mcp) — MCP server for AI agents
258
+
259
+ ## License
260
+
261
+ [MIT](https://github.com/reaatech/prompt-version-control/blob/main/LICENSE)
@@ -0,0 +1,4 @@
1
+ import { Hono } from 'hono';
2
+ declare const router: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ export { router as deploymentRoutes };
4
+ //# sourceMappingURL=deployments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployments.d.ts","sourceRoot":"","sources":["../../../src/api/routes/deployments.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAM5B,QAAA,MAAM,MAAM,4EAAa,CAAC;AAuD1B,OAAO,EAAE,MAAM,IAAI,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,48 @@
1
+ import { zValidator } from '@hono/zod-validator';
2
+ import { Hono } from 'hono';
3
+ import { z } from 'zod';
4
+ import { authMiddleware } from '../../middleware/auth.js';
5
+ import { deploymentService } from '../../services/deployment.service.js';
6
+ import { getProjectId } from '../../utils/context.js';
7
+ const router = new Hono();
8
+ router.use('*', authMiddleware);
9
+ const CreateDeploymentSchema = z.object({
10
+ promptId: z.string(),
11
+ name: z.string().min(1),
12
+ variants: z.array(z.object({
13
+ versionId: z.string(),
14
+ weight: z.number().int().min(0).max(100),
15
+ isControl: z.boolean().default(false),
16
+ })),
17
+ });
18
+ router.post('/', zValidator('json', CreateDeploymentSchema), async (c) => {
19
+ const projectId = getProjectId(c);
20
+ const body = c.req.valid('json');
21
+ const deployment = await deploymentService.createDeployment(projectId, body.promptId, body.name, body.variants);
22
+ return c.json(deployment, 201);
23
+ });
24
+ router.get('/', async (c) => {
25
+ const projectId = getProjectId(c);
26
+ const promptId = c.req.query('promptId');
27
+ const deployments = await deploymentService.listDeployments(projectId, promptId);
28
+ return c.json({ data: deployments });
29
+ });
30
+ router.get('/:id/resolve', async (c) => {
31
+ const projectId = getProjectId(c);
32
+ const id = c.req.param('id');
33
+ const sessionId = c.req.query('sessionId');
34
+ const versionId = await deploymentService.resolveVersion(projectId, id, sessionId ?? undefined);
35
+ return c.json({ versionId, sessionId });
36
+ });
37
+ const UpdateDeploymentSchema = z.object({
38
+ status: z.enum(['active', 'paused', 'archived']),
39
+ });
40
+ router.put('/:id', zValidator('json', UpdateDeploymentSchema), async (c) => {
41
+ const projectId = getProjectId(c);
42
+ const id = c.req.param('id');
43
+ const body = c.req.valid('json');
44
+ const deployment = await deploymentService.updateStatus(projectId, id, body.status);
45
+ return c.json(deployment);
46
+ });
47
+ export { router as deploymentRoutes };
48
+ //# sourceMappingURL=deployments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployments.js","sourceRoot":"","sources":["../../../src/api/routes/deployments.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { Hono } from 'hono';
2
+ declare const router: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ export { router as docsRoutes };
4
+ //# sourceMappingURL=docs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../../src/api/routes/docs.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,QAAA,MAAM,MAAM,4EAAa,CAAC;AA8E1B,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,CAAC"}
@@ -0,0 +1,75 @@
1
+ import { readFile, stat } from 'node:fs/promises';
2
+ import { dirname, resolve } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { Hono } from 'hono';
5
+ const router = new Hono();
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ /**
8
+ * Locate the OpenAPI spec. We support several layouts:
9
+ * - dev: packages/server/src/api/routes/ → ../../../../../docs/api/openapi.yaml
10
+ * - dist: packages/server/dist/api/routes/ → ../../../../../docs/api/openapi.yaml
11
+ * - docker: /app/openapi.yaml (copied at build time)
12
+ * - explicit: $OPENAPI_SPEC_PATH
13
+ */
14
+ const candidatePaths = [
15
+ ...(process.env.OPENAPI_SPEC_PATH ? [process.env.OPENAPI_SPEC_PATH] : []),
16
+ resolve(__dirname, '../../../../../docs/api/openapi.yaml'),
17
+ resolve(process.cwd(), 'docs/api/openapi.yaml'),
18
+ resolve(process.cwd(), 'openapi.yaml'),
19
+ ];
20
+ let cachedSpec = null;
21
+ async function loadSpec() {
22
+ if (cachedSpec)
23
+ return cachedSpec;
24
+ for (const p of candidatePaths) {
25
+ try {
26
+ await stat(p);
27
+ cachedSpec = await readFile(p, 'utf8');
28
+ return cachedSpec;
29
+ }
30
+ catch {
31
+ // try next candidate
32
+ }
33
+ }
34
+ return null;
35
+ }
36
+ // Where Swagger UI assets are loaded from. Defaults to the public CDN; override
37
+ // via SWAGGER_UI_BASE_URL to point at a vendored copy for airgapped installs.
38
+ const SWAGGER_UI_BASE = (process.env.SWAGGER_UI_BASE_URL ?? 'https://unpkg.com/swagger-ui-dist@5').replace(/\/$/, '');
39
+ router.get('/', async (c) => {
40
+ const spec = await loadSpec();
41
+ if (!spec) {
42
+ return c.json({ error: 'OpenAPI spec not found' }, 404);
43
+ }
44
+ const html = `<!DOCTYPE html>
45
+ <html>
46
+ <head>
47
+ <title>PVC API Documentation</title>
48
+ <meta charset="utf-8" />
49
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
50
+ <link rel="stylesheet" type="text/css" href="${SWAGGER_UI_BASE}/swagger-ui.css" />
51
+ </head>
52
+ <body>
53
+ <div id="swagger-ui"></div>
54
+ <script src="${SWAGGER_UI_BASE}/swagger-ui-bundle.js"></script>
55
+ <script>
56
+ window.onload = function () {
57
+ SwaggerUIBundle({
58
+ url: 'openapi.yaml',
59
+ dom_id: '#swagger-ui',
60
+ });
61
+ };
62
+ </script>
63
+ </body>
64
+ </html>`;
65
+ return c.html(html);
66
+ });
67
+ router.get('/openapi.yaml', async (c) => {
68
+ const spec = await loadSpec();
69
+ if (!spec) {
70
+ return c.json({ error: 'OpenAPI spec not found' }, 404);
71
+ }
72
+ return c.text(spec, 200, { 'Content-Type': 'text/yaml' });
73
+ });
74
+ export { router as docsRoutes };
75
+ //# sourceMappingURL=docs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.js","sourceRoot":"","sources":["../../../src/api/routes/docs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,MAAM,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;AAE1B,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE1D;;;;;;GAMG;AACH,MAAM,cAAc,GAAa;IAC/B,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACzE,OAAO,CAAC,SAAS,EAAE,sCAAsC,CAAC;IAC1D,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,uBAAuB,CAAC;IAC/C,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC;CACvC,CAAC;AAEF,IAAI,UAAU,GAAkB,IAAI,CAAC;AACrC,KAAK,UAAU,QAAQ;IACrB,IAAI,UAAU;QAAE,OAAO,UAAU,CAAC;IAClC,KAAK,MAAM,CAAC,IAAI,cAAc,EAAE,CAAC;QAC/B,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC;YACd,UAAU,GAAG,MAAM,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;YACvC,OAAO,UAAU,CAAC;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,qBAAqB;QACvB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,gFAAgF;AAChF,8EAA8E;AAC9E,MAAM,eAAe,GAAG,CACtB,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,qCAAqC,CACzE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAErB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAC1B,MAAM,IAAI,GAAG,MAAM,QAAQ,EAAE,CAAC;IAC9B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,wBAAwB,EAAE,EAAE,GAAG,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,IAAI,GAAG;;;;;;mDAMoC,eAAe;;;;mBAI/C,eAAe;;;;;;;;;;QAU1B,CAAC;IAEP,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACtB,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,GAAG,CAAC,eAAe,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IACtC,MAAM,IAAI,GAAG,MAAM,QAAQ,EAAE,CAAC;IAC9B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,wBAAwB,EAAE,EAAE,GAAG,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;AAC5D,CAAC,CAAC,CAAC;AAEH,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { Hono } from 'hono';
2
+ declare const router: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ export { router as evaluationRoutes };
4
+ //# sourceMappingURL=evaluations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluations.d.ts","sourceRoot":"","sources":["../../../src/api/routes/evaluations.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAO5B,QAAA,MAAM,MAAM,4EAAa,CAAC;AAgE1B,OAAO,EAAE,MAAM,IAAI,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,63 @@
1
+ import { zValidator } from '@hono/zod-validator';
2
+ import { EvalStatusSchema } from '@reaatech/prompt-version-control-shared';
3
+ import { Hono } from 'hono';
4
+ import { z } from 'zod';
5
+ import { AppError } from '../../errors.js';
6
+ import { authMiddleware } from '../../middleware/auth.js';
7
+ import { evalService } from '../../services/eval.service.js';
8
+ import { getProjectId } from '../../utils/context.js';
9
+ const router = new Hono();
10
+ // Webhook is public (HMAC-authenticated). Mount BEFORE the auth middleware.
11
+ const EvalWebhookSchema = z.object({
12
+ harnessId: z.string().optional(),
13
+ status: EvalStatusSchema,
14
+ score: z.number().optional(),
15
+ metrics: z.record(z.unknown()).optional(),
16
+ });
17
+ router.post('/webhook', async (c) => {
18
+ const evaluationId = c.req.query('evaluationId');
19
+ if (!evaluationId) {
20
+ throw new AppError('MISSING_EVALUATION_ID', 400, 'evaluationId query parameter is required');
21
+ }
22
+ const rawBody = await c.req.text();
23
+ let parsed;
24
+ try {
25
+ parsed = JSON.parse(rawBody);
26
+ }
27
+ catch {
28
+ throw new AppError('INVALID_JSON', 400, 'Invalid JSON body');
29
+ }
30
+ const body = EvalWebhookSchema.parse(parsed);
31
+ const signature = c.req.header('x-webhook-signature') ?? c.req.header('x-hub-signature-256') ?? undefined;
32
+ const eval_ = await evalService.receiveWebhook(evaluationId, rawBody, signature, {
33
+ status: body.status,
34
+ score: body.score,
35
+ metrics: body.metrics,
36
+ });
37
+ return c.json(eval_);
38
+ });
39
+ router.use('*', authMiddleware);
40
+ const TriggerEvalSchema = z.object({
41
+ versionId: z.string(),
42
+ harnessId: z.string().default('default'),
43
+ });
44
+ router.post('/trigger', zValidator('json', TriggerEvalSchema), async (c) => {
45
+ const projectId = getProjectId(c);
46
+ const body = c.req.valid('json');
47
+ const eval_ = await evalService.trigger(projectId, body.versionId, body.harnessId);
48
+ return c.json(eval_, 201);
49
+ });
50
+ router.get('/versions/:versionId', async (c) => {
51
+ const projectId = getProjectId(c);
52
+ const versionId = c.req.param('versionId');
53
+ const evals = await evalService.listByVersion(projectId, versionId);
54
+ return c.json({ data: evals });
55
+ });
56
+ router.get('/versions/:versionId/gate', async (c) => {
57
+ const projectId = getProjectId(c);
58
+ const versionId = c.req.param('versionId');
59
+ const status = await evalService.getPromotionGateStatus(projectId, versionId);
60
+ return c.json(status);
61
+ });
62
+ export { router as evaluationRoutes };
63
+ //# sourceMappingURL=evaluations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluations.js","sourceRoot":"","sources":["../../../src/api/routes/evaluations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { Hono } from 'hono';
2
+ declare const router: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ export { router as metricRoutes };
4
+ //# sourceMappingURL=metrics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../../src/api/routes/metrics.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAM5B,QAAA,MAAM,MAAM,4EAAa,CAAC;AAmC1B,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { zValidator } from '@hono/zod-validator';
2
+ import { IngestMetricSchema } from '@reaatech/prompt-version-control-shared';
3
+ import { Hono } from 'hono';
4
+ import { z } from 'zod';
5
+ import { authMiddleware } from '../../middleware/auth.js';
6
+ import { metricService } from '../../services/metric.service.js';
7
+ import { getProjectId } from '../../utils/context.js';
8
+ const router = new Hono();
9
+ router.use('*', authMiddleware);
10
+ const IngestMetricsSchema = z.object({
11
+ metrics: z.array(IngestMetricSchema),
12
+ });
13
+ router.post('/ingest', zValidator('json', IngestMetricsSchema), async (c) => {
14
+ const projectId = getProjectId(c);
15
+ const body = c.req.valid('json');
16
+ const result = await metricService.ingest(projectId, body.metrics);
17
+ return c.json(result, 201);
18
+ });
19
+ router.get('/versions/:versionId', async (c) => {
20
+ const projectId = getProjectId(c);
21
+ const versionId = c.req.param('versionId');
22
+ const hours = c.req.query('hours');
23
+ const metrics = await metricService.getVersionMetrics(projectId, versionId, {
24
+ hours: hours ? Number(hours) : undefined,
25
+ });
26
+ return c.json({ data: metrics });
27
+ });
28
+ router.get('/prompts/:promptId', async (c) => {
29
+ const projectId = getProjectId(c);
30
+ const promptId = c.req.param('promptId');
31
+ const hours = c.req.query('hours');
32
+ const metrics = await metricService.getPromptMetrics(projectId, promptId, {
33
+ hours: hours ? Number(hours) : undefined,
34
+ });
35
+ return c.json({ data: metrics });
36
+ });
37
+ export { router as metricRoutes };
38
+ //# sourceMappingURL=metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../../src/api/routes/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEtD,MAAM,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;AAE1B,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;AAEhC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC;CACrC,CAAC,CAAC;AAEH,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,MAAM,EAAE,mBAAmB,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAC1E,MAAM,SAAS,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;IAClC,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACnE,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAC7B,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,GAAG,CAAC,sBAAsB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAC7C,MAAM,SAAS,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,iBAAiB,CAAC,SAAS,EAAE,SAAS,EAAE;QAC1E,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS;KACzC,CAAC,CAAC;IACH,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;AACnC,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,GAAG,CAAC,oBAAoB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAC3C,MAAM,SAAS,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACzC,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,gBAAgB,CAAC,SAAS,EAAE,QAAQ,EAAE;QACxE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS;KACzC,CAAC,CAAC;IACH,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;AACnC,CAAC,CAAC,CAAC;AAEH,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { Hono } from 'hono';
2
+ declare const router: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ export { router as promotionRoutes };
4
+ //# sourceMappingURL=promotions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promotions.d.ts","sourceRoot":"","sources":["../../../src/api/routes/promotions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAU5B,QAAA,MAAM,MAAM,4EAAa,CAAC;AAqG1B,OAAO,EAAE,MAAM,IAAI,eAAe,EAAE,CAAC"}