@vfarcic/dot-ai 1.21.1 → 1.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/git-utils.d.ts +46 -0
- package/dist/core/git-utils.d.ts.map +1 -1
- package/dist/core/git-utils.js +192 -1
- package/dist/core/user-prompts-loader.d.ts +129 -1
- package/dist/core/user-prompts-loader.d.ts.map +1 -1
- package/dist/core/user-prompts-loader.js +654 -68
- package/dist/interfaces/cors-headers.d.ts +41 -0
- package/dist/interfaces/cors-headers.d.ts.map +1 -0
- package/dist/interfaces/cors-headers.js +43 -0
- package/dist/interfaces/header-redaction.d.ts +28 -0
- package/dist/interfaces/header-redaction.d.ts.map +1 -0
- package/dist/interfaces/header-redaction.js +48 -0
- package/dist/interfaces/mcp.d.ts +22 -0
- package/dist/interfaces/mcp.d.ts.map +1 -1
- package/dist/interfaces/mcp.js +131 -7
- package/dist/interfaces/openapi-generator.d.ts.map +1 -1
- package/dist/interfaces/openapi-generator.js +11 -5
- package/dist/interfaces/rest-api.d.ts +59 -15
- package/dist/interfaces/rest-api.d.ts.map +1 -1
- package/dist/interfaces/rest-api.js +288 -52
- package/dist/interfaces/routes/index.d.ts.map +1 -1
- package/dist/interfaces/routes/index.js +35 -0
- package/dist/interfaces/schemas/common.d.ts +33 -0
- package/dist/interfaces/schemas/common.d.ts.map +1 -1
- package/dist/interfaces/schemas/common.js +20 -1
- package/dist/interfaces/schemas/index.d.ts +2 -2
- package/dist/interfaces/schemas/index.d.ts.map +1 -1
- package/dist/interfaces/schemas/index.js +14 -3
- package/dist/interfaces/schemas/prompts.d.ts +155 -0
- package/dist/interfaces/schemas/prompts.d.ts.map +1 -1
- package/dist/interfaces/schemas/prompts.js +134 -1
- package/dist/tools/prompts.d.ts.map +1 -1
- package/dist/tools/prompts.js +37 -2
- package/package.json +6 -4
|
@@ -41,6 +41,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
41
41
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
42
|
exports.RestApiRouter = exports.HttpStatus = exports.UNPARSEABLE_QUERY_PLACEHOLDER = void 0;
|
|
43
43
|
exports.sanitizeRequestUrlForLogging = sanitizeRequestUrlForLogging;
|
|
44
|
+
exports.extractPromptsOverride = extractPromptsOverride;
|
|
44
45
|
const node_url_1 = require("node:url");
|
|
45
46
|
const openapi_generator_1 = require("./openapi-generator");
|
|
46
47
|
const rest_route_registry_1 = require("./rest-route-registry");
|
|
@@ -50,6 +51,7 @@ const embedding_migration_handler_1 = require("./embedding-migration-handler");
|
|
|
50
51
|
const prompts_1 = require("../tools/prompts");
|
|
51
52
|
const user_prompts_loader_1 = require("../core/user-prompts-loader");
|
|
52
53
|
const git_utils_1 = require("../core/git-utils");
|
|
54
|
+
const cors_headers_1 = require("./cors-headers");
|
|
53
55
|
const generic_session_manager_1 = require("../core/generic-session-manager");
|
|
54
56
|
const session_events_1 = require("../core/session-events");
|
|
55
57
|
const shared_prompt_loader_1 = require("../core/shared-prompt-loader");
|
|
@@ -72,9 +74,11 @@ const rbac_1 = require("../core/rbac");
|
|
|
72
74
|
exports.UNPARSEABLE_QUERY_PLACEHOLDER = '?<redacted-unparseable>';
|
|
73
75
|
/**
|
|
74
76
|
* F3: req.url is logged on every request; with PRD #581 the query string may
|
|
75
|
-
* carry `?repo=<user-supplied-url>` whose value can include credentials
|
|
76
|
-
*
|
|
77
|
-
*
|
|
77
|
+
* carry `?repo=<user-supplied-url>` whose value can include credentials, and
|
|
78
|
+
* PRD #647 adds `?source=<identifier>` which is equally credential-bearing (it
|
|
79
|
+
* may be a `https://user:tok@host` git URL). This helper rewrites BOTH values
|
|
80
|
+
* to their credential-scrubbed form so the raw token doesn't reach the log.
|
|
81
|
+
* Everything else is preserved verbatim.
|
|
78
82
|
*
|
|
79
83
|
* CodeRabbit Major B: on parse failure, we no longer return the input
|
|
80
84
|
* verbatim — an unparseable URL is more likely than a parseable one to hide
|
|
@@ -86,8 +90,19 @@ exports.UNPARSEABLE_QUERY_PLACEHOLDER = '?<redacted-unparseable>';
|
|
|
86
90
|
function sanitizeRequestUrlForLogging(url) {
|
|
87
91
|
if (!url)
|
|
88
92
|
return url;
|
|
89
|
-
|
|
93
|
+
// Fast path: only walk the URL when it carries a credential-bearing param
|
|
94
|
+
// we know how to scrub (PRD #581 `repo=`, PRD #647 `source=`).
|
|
95
|
+
//
|
|
96
|
+
// CodeRabbit C3: a percent-encoded param NAME (e.g. `r%65po=`, `s%6Frce=`)
|
|
97
|
+
// decodes to `repo`/`source` once parsed, so the literal-substring fast path
|
|
98
|
+
// would early-return WITHOUT scrubbing and leak the credential into the log.
|
|
99
|
+
// Any `%` means a name could be encoded, so fall through to the full
|
|
100
|
+
// parse-and-scrub below (URLSearchParams decodes the name, catching it).
|
|
101
|
+
if (!url.includes('repo=') &&
|
|
102
|
+
!url.includes('source=') &&
|
|
103
|
+
!url.includes('%')) {
|
|
90
104
|
return url;
|
|
105
|
+
}
|
|
91
106
|
try {
|
|
92
107
|
// req.url is path-relative; provide a dummy base for URL parsing.
|
|
93
108
|
const parsed = new node_url_1.URL(url, 'http://internal.invalid');
|
|
@@ -95,6 +110,13 @@ function sanitizeRequestUrlForLogging(url) {
|
|
|
95
110
|
if (repo) {
|
|
96
111
|
parsed.searchParams.set('repo', (0, user_prompts_loader_1.sanitizeUrlForLogging)(repo));
|
|
97
112
|
}
|
|
113
|
+
// PRD #647 M5 (F2): `?source=` is scrubbed with the same deep helper used
|
|
114
|
+
// for the echoed `source` (userinfo + credential-bearing query params), so
|
|
115
|
+
// `?source=https://user:tok@host` never appears unscrubbed in the log.
|
|
116
|
+
const source = parsed.searchParams.get('source');
|
|
117
|
+
if (source) {
|
|
118
|
+
parsed.searchParams.set('source', (0, user_prompts_loader_1.scrubSourceUrl)(source));
|
|
119
|
+
}
|
|
98
120
|
// Return path + search only (drop the dummy base).
|
|
99
121
|
return parsed.pathname + parsed.search + parsed.hash;
|
|
100
122
|
}
|
|
@@ -108,6 +130,150 @@ function sanitizeRequestUrlForLogging(url) {
|
|
|
108
130
|
return url.slice(0, qIdx) + exports.UNPARSEABLE_QUERY_PLACEHOLDER;
|
|
109
131
|
}
|
|
110
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Coerce an optional override string param (path/branch) supplied via query
|
|
135
|
+
* string or JSON body. Mirrors the `repo` guard in extractPromptsOverride:
|
|
136
|
+
* - non-string (array, number, object, boolean) → 400 (avoids a 500 from a
|
|
137
|
+
* malformed body reaching downstream code).
|
|
138
|
+
* - absent (null/undefined) or empty/whitespace-only → `undefined`, i.e.
|
|
139
|
+
* treated as not supplied so the downstream default (subPath '' / branch
|
|
140
|
+
* 'main') is preserved and an empty-string branch never reaches
|
|
141
|
+
* isValidGitBranch (which would otherwise reject it).
|
|
142
|
+
* - otherwise → the trimmed value.
|
|
143
|
+
*/
|
|
144
|
+
function coerceOverrideStringParam(value, name) {
|
|
145
|
+
if (value === undefined || value === null) {
|
|
146
|
+
return { ok: true, value: undefined };
|
|
147
|
+
}
|
|
148
|
+
if (typeof value !== 'string') {
|
|
149
|
+
return {
|
|
150
|
+
ok: false,
|
|
151
|
+
message: `${name} must be a string (got ${Array.isArray(value) ? 'array' : typeof value})`,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
const trimmed = value.trim();
|
|
155
|
+
return { ok: true, value: trimmed.length > 0 ? trimmed : undefined };
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Read the per-request git credential from the X-Dot-AI-Git-Token header
|
|
159
|
+
* (PRD #621 M2). Node lowercases incoming header names and may present a
|
|
160
|
+
* repeated header as an array; normalize to a single non-empty string or
|
|
161
|
+
* undefined. The value is a secret, so it is never logged here.
|
|
162
|
+
*/
|
|
163
|
+
function readGitTokenHeader(req) {
|
|
164
|
+
const raw = req.headers[cors_headers_1.GIT_TOKEN_HEADER_LC];
|
|
165
|
+
const value = Array.isArray(raw) ? raw[0] : raw;
|
|
166
|
+
if (typeof value !== 'string') {
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
const trimmed = value.trim();
|
|
170
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Extract and validate the per-request prompts override.
|
|
174
|
+
*
|
|
175
|
+
* Threads three optional, additive inputs from the request into a
|
|
176
|
+
* UserPromptsOverride (PRD #581 introduced `repo`; PRD #621 M1 adds `path`
|
|
177
|
+
* and `branch`):
|
|
178
|
+
* - repoParam → override.repoUrl (GET ?repo= / POST body `repo`)
|
|
179
|
+
* - pathParam → override.subPath (GET ?path= / POST body `path`)
|
|
180
|
+
* - branchParam → override.branch (GET ?branch= / POST body `branch`)
|
|
181
|
+
* - gitToken → override.gitToken (X-Dot-AI-Git-Token request header; M2)
|
|
182
|
+
*
|
|
183
|
+
* Returns:
|
|
184
|
+
* - { ok: true, override } when no `repo` is supplied (override undefined;
|
|
185
|
+
* any path/branch/token are ignored, since they only qualify an override —
|
|
186
|
+
* this keeps the no-`repo` / env-var-configured path unchanged).
|
|
187
|
+
* - { ok: true, override } when a syntactically valid override is supplied.
|
|
188
|
+
* - { ok: false, message } when the override fails validation (HTTP 400).
|
|
189
|
+
*
|
|
190
|
+
* The validation message is run through scrubCredentials so embedded tokens
|
|
191
|
+
* never reach the wire response.
|
|
192
|
+
*
|
|
193
|
+
* Backward compatibility (PRD #621, non-negotiable): when path/branch are
|
|
194
|
+
* absent or empty, the override carries `repoUrl` only — byte-identical to
|
|
195
|
+
* the PRD #581 behavior (same clone target: repo root, `main`). subPath and
|
|
196
|
+
* branch are populated ONLY for a non-empty value, so downstream defaults are
|
|
197
|
+
* untouched. The credential header is INERT unless a `?repo=` override is
|
|
198
|
+
* present: without a repo this returns `override: undefined` before the token
|
|
199
|
+
* is ever read, so the env-var path is unaffected by a forwarded header.
|
|
200
|
+
*
|
|
201
|
+
* Validation is delegated to getUserPromptsConfigFromOverride (scheme,
|
|
202
|
+
* sanitizeRelativePath for subPath, isValidGitBranch for branch) and happens
|
|
203
|
+
* BEFORE any clone or shared-cache mutation, so a rejected override can never
|
|
204
|
+
* corrupt the env-var-configured cache.
|
|
205
|
+
*/
|
|
206
|
+
function extractPromptsOverride(repoParam, pathParam, branchParam, gitToken, sourceParam) {
|
|
207
|
+
// PRD #647 D1: an explicit `?source=<identifier>` selects an already-ingested
|
|
208
|
+
// (CLI-uploaded) source. It is the explicit ingested signal, so it takes
|
|
209
|
+
// precedence over `?repo=` and the clone-qualifying params (path/branch/token)
|
|
210
|
+
// do not apply — they only describe a git clone, which an ingested source is
|
|
211
|
+
// not. Resolution against the in-memory ingested cache (and the "never clone"
|
|
212
|
+
// guarantee) happens in loadUserPrompts via override.ingestedSource. The raw
|
|
213
|
+
// identifier doubles as repoUrl ONLY so computePromptsSource echoes the
|
|
214
|
+
// scrubbed source; it is never cloned or logged unscrubbed on this path.
|
|
215
|
+
if (typeof sourceParam === 'string' && sourceParam.trim() !== '') {
|
|
216
|
+
const identifier = sourceParam.trim();
|
|
217
|
+
return {
|
|
218
|
+
ok: true,
|
|
219
|
+
override: { repoUrl: identifier, ingestedSource: identifier },
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
// Treat absent (null/undefined) repo as no override. path/branch/token only
|
|
223
|
+
// qualify an override, so without a repo they are ignored (the credential
|
|
224
|
+
// header is inert on the env-var path).
|
|
225
|
+
if (repoParam === undefined || repoParam === null) {
|
|
226
|
+
return { ok: true, override: undefined };
|
|
227
|
+
}
|
|
228
|
+
// The wire contract says `repo` is a string. Anything else (array,
|
|
229
|
+
// number, object, boolean) is a 400 — otherwise downstream code
|
|
230
|
+
// would crash to a 500.
|
|
231
|
+
if (typeof repoParam !== 'string') {
|
|
232
|
+
return {
|
|
233
|
+
ok: false,
|
|
234
|
+
message: `repo must be a string (got ${Array.isArray(repoParam) ? 'array' : typeof repoParam})`,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
const trimmed = repoParam.trim();
|
|
238
|
+
if (!trimmed) {
|
|
239
|
+
return { ok: true, override: undefined };
|
|
240
|
+
}
|
|
241
|
+
const candidate = { repoUrl: trimmed };
|
|
242
|
+
// PRD #621 M1: thread ?path= / body `path` into subPath (validated
|
|
243
|
+
// downstream by sanitizeRelativePath).
|
|
244
|
+
const pathResult = coerceOverrideStringParam(pathParam, 'path');
|
|
245
|
+
if (!pathResult.ok) {
|
|
246
|
+
return pathResult;
|
|
247
|
+
}
|
|
248
|
+
if (pathResult.value !== undefined) {
|
|
249
|
+
candidate.subPath = pathResult.value;
|
|
250
|
+
}
|
|
251
|
+
// PRD #621 M1: thread ?branch= / body `branch` into branch (validated
|
|
252
|
+
// downstream by isValidGitBranch).
|
|
253
|
+
const branchResult = coerceOverrideStringParam(branchParam, 'branch');
|
|
254
|
+
if (!branchResult.ok) {
|
|
255
|
+
return branchResult;
|
|
256
|
+
}
|
|
257
|
+
if (branchResult.value !== undefined) {
|
|
258
|
+
candidate.branch = branchResult.value;
|
|
259
|
+
}
|
|
260
|
+
// PRD #621 M2: the X-Dot-AI-Git-Token header (read by the handler and passed
|
|
261
|
+
// in already-normalized to a non-empty string or undefined) authenticates
|
|
262
|
+
// THIS override clone. It travels only as a header — never query/body — and
|
|
263
|
+
// is never echoed (computePromptsSource uses repoUrl only).
|
|
264
|
+
if (gitToken) {
|
|
265
|
+
candidate.gitToken = gitToken;
|
|
266
|
+
}
|
|
267
|
+
try {
|
|
268
|
+
// Throws on invalid scheme / subPath / branch.
|
|
269
|
+
(0, user_prompts_loader_1.getUserPromptsConfigFromOverride)(candidate);
|
|
270
|
+
return { ok: true, override: candidate };
|
|
271
|
+
}
|
|
272
|
+
catch (error) {
|
|
273
|
+
const raw = error instanceof Error ? error.message : 'Invalid override';
|
|
274
|
+
return { ok: false, message: (0, git_utils_1.scrubCredentials)(raw) };
|
|
275
|
+
}
|
|
276
|
+
}
|
|
111
277
|
/**
|
|
112
278
|
* HTTP status codes for REST responses
|
|
113
279
|
*/
|
|
@@ -245,6 +411,7 @@ class RestApiRouter {
|
|
|
245
411
|
'GET:/api/v1/logs': () => this.handleGetLogs(req, res, requestId, searchParams),
|
|
246
412
|
'GET:/api/v1/prompts': () => this.handlePromptsListRequest(req, res, requestId, searchParams),
|
|
247
413
|
'POST:/api/v1/prompts/refresh': () => this.handlePromptsCacheRefresh(req, res, requestId, body),
|
|
414
|
+
'POST:/api/v1/prompts/sources': () => this.handlePromptsSourceIngest(req, res, requestId, body),
|
|
248
415
|
'POST:/api/v1/prompts/:promptName': () => this.handlePromptsGetRequest(req, res, requestId, params.promptName, body, searchParams),
|
|
249
416
|
'GET:/api/v1/visualize/:sessionId': () => this.handleVisualize(req, res, requestId, params.sessionId, searchParams),
|
|
250
417
|
'GET:/api/v1/events/remediations': () => this.handleRemediationSSE(req, res, requestId),
|
|
@@ -1086,53 +1253,21 @@ class RestApiRouter {
|
|
|
1086
1253
|
await this.sendErrorResponse(res, requestId, HttpStatus.INTERNAL_SERVER_ERROR, 'LOGS_ERROR', 'Failed to retrieve logs', { error: errorMessage });
|
|
1087
1254
|
}
|
|
1088
1255
|
}
|
|
1089
|
-
/**
|
|
1090
|
-
* Extract and validate the per-request `repo` override (PRD #581).
|
|
1091
|
-
*
|
|
1092
|
-
* Returns:
|
|
1093
|
-
* - { ok: true, override } when no repo param is supplied, override is undefined.
|
|
1094
|
-
* - { ok: true, override } when a syntactically valid override URL is supplied.
|
|
1095
|
-
* - { ok: false, message } when the override fails validation (HTTP 400).
|
|
1096
|
-
*
|
|
1097
|
-
* The validation message is run through scrubCredentials so embedded tokens
|
|
1098
|
-
* never reach the wire response.
|
|
1099
|
-
*/
|
|
1100
|
-
extractPromptsOverride(repoParam) {
|
|
1101
|
-
// Treat absent (null/undefined) as no override.
|
|
1102
|
-
if (repoParam === undefined || repoParam === null) {
|
|
1103
|
-
return { ok: true, override: undefined };
|
|
1104
|
-
}
|
|
1105
|
-
// The wire contract says `repo` is a string. Anything else (array,
|
|
1106
|
-
// number, object, boolean) is a 400 — otherwise downstream code
|
|
1107
|
-
// would crash to a 500.
|
|
1108
|
-
if (typeof repoParam !== 'string') {
|
|
1109
|
-
return {
|
|
1110
|
-
ok: false,
|
|
1111
|
-
message: `repo must be a string (got ${Array.isArray(repoParam) ? 'array' : typeof repoParam})`,
|
|
1112
|
-
};
|
|
1113
|
-
}
|
|
1114
|
-
const trimmed = repoParam.trim();
|
|
1115
|
-
if (!trimmed) {
|
|
1116
|
-
return { ok: true, override: undefined };
|
|
1117
|
-
}
|
|
1118
|
-
const candidate = { repoUrl: trimmed };
|
|
1119
|
-
try {
|
|
1120
|
-
// Throws on invalid scheme / subPath / branch.
|
|
1121
|
-
(0, user_prompts_loader_1.getUserPromptsConfigFromOverride)(candidate);
|
|
1122
|
-
return { ok: true, override: candidate };
|
|
1123
|
-
}
|
|
1124
|
-
catch (error) {
|
|
1125
|
-
const raw = error instanceof Error ? error.message : 'Invalid override';
|
|
1126
|
-
return { ok: false, message: (0, git_utils_1.scrubCredentials)(raw) };
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
1256
|
/**
|
|
1130
1257
|
* Handle prompts list requests
|
|
1131
1258
|
*/
|
|
1132
1259
|
async handlePromptsListRequest(req, res, requestId, searchParams) {
|
|
1133
1260
|
try {
|
|
1134
1261
|
this.logger.info('Processing prompts list request', { requestId });
|
|
1135
|
-
|
|
1262
|
+
// PRD #581: ?repo= override. PRD #621 M1: ?path= / ?branch= thread into
|
|
1263
|
+
// candidate.subPath / candidate.branch (absent → unchanged behavior).
|
|
1264
|
+
// PRD #621 M2: X-Dot-AI-Git-Token header authenticates the override clone
|
|
1265
|
+
// (inert when no ?repo= override is present).
|
|
1266
|
+
// PRD #647 list-by-source: ?source= selects an already-ingested source,
|
|
1267
|
+
// resolved from the in-memory upload cache with no git operation (same
|
|
1268
|
+
// signal as the render path). Absent → byte-identical to today (env-var /
|
|
1269
|
+
// built-in set), so the no-?source= behavior is unchanged.
|
|
1270
|
+
const overrideResult = extractPromptsOverride(searchParams.get('repo'), searchParams.get('path'), searchParams.get('branch'), readGitTokenHeader(req), searchParams.get('source'));
|
|
1136
1271
|
if (!overrideResult.ok) {
|
|
1137
1272
|
await this.sendErrorResponse(res, requestId, HttpStatus.BAD_REQUEST, 'VALIDATION_ERROR', overrideResult.message);
|
|
1138
1273
|
return;
|
|
@@ -1154,6 +1289,24 @@ class RestApiRouter {
|
|
|
1154
1289
|
});
|
|
1155
1290
|
}
|
|
1156
1291
|
catch (error) {
|
|
1292
|
+
// A per-request override (?repo=) whose source can't be loaded is a
|
|
1293
|
+
// bad-gateway condition, not a server fault: surface it (issue #575)
|
|
1294
|
+
// instead of silently serving built-in prompts with HTTP 200. The
|
|
1295
|
+
// message is already credential-scrubbed by the loader.
|
|
1296
|
+
if (error instanceof user_prompts_loader_1.UserPromptsOverrideError) {
|
|
1297
|
+
await this.sendErrorResponse(res, requestId, HttpStatus.BAD_GATEWAY, 'PROMPTS_SOURCE_ERROR', error.message);
|
|
1298
|
+
return;
|
|
1299
|
+
}
|
|
1300
|
+
// PRD #647 list-by-source (D2): an unknown/evicted ?source= identifier is
|
|
1301
|
+
// a caller-actionable validation error — surface the re-upload guidance as
|
|
1302
|
+
// a 400 (same mapping the render handler uses), NOT a generic 500 or a
|
|
1303
|
+
// silent success-with-builtins. The message names POST
|
|
1304
|
+
// /api/v1/prompts/sources and carries no clone/git/scheme vocabulary.
|
|
1305
|
+
const listErrorMessage = error instanceof Error ? error.message : String(error);
|
|
1306
|
+
if (listErrorMessage.includes('Ingested source not found')) {
|
|
1307
|
+
await this.sendErrorResponse(res, requestId, HttpStatus.BAD_REQUEST, 'VALIDATION_ERROR', listErrorMessage);
|
|
1308
|
+
return;
|
|
1309
|
+
}
|
|
1157
1310
|
this.logger.error('Prompts list request failed', error instanceof Error ? error : new Error(String(error)), {
|
|
1158
1311
|
requestId,
|
|
1159
1312
|
});
|
|
@@ -1169,7 +1322,15 @@ class RestApiRouter {
|
|
|
1169
1322
|
requestId,
|
|
1170
1323
|
promptName,
|
|
1171
1324
|
});
|
|
1172
|
-
|
|
1325
|
+
// PRD #581: ?repo= override. PRD #621 M1: ?path= / ?branch= thread into
|
|
1326
|
+
// candidate.subPath / candidate.branch (absent → unchanged behavior).
|
|
1327
|
+
// PRD #621 M2: X-Dot-AI-Git-Token header authenticates the override clone
|
|
1328
|
+
// (inert when no ?repo= override is present).
|
|
1329
|
+
// PRD #647 D1/M3: ?source= selects an already-ingested source, resolved
|
|
1330
|
+
// from the in-memory upload cache with no git operation (precedence over
|
|
1331
|
+
// ?repo=). Absent → unchanged behavior, so the env-var/clone paths are
|
|
1332
|
+
// byte-identical to today.
|
|
1333
|
+
const overrideResult = extractPromptsOverride(searchParams.get('repo'), searchParams.get('path'), searchParams.get('branch'), readGitTokenHeader(req), searchParams.get('source'));
|
|
1173
1334
|
if (!overrideResult.ok) {
|
|
1174
1335
|
await this.sendErrorResponse(res, requestId, HttpStatus.BAD_REQUEST, 'VALIDATION_ERROR', overrideResult.message);
|
|
1175
1336
|
return;
|
|
@@ -1192,14 +1353,24 @@ class RestApiRouter {
|
|
|
1192
1353
|
});
|
|
1193
1354
|
}
|
|
1194
1355
|
catch (error) {
|
|
1356
|
+
// A per-request override (?repo=) whose source can't be loaded is a
|
|
1357
|
+
// bad-gateway condition (issue #575); surface it before the generic
|
|
1358
|
+
// validation/500 mapping. The message is already credential-scrubbed.
|
|
1359
|
+
if (error instanceof user_prompts_loader_1.UserPromptsOverrideError) {
|
|
1360
|
+
await this.sendErrorResponse(res, requestId, HttpStatus.BAD_GATEWAY, 'PROMPTS_SOURCE_ERROR', error.message);
|
|
1361
|
+
return;
|
|
1362
|
+
}
|
|
1195
1363
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1196
1364
|
this.logger.error('Prompt get request failed', error instanceof Error ? error : new Error(String(error)), {
|
|
1197
1365
|
requestId,
|
|
1198
1366
|
promptName,
|
|
1199
1367
|
});
|
|
1200
|
-
// Check if it's a validation error (missing required arguments
|
|
1368
|
+
// Check if it's a validation error (missing required arguments, prompt not
|
|
1369
|
+
// found, or a missing ingested ?source= identifier — PRD #647 D2, which
|
|
1370
|
+
// carries re-upload guidance and must be a 400, not a 500).
|
|
1201
1371
|
const isValidationError = errorMessage.includes('Missing required arguments') ||
|
|
1202
|
-
errorMessage.includes('Prompt not found')
|
|
1372
|
+
errorMessage.includes('Prompt not found') ||
|
|
1373
|
+
errorMessage.includes('Ingested source not found');
|
|
1203
1374
|
await this.sendErrorResponse(res, requestId, isValidationError
|
|
1204
1375
|
? HttpStatus.BAD_REQUEST
|
|
1205
1376
|
: HttpStatus.INTERNAL_SERVER_ERROR, isValidationError ? 'VALIDATION_ERROR' : 'PROMPT_GET_ERROR', errorMessage);
|
|
@@ -1214,9 +1385,13 @@ class RestApiRouter {
|
|
|
1214
1385
|
requestId,
|
|
1215
1386
|
});
|
|
1216
1387
|
// body.repo type is checked inside extractPromptsOverride (it accepts
|
|
1217
|
-
// unknown and rejects non-string values with 400 — see F2).
|
|
1388
|
+
// unknown and rejects non-string values with 400 — see F2). PRD #621 M1:
|
|
1389
|
+
// body `path` / `branch` thread into candidate.subPath / candidate.branch
|
|
1390
|
+
// (absent → unchanged behavior); both are likewise type-checked.
|
|
1218
1391
|
const bodyObj = body;
|
|
1219
|
-
|
|
1392
|
+
// PRD #621 M2: the credential always travels as the X-Dot-AI-Git-Token
|
|
1393
|
+
// header — never the body — and is inert without a repo override.
|
|
1394
|
+
const overrideResult = extractPromptsOverride(bodyObj?.repo, bodyObj?.path, bodyObj?.branch, readGitTokenHeader(req));
|
|
1220
1395
|
if (!overrideResult.ok) {
|
|
1221
1396
|
await this.sendErrorResponse(res, requestId, HttpStatus.BAD_REQUEST, 'VALIDATION_ERROR', overrideResult.message);
|
|
1222
1397
|
return;
|
|
@@ -1244,10 +1419,67 @@ class RestApiRouter {
|
|
|
1244
1419
|
});
|
|
1245
1420
|
}
|
|
1246
1421
|
catch (error) {
|
|
1422
|
+
// A per-request override (body.repo) whose source can't be loaded is a
|
|
1423
|
+
// bad-gateway condition (issue #575); surface it instead of a generic
|
|
1424
|
+
// 500. The message is already credential-scrubbed by the loader.
|
|
1425
|
+
if (error instanceof user_prompts_loader_1.UserPromptsOverrideError) {
|
|
1426
|
+
await this.sendErrorResponse(res, requestId, HttpStatus.BAD_GATEWAY, 'PROMPTS_SOURCE_ERROR', error.message);
|
|
1427
|
+
return;
|
|
1428
|
+
}
|
|
1247
1429
|
this.logger.error('Prompts cache refresh failed', error instanceof Error ? error : new Error(String(error)), { requestId });
|
|
1248
1430
|
await this.sendErrorResponse(res, requestId, HttpStatus.INTERNAL_SERVER_ERROR, 'PROMPTS_CACHE_REFRESH_ERROR', 'Failed to refresh prompts cache');
|
|
1249
1431
|
}
|
|
1250
1432
|
}
|
|
1433
|
+
/**
|
|
1434
|
+
* Handle prompts source ingestion (PRD #647 M2).
|
|
1435
|
+
*
|
|
1436
|
+
* Accepts a JSON manifest { source, contentHash, files:[{path, content(base64),
|
|
1437
|
+
* mode}] }, base64-decodes and caches the uploaded skill source keyed by its
|
|
1438
|
+
* `source` identifier in the in-memory ingested cache. A later
|
|
1439
|
+
* POST /api/v1/prompts/:promptName?source=<identifier> renders it through the
|
|
1440
|
+
* existing render path with no git operation. The (scrubbed) source is echoed
|
|
1441
|
+
* back. Bearer-gated by the same checkBearerAuth path as every non-OpenAPI
|
|
1442
|
+
* request.
|
|
1443
|
+
*/
|
|
1444
|
+
async handlePromptsSourceIngest(req, res, requestId, body) {
|
|
1445
|
+
try {
|
|
1446
|
+
this.logger.info('Processing prompts source ingest request', {
|
|
1447
|
+
requestId,
|
|
1448
|
+
});
|
|
1449
|
+
// All fields are untrusted; ingestPromptsSource validates and decodes
|
|
1450
|
+
// them, throwing PromptsSourceValidationError (→ 400) on a malformed or
|
|
1451
|
+
// unsafe manifest before anything is cached.
|
|
1452
|
+
const manifest = body;
|
|
1453
|
+
const result = (0, user_prompts_loader_1.ingestPromptsSource)({
|
|
1454
|
+
source: manifest?.source,
|
|
1455
|
+
contentHash: manifest?.contentHash,
|
|
1456
|
+
files: manifest?.files,
|
|
1457
|
+
}, this.logger);
|
|
1458
|
+
const response = {
|
|
1459
|
+
success: true,
|
|
1460
|
+
data: result,
|
|
1461
|
+
meta: {
|
|
1462
|
+
timestamp: new Date().toISOString(),
|
|
1463
|
+
requestId,
|
|
1464
|
+
version: this.config.version,
|
|
1465
|
+
},
|
|
1466
|
+
};
|
|
1467
|
+
await this.sendJsonResponse(res, HttpStatus.OK, response);
|
|
1468
|
+
this.logger.info('Prompts source ingest completed', {
|
|
1469
|
+
requestId,
|
|
1470
|
+
source: result.source,
|
|
1471
|
+
fileCount: result.fileCount,
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
catch (error) {
|
|
1475
|
+
const isValidationError = error instanceof user_prompts_loader_1.PromptsSourceValidationError;
|
|
1476
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1477
|
+
this.logger.error('Prompts source ingest failed', error instanceof Error ? error : new Error(String(error)), { requestId });
|
|
1478
|
+
await this.sendErrorResponse(res, requestId, isValidationError
|
|
1479
|
+
? HttpStatus.BAD_REQUEST
|
|
1480
|
+
: HttpStatus.INTERNAL_SERVER_ERROR, isValidationError ? 'VALIDATION_ERROR' : 'PROMPTS_SOURCE_INGEST_ERROR', isValidationError ? errorMessage : 'Failed to ingest prompts source');
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1251
1483
|
/**
|
|
1252
1484
|
* Handle visualization requests (PRD #317)
|
|
1253
1485
|
* Returns structured visualization data for a query session
|
|
@@ -1599,7 +1831,9 @@ class RestApiRouter {
|
|
|
1599
1831
|
};
|
|
1600
1832
|
if (this.config.enableCors) {
|
|
1601
1833
|
headers['Access-Control-Allow-Origin'] = '*';
|
|
1602
|
-
|
|
1834
|
+
// R-2: use the shared allowlist (single source of truth in cors-headers.ts)
|
|
1835
|
+
// so the SSE preflight includes X-Dot-AI-Git-Token like every other route.
|
|
1836
|
+
headers['Access-Control-Allow-Headers'] = cors_headers_1.REST_CORS_ALLOW_HEADERS;
|
|
1603
1837
|
}
|
|
1604
1838
|
res.writeHead(HttpStatus.OK, headers);
|
|
1605
1839
|
this.logger.info('SSE connection established', { requestId });
|
|
@@ -2187,7 +2421,9 @@ class RestApiRouter {
|
|
|
2187
2421
|
setCorsHeaders(res) {
|
|
2188
2422
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
2189
2423
|
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');
|
|
2190
|
-
|
|
2424
|
+
// PRD #621 M2 / Decision 1: advertise the X-Dot-AI-Git-Token credential
|
|
2425
|
+
// header (shared with the mcp.ts allowlist via cors-headers.ts).
|
|
2426
|
+
res.setHeader('Access-Control-Allow-Headers', cors_headers_1.REST_CORS_ALLOW_HEADERS);
|
|
2191
2427
|
res.setHeader('Access-Control-Max-Age', '86400');
|
|
2192
2428
|
}
|
|
2193
2429
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/interfaces/routes/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/interfaces/routes/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAgN5E;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,eAAe,CAC5C,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,CACR,EA6XA,CAAC;AAEF;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAInE;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
|
|
@@ -286,8 +286,17 @@ exports.routeDefinitions = [
|
|
|
286
286
|
method: 'GET',
|
|
287
287
|
description: 'List all available prompts',
|
|
288
288
|
tags: ['Prompts'],
|
|
289
|
+
// PRD #647 list-by-source: declare the per-request query params the list
|
|
290
|
+
// endpoint accepts. `?source=` enumerates a previously-ingested source (no
|
|
291
|
+
// git clone); `?repo=`/`?path=`/`?branch=` are the existing git overrides.
|
|
292
|
+
query: schemas_1.PromptsListQuerySchema,
|
|
289
293
|
response: schemas_1.PromptsListResponseSchema,
|
|
290
294
|
errorResponses: {
|
|
295
|
+
// PRD #647 list-by-source (D2): an unknown/evicted ?source= identifier
|
|
296
|
+
// returns 400 VALIDATION_ERROR with re-upload guidance — same contract as
|
|
297
|
+
// the render endpoint's ?source= miss.
|
|
298
|
+
400: schemas_1.PromptValidationErrorSchema,
|
|
299
|
+
502: schemas_1.PromptsSourceErrorSchema,
|
|
291
300
|
500: schemas_1.InternalServerErrorSchema,
|
|
292
301
|
},
|
|
293
302
|
},
|
|
@@ -298,19 +307,45 @@ exports.routeDefinitions = [
|
|
|
298
307
|
tags: ['Prompts'],
|
|
299
308
|
response: schemas_1.PromptsCacheRefreshResponseSchema,
|
|
300
309
|
errorResponses: {
|
|
310
|
+
502: schemas_1.PromptsSourceErrorSchema,
|
|
301
311
|
500: schemas_1.PromptsCacheRefreshErrorSchema,
|
|
302
312
|
},
|
|
303
313
|
},
|
|
314
|
+
{
|
|
315
|
+
path: '/api/v1/prompts/sources',
|
|
316
|
+
method: 'POST',
|
|
317
|
+
description: 'Ingest (upload) a skill source the server caches and renders via POST /api/v1/prompts/:promptName?source=<identifier> with no git clone (PRD #647)',
|
|
318
|
+
tags: ['Prompts'],
|
|
319
|
+
body: schemas_1.PromptsSourceIngestRequestSchema,
|
|
320
|
+
response: schemas_1.PromptsSourceIngestResponseSchema,
|
|
321
|
+
errorResponses: {
|
|
322
|
+
400: schemas_1.PromptsSourceIngestErrorSchema,
|
|
323
|
+
// PRD #647 A7/A9 (CodeRabbit): the 512 KiB raw-body cap returns 413
|
|
324
|
+
// (PAYLOAD_TOO_LARGE) from mcp.ts before route dispatch — document it.
|
|
325
|
+
413: schemas_1.PromptsSourceIngestPayloadTooLargeErrorSchema,
|
|
326
|
+
// PRD #647 A8 (CodeRabbit): narrowed to the only 500 code this handler
|
|
327
|
+
// emits, instead of the shared broad InternalServerErrorSchema union.
|
|
328
|
+
500: schemas_1.PromptsSourceIngestServerErrorSchema,
|
|
329
|
+
},
|
|
330
|
+
},
|
|
304
331
|
{
|
|
305
332
|
path: '/api/v1/prompts/:promptName',
|
|
306
333
|
method: 'POST',
|
|
307
334
|
description: 'Get a prompt with rendered template arguments',
|
|
308
335
|
tags: ['Prompts'],
|
|
309
336
|
params: PromptNameParamsSchema,
|
|
337
|
+
// PRD #647 A6 (CodeRabbit): declare the per-request render query params
|
|
338
|
+
// (?source= ingest-render, plus ?repo=/?path=/?branch= overrides).
|
|
339
|
+
query: schemas_1.PromptGetQuerySchema,
|
|
310
340
|
body: schemas_1.PromptGetRequestSchema,
|
|
311
341
|
response: schemas_1.PromptGetResponseSchema,
|
|
312
342
|
errorResponses: {
|
|
343
|
+
// PRD #647 (CodeRabbit): the render handler returns 400 VALIDATION_ERROR
|
|
344
|
+
// when ?source= resolution fails (unresolvable ingested source → D2) or
|
|
345
|
+
// required arguments are missing — document that contract.
|
|
346
|
+
400: schemas_1.PromptValidationErrorSchema,
|
|
313
347
|
404: schemas_1.PromptNotFoundErrorSchema,
|
|
348
|
+
502: schemas_1.PromptsSourceErrorSchema,
|
|
314
349
|
500: schemas_1.InternalServerErrorSchema,
|
|
315
350
|
},
|
|
316
351
|
},
|
|
@@ -119,6 +119,23 @@ export declare const MethodNotAllowedErrorSchema: z.ZodObject<{
|
|
|
119
119
|
code: z.ZodLiteral<"METHOD_NOT_ALLOWED">;
|
|
120
120
|
}, z.core.$strip>;
|
|
121
121
|
}, z.core.$strip>;
|
|
122
|
+
/**
|
|
123
|
+
* 413 returned when a request body exceeds a per-route raw-body cap (PRD #647:
|
|
124
|
+
* the 512 KiB prompts source ingest cap). The handler emits PAYLOAD_TOO_LARGE.
|
|
125
|
+
*/
|
|
126
|
+
export declare const PayloadTooLargeErrorSchema: z.ZodObject<{
|
|
127
|
+
success: z.ZodLiteral<false>;
|
|
128
|
+
meta: z.ZodOptional<z.ZodObject<{
|
|
129
|
+
timestamp: z.ZodString;
|
|
130
|
+
requestId: z.ZodOptional<z.ZodString>;
|
|
131
|
+
version: z.ZodString;
|
|
132
|
+
}, z.core.$strip>>;
|
|
133
|
+
error: z.ZodObject<{
|
|
134
|
+
message: z.ZodString;
|
|
135
|
+
details: z.ZodOptional<z.ZodAny>;
|
|
136
|
+
code: z.ZodLiteral<"PAYLOAD_TOO_LARGE">;
|
|
137
|
+
}, z.core.$strip>;
|
|
138
|
+
}, z.core.$strip>;
|
|
122
139
|
export declare const ServiceUnavailableErrorSchema: z.ZodObject<{
|
|
123
140
|
success: z.ZodLiteral<false>;
|
|
124
141
|
meta: z.ZodOptional<z.ZodObject<{
|
|
@@ -137,6 +154,21 @@ export declare const ServiceUnavailableErrorSchema: z.ZodObject<{
|
|
|
137
154
|
}>;
|
|
138
155
|
}, z.core.$strip>;
|
|
139
156
|
}, z.core.$strip>;
|
|
157
|
+
export declare const BadGatewayErrorSchema: z.ZodObject<{
|
|
158
|
+
success: z.ZodLiteral<false>;
|
|
159
|
+
meta: z.ZodOptional<z.ZodObject<{
|
|
160
|
+
timestamp: z.ZodString;
|
|
161
|
+
requestId: z.ZodOptional<z.ZodString>;
|
|
162
|
+
version: z.ZodString;
|
|
163
|
+
}, z.core.$strip>>;
|
|
164
|
+
error: z.ZodObject<{
|
|
165
|
+
message: z.ZodString;
|
|
166
|
+
details: z.ZodOptional<z.ZodAny>;
|
|
167
|
+
code: z.ZodEnum<{
|
|
168
|
+
PROMPTS_SOURCE_ERROR: "PROMPTS_SOURCE_ERROR";
|
|
169
|
+
}>;
|
|
170
|
+
}, z.core.$strip>;
|
|
171
|
+
}, z.core.$strip>;
|
|
140
172
|
export declare const InternalServerErrorSchema: z.ZodObject<{
|
|
141
173
|
success: z.ZodLiteral<false>;
|
|
142
174
|
meta: z.ZodOptional<z.ZodObject<{
|
|
@@ -166,6 +198,7 @@ export declare const InternalServerErrorSchema: z.ZodObject<{
|
|
|
166
198
|
SESSION_RETRIEVAL_ERROR: "SESSION_RETRIEVAL_ERROR";
|
|
167
199
|
MIGRATION_ERROR: "MIGRATION_ERROR";
|
|
168
200
|
PROMPTS_CACHE_REFRESH_ERROR: "PROMPTS_CACHE_REFRESH_ERROR";
|
|
201
|
+
PROMPTS_SOURCE_INGEST_ERROR: "PROMPTS_SOURCE_INGEST_ERROR";
|
|
169
202
|
USER_MANAGEMENT_ERROR: "USER_MANAGEMENT_ERROR";
|
|
170
203
|
}>;
|
|
171
204
|
}, z.core.$strip>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../src/interfaces/schemas/common.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,UAAU;;;;iBAOrB,CAAC;AAEH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAE9C;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;;iBAI7B,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D;;;GAGG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;iBAOhC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EAChE,UAAU,EAAE,CAAC;;;;;;;;kBAOd;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;iBAI9B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;iBAI9B,CAAC;AAEH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;iBAUhC,CAAC;AAEH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;iBAItC,CAAC;AAEH,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;iBASxC,CAAC;AAEH,eAAO,MAAM,yBAAyB
|
|
1
|
+
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../src/interfaces/schemas/common.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,UAAU;;;;iBAOrB,CAAC;AAEH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAE9C;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;;iBAI7B,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D;;;GAGG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;iBAOhC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EAChE,UAAU,EAAE,CAAC;;;;;;;;kBAOd;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;iBAI9B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;iBAI9B,CAAC;AAEH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;iBAUhC,CAAC;AAEH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;iBAItC,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;iBAIrC,CAAC;AAEH,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;iBASxC,CAAC;AAEH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;iBAQhC,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAyBpC,CAAC"}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* PRD #354: REST API Route Registry with Auto-Generated OpenAPI and Test Fixtures
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.InternalServerErrorSchema = exports.ServiceUnavailableErrorSchema = exports.MethodNotAllowedErrorSchema = exports.BadRequestErrorSchema = exports.NotFoundErrorSchema = exports.ErrorResponseSchema = exports.RestApiResponseSchema = exports.ErrorDetailsSchema = exports.MetaSchema = void 0;
|
|
9
|
+
exports.InternalServerErrorSchema = exports.BadGatewayErrorSchema = exports.ServiceUnavailableErrorSchema = exports.PayloadTooLargeErrorSchema = exports.MethodNotAllowedErrorSchema = exports.BadRequestErrorSchema = exports.NotFoundErrorSchema = exports.ErrorResponseSchema = exports.RestApiResponseSchema = exports.ErrorDetailsSchema = exports.MetaSchema = void 0;
|
|
10
10
|
exports.createSuccessResponseSchema = createSuccessResponseSchema;
|
|
11
11
|
const zod_1 = require("zod");
|
|
12
12
|
/**
|
|
@@ -80,6 +80,15 @@ exports.MethodNotAllowedErrorSchema = exports.ErrorResponseSchema.extend({
|
|
|
80
80
|
code: zod_1.z.literal('METHOD_NOT_ALLOWED'),
|
|
81
81
|
}),
|
|
82
82
|
});
|
|
83
|
+
/**
|
|
84
|
+
* 413 returned when a request body exceeds a per-route raw-body cap (PRD #647:
|
|
85
|
+
* the 512 KiB prompts source ingest cap). The handler emits PAYLOAD_TOO_LARGE.
|
|
86
|
+
*/
|
|
87
|
+
exports.PayloadTooLargeErrorSchema = exports.ErrorResponseSchema.extend({
|
|
88
|
+
error: exports.ErrorDetailsSchema.extend({
|
|
89
|
+
code: zod_1.z.literal('PAYLOAD_TOO_LARGE'),
|
|
90
|
+
}),
|
|
91
|
+
});
|
|
83
92
|
exports.ServiceUnavailableErrorSchema = exports.ErrorResponseSchema.extend({
|
|
84
93
|
error: exports.ErrorDetailsSchema.extend({
|
|
85
94
|
code: zod_1.z.enum([
|
|
@@ -90,6 +99,15 @@ exports.ServiceUnavailableErrorSchema = exports.ErrorResponseSchema.extend({
|
|
|
90
99
|
]),
|
|
91
100
|
}),
|
|
92
101
|
});
|
|
102
|
+
exports.BadGatewayErrorSchema = exports.ErrorResponseSchema.extend({
|
|
103
|
+
error: exports.ErrorDetailsSchema.extend({
|
|
104
|
+
code: zod_1.z.enum([
|
|
105
|
+
// A per-request prompts-repo override (?repo=) whose source could not be
|
|
106
|
+
// cloned — bad/missing forwarded credential or unreachable host (issue #575).
|
|
107
|
+
'PROMPTS_SOURCE_ERROR',
|
|
108
|
+
]),
|
|
109
|
+
}),
|
|
110
|
+
});
|
|
93
111
|
exports.InternalServerErrorSchema = exports.ErrorResponseSchema.extend({
|
|
94
112
|
error: exports.ErrorDetailsSchema.extend({
|
|
95
113
|
code: zod_1.z.enum([
|
|
@@ -111,6 +129,7 @@ exports.InternalServerErrorSchema = exports.ErrorResponseSchema.extend({
|
|
|
111
129
|
'SESSION_RETRIEVAL_ERROR',
|
|
112
130
|
'MIGRATION_ERROR',
|
|
113
131
|
'PROMPTS_CACHE_REFRESH_ERROR',
|
|
132
|
+
'PROMPTS_SOURCE_INGEST_ERROR',
|
|
114
133
|
'USER_MANAGEMENT_ERROR',
|
|
115
134
|
]),
|
|
116
135
|
}),
|