veryfront 0.1.83 → 0.1.85
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/esm/cli/commands/knowledge/command.d.ts +10 -13
- package/esm/cli/commands/knowledge/command.d.ts.map +1 -1
- package/esm/cli/commands/knowledge/command.js +294 -110
- package/esm/cli/commands/knowledge/parser-source.d.ts.map +1 -1
- package/esm/cli/commands/knowledge/parser-source.js +52 -0
- package/esm/cli/commands/knowledge/result.d.ts +54 -0
- package/esm/cli/commands/knowledge/result.d.ts.map +1 -0
- package/esm/cli/commands/knowledge/result.js +22 -0
- package/esm/cli/commands/knowledge/source-policy.d.ts +11 -0
- package/esm/cli/commands/knowledge/source-policy.d.ts.map +1 -0
- package/esm/cli/commands/knowledge/source-policy.js +135 -0
- package/esm/deno.js +1 -1
- package/esm/src/jobs/index.d.ts +1 -1
- package/esm/src/jobs/index.d.ts.map +1 -1
- package/esm/src/jobs/index.js +1 -1
- package/esm/src/jobs/schemas.d.ts +1104 -185
- package/esm/src/jobs/schemas.d.ts.map +1 -1
- package/esm/src/jobs/schemas.js +81 -8
- package/esm/src/proxy/error-response.d.ts +7 -0
- package/esm/src/proxy/error-response.d.ts.map +1 -0
- package/esm/src/proxy/error-response.js +26 -0
- package/esm/src/proxy/handler.d.ts.map +1 -1
- package/esm/src/proxy/handler.js +25 -0
- package/esm/src/proxy/main.js +2 -23
- package/esm/src/rendering/orchestrator/css-candidate-manifest.d.ts +11 -0
- package/esm/src/rendering/orchestrator/css-candidate-manifest.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/css-candidate-manifest.js +23 -12
- package/esm/src/server/handlers/dev/styles-candidate-scanner.d.ts.map +1 -1
- package/esm/src/server/handlers/dev/styles-candidate-scanner.js +25 -8
- package/esm/src/server/handlers/dev/styles-css.handler.d.ts +1 -0
- package/esm/src/server/handlers/dev/styles-css.handler.d.ts.map +1 -1
- package/esm/src/server/handlers/dev/styles-css.handler.js +15 -5
- package/esm/src/transforms/esm/http-cache-helpers.d.ts.map +1 -1
- package/esm/src/transforms/esm/http-cache-helpers.js +7 -1
- package/esm/src/transforms/import-rewriter/strategies/bare-strategy.d.ts.map +1 -1
- package/esm/src/transforms/import-rewriter/strategies/bare-strategy.js +11 -8
- package/esm/src/transforms/shared/package-specifier.d.ts +7 -0
- package/esm/src/transforms/shared/package-specifier.d.ts.map +1 -0
- package/esm/src/transforms/shared/package-specifier.js +19 -0
- package/package.json +1 -1
- package/src/cli/commands/knowledge/command.ts +375 -139
- package/src/cli/commands/knowledge/parser-source.ts +52 -0
- package/src/cli/commands/knowledge/result.ts +88 -0
- package/src/cli/commands/knowledge/source-policy.ts +164 -0
- package/src/deno.js +1 -1
- package/src/src/jobs/index.ts +16 -0
- package/src/src/jobs/schemas.ts +105 -8
- package/src/src/proxy/error-response.ts +33 -0
- package/src/src/proxy/handler.ts +43 -0
- package/src/src/proxy/main.ts +2 -27
- package/src/src/rendering/orchestrator/css-candidate-manifest.ts +40 -14
- package/src/src/server/handlers/dev/styles-candidate-scanner.ts +37 -11
- package/src/src/server/handlers/dev/styles-css.handler.ts +25 -4
- package/src/src/transforms/esm/http-cache-helpers.ts +12 -1
- package/src/src/transforms/import-rewriter/strategies/bare-strategy.ts +11 -12
- package/src/src/transforms/shared/package-specifier.ts +29 -0
|
@@ -14,6 +14,53 @@ def yaml_quote(value: Any) -> str:
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
CODE_FENCE = chr(96) * 3
|
|
17
|
+
TEXT_FILE_EXTENSIONS = {
|
|
18
|
+
".c",
|
|
19
|
+
".cc",
|
|
20
|
+
".conf",
|
|
21
|
+
".cpp",
|
|
22
|
+
".cs",
|
|
23
|
+
".css",
|
|
24
|
+
".go",
|
|
25
|
+
".h",
|
|
26
|
+
".hpp",
|
|
27
|
+
".ini",
|
|
28
|
+
".java",
|
|
29
|
+
".js",
|
|
30
|
+
".jsonl",
|
|
31
|
+
".jsx",
|
|
32
|
+
".kt",
|
|
33
|
+
".less",
|
|
34
|
+
".lua",
|
|
35
|
+
".mjs",
|
|
36
|
+
".ndjson",
|
|
37
|
+
".php",
|
|
38
|
+
".pl",
|
|
39
|
+
".py",
|
|
40
|
+
".r",
|
|
41
|
+
".rb",
|
|
42
|
+
".rs",
|
|
43
|
+
".sass",
|
|
44
|
+
".scala",
|
|
45
|
+
".scss",
|
|
46
|
+
".sh",
|
|
47
|
+
".sql",
|
|
48
|
+
".swift",
|
|
49
|
+
".toml",
|
|
50
|
+
".ts",
|
|
51
|
+
".tsx",
|
|
52
|
+
".xml",
|
|
53
|
+
".yaml",
|
|
54
|
+
".yml",
|
|
55
|
+
".zsh",
|
|
56
|
+
}
|
|
57
|
+
TEXT_FILE_NAMES = {
|
|
58
|
+
"dockerfile",
|
|
59
|
+
"makefile",
|
|
60
|
+
"readme",
|
|
61
|
+
"license",
|
|
62
|
+
"changelog",
|
|
63
|
+
}
|
|
17
64
|
|
|
18
65
|
|
|
19
66
|
def slugify(value: str) -> str:
|
|
@@ -406,6 +453,7 @@ def parse_json(path: str):
|
|
|
406
453
|
|
|
407
454
|
def select_parser(path: Path):
|
|
408
455
|
ext = path.suffix.lower()
|
|
456
|
+
name = path.name.lower()
|
|
409
457
|
if ext == ".pdf":
|
|
410
458
|
return "pdf", prefer_kreuzberg("pdf", parse_pdf)
|
|
411
459
|
if ext in {".csv", ".tsv"}:
|
|
@@ -424,6 +472,10 @@ def select_parser(path: Path):
|
|
|
424
472
|
return ext.lstrip("."), parse_text
|
|
425
473
|
if ext == ".json":
|
|
426
474
|
return "json", parse_json
|
|
475
|
+
if ext in TEXT_FILE_EXTENSIONS:
|
|
476
|
+
return ext.lstrip("."), parse_text
|
|
477
|
+
if not ext and name in TEXT_FILE_NAMES:
|
|
478
|
+
return "text", parse_text
|
|
427
479
|
raise ValueError(f"Unsupported file type: {ext}")
|
|
428
480
|
|
|
429
481
|
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
export type KnowledgeIngestSkipReason =
|
|
2
|
+
| "hidden_path"
|
|
3
|
+
| "ignored_directory"
|
|
4
|
+
| "unsupported_file_type";
|
|
5
|
+
|
|
6
|
+
export type KnowledgeIngestFailureReason =
|
|
7
|
+
| "parser_error"
|
|
8
|
+
| "upload_error";
|
|
9
|
+
|
|
10
|
+
export interface KnowledgeIngestFileResult {
|
|
11
|
+
source: string;
|
|
12
|
+
localSourcePath: string;
|
|
13
|
+
outputPath: string;
|
|
14
|
+
remotePath: string;
|
|
15
|
+
slug: string;
|
|
16
|
+
sourceType: string;
|
|
17
|
+
summary: string;
|
|
18
|
+
stats: Record<string, unknown>;
|
|
19
|
+
warnings: string[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface KnowledgeIngestSkippedFileResult {
|
|
23
|
+
source: string;
|
|
24
|
+
localSourcePath: string | null;
|
|
25
|
+
reason: KnowledgeIngestSkipReason;
|
|
26
|
+
message: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface KnowledgeIngestFailedFileResult {
|
|
30
|
+
source: string;
|
|
31
|
+
localSourcePath: string;
|
|
32
|
+
reason: KnowledgeIngestFailureReason;
|
|
33
|
+
message: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface KnowledgeIngestSummary {
|
|
37
|
+
requested_count: number;
|
|
38
|
+
ingested_count: number;
|
|
39
|
+
skipped_count: number;
|
|
40
|
+
failed_count: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface KnowledgeIngestResultMetadata {
|
|
44
|
+
requested_count: number;
|
|
45
|
+
source_mode: "explicit_sources" | "path_prefix";
|
|
46
|
+
knowledge_path: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface KnowledgeIngestJobResult {
|
|
50
|
+
kind: "knowledge_ingest";
|
|
51
|
+
version: 1;
|
|
52
|
+
metadata: KnowledgeIngestResultMetadata;
|
|
53
|
+
summary: KnowledgeIngestSummary;
|
|
54
|
+
ingested: KnowledgeIngestFileResult[];
|
|
55
|
+
skipped: KnowledgeIngestSkippedFileResult[];
|
|
56
|
+
failed: KnowledgeIngestFailedFileResult[];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function buildKnowledgeIngestJobResult(input: {
|
|
60
|
+
requestedCount: number;
|
|
61
|
+
sourceMode: KnowledgeIngestResultMetadata["source_mode"];
|
|
62
|
+
knowledgePath: string;
|
|
63
|
+
ingested: KnowledgeIngestFileResult[];
|
|
64
|
+
skipped?: KnowledgeIngestSkippedFileResult[];
|
|
65
|
+
failed?: KnowledgeIngestFailedFileResult[];
|
|
66
|
+
}): KnowledgeIngestJobResult {
|
|
67
|
+
const skipped = input.skipped ?? [];
|
|
68
|
+
const failed = input.failed ?? [];
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
kind: "knowledge_ingest",
|
|
72
|
+
version: 1,
|
|
73
|
+
metadata: {
|
|
74
|
+
requested_count: input.requestedCount,
|
|
75
|
+
source_mode: input.sourceMode,
|
|
76
|
+
knowledge_path: input.knowledgePath,
|
|
77
|
+
},
|
|
78
|
+
summary: {
|
|
79
|
+
requested_count: input.requestedCount,
|
|
80
|
+
ingested_count: input.ingested.length,
|
|
81
|
+
skipped_count: skipped.length,
|
|
82
|
+
failed_count: failed.length,
|
|
83
|
+
},
|
|
84
|
+
ingested: input.ingested,
|
|
85
|
+
skipped,
|
|
86
|
+
failed,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { basename, extname, normalize } from "../../../src/platform/compat/path/index.js";
|
|
2
|
+
import type { KnowledgeIngestSkipReason } from "./result.js";
|
|
3
|
+
|
|
4
|
+
const RICH_FILE_EXTENSIONS = new Set([
|
|
5
|
+
".pdf",
|
|
6
|
+
".csv",
|
|
7
|
+
".tsv",
|
|
8
|
+
".docx",
|
|
9
|
+
".xlsx",
|
|
10
|
+
".xls",
|
|
11
|
+
".pptx",
|
|
12
|
+
".html",
|
|
13
|
+
".htm",
|
|
14
|
+
".txt",
|
|
15
|
+
".json",
|
|
16
|
+
".md",
|
|
17
|
+
".mdx",
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
const TEXT_FALLBACK_EXTENSIONS = new Set([
|
|
21
|
+
".c",
|
|
22
|
+
".cc",
|
|
23
|
+
".conf",
|
|
24
|
+
".cpp",
|
|
25
|
+
".cs",
|
|
26
|
+
".css",
|
|
27
|
+
".go",
|
|
28
|
+
".h",
|
|
29
|
+
".hpp",
|
|
30
|
+
".ini",
|
|
31
|
+
".java",
|
|
32
|
+
".js",
|
|
33
|
+
".jsonl",
|
|
34
|
+
".jsx",
|
|
35
|
+
".kt",
|
|
36
|
+
".less",
|
|
37
|
+
".lua",
|
|
38
|
+
".mjs",
|
|
39
|
+
".ndjson",
|
|
40
|
+
".php",
|
|
41
|
+
".pl",
|
|
42
|
+
".py",
|
|
43
|
+
".r",
|
|
44
|
+
".rb",
|
|
45
|
+
".rs",
|
|
46
|
+
".sass",
|
|
47
|
+
".scala",
|
|
48
|
+
".scss",
|
|
49
|
+
".sh",
|
|
50
|
+
".sql",
|
|
51
|
+
".swift",
|
|
52
|
+
".toml",
|
|
53
|
+
".tsx",
|
|
54
|
+
".ts",
|
|
55
|
+
".xml",
|
|
56
|
+
".yaml",
|
|
57
|
+
".yml",
|
|
58
|
+
".zsh",
|
|
59
|
+
]);
|
|
60
|
+
|
|
61
|
+
const TEXT_FALLBACK_FILENAMES = new Set([
|
|
62
|
+
"dockerfile",
|
|
63
|
+
"makefile",
|
|
64
|
+
"readme",
|
|
65
|
+
"license",
|
|
66
|
+
"changelog",
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
const IGNORED_DIRECTORY_NAMES = new Set([
|
|
70
|
+
"node_modules",
|
|
71
|
+
]);
|
|
72
|
+
|
|
73
|
+
export type KnowledgeIngestSourceDecision =
|
|
74
|
+
| { kind: "ingest" }
|
|
75
|
+
| {
|
|
76
|
+
kind: "skip";
|
|
77
|
+
reason: KnowledgeIngestSkipReason;
|
|
78
|
+
message: string;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
function normalizePathSegments(value: string): string[] {
|
|
82
|
+
return normalize(value)
|
|
83
|
+
.replaceAll("\\", "/")
|
|
84
|
+
.split("/")
|
|
85
|
+
.map((segment) => segment.trim())
|
|
86
|
+
.filter((segment) => segment.length > 0 && segment !== "." && segment !== "..");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function findHiddenSegment(segments: string[]): string | null {
|
|
90
|
+
for (const segment of segments) {
|
|
91
|
+
if (segment.startsWith(".")) {
|
|
92
|
+
return segment;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function findIgnoredDirectory(segments: string[]): string | null {
|
|
100
|
+
for (const segment of segments) {
|
|
101
|
+
if (IGNORED_DIRECTORY_NAMES.has(segment.toLowerCase())) {
|
|
102
|
+
return segment;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function isSupportedKnowledgeFile(path: string): boolean {
|
|
110
|
+
const extension = extname(path).toLowerCase();
|
|
111
|
+
if (
|
|
112
|
+
extension && (RICH_FILE_EXTENSIONS.has(extension) || TEXT_FALLBACK_EXTENSIONS.has(extension))
|
|
113
|
+
) {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const fileName = basename(path).toLowerCase();
|
|
118
|
+
return TEXT_FALLBACK_FILENAMES.has(fileName);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function classifyCommonKnowledgePath(path: string): KnowledgeIngestSourceDecision | null {
|
|
122
|
+
const segments = normalizePathSegments(path);
|
|
123
|
+
const hiddenSegment = findHiddenSegment(segments);
|
|
124
|
+
if (hiddenSegment != null) {
|
|
125
|
+
return {
|
|
126
|
+
kind: "skip",
|
|
127
|
+
reason: "hidden_path",
|
|
128
|
+
message: `Hidden file or directory skipped: ${hiddenSegment}`,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const ignoredDirectory = findIgnoredDirectory(segments);
|
|
133
|
+
if (ignoredDirectory != null) {
|
|
134
|
+
return {
|
|
135
|
+
kind: "skip",
|
|
136
|
+
reason: "ignored_directory",
|
|
137
|
+
message: `Ignored directory skipped: ${ignoredDirectory}`,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function classifyKnowledgeDirectoryPath(path: string): KnowledgeIngestSourceDecision {
|
|
145
|
+
return classifyCommonKnowledgePath(path) ?? { kind: "ingest" };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function classifyKnowledgeSourcePath(path: string): KnowledgeIngestSourceDecision {
|
|
149
|
+
const commonDecision = classifyCommonKnowledgePath(path);
|
|
150
|
+
if (commonDecision != null) {
|
|
151
|
+
return commonDecision;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (!isSupportedKnowledgeFile(path)) {
|
|
155
|
+
const extension = extname(path).toLowerCase();
|
|
156
|
+
return {
|
|
157
|
+
kind: "skip",
|
|
158
|
+
reason: "unsupported_file_type",
|
|
159
|
+
message: `Unsupported file type: ${extension || basename(path)}`,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return { kind: "ingest" };
|
|
164
|
+
}
|
package/src/deno.js
CHANGED
package/src/src/jobs/index.ts
CHANGED
|
@@ -60,10 +60,16 @@ export {
|
|
|
60
60
|
JobEventSchema,
|
|
61
61
|
type JobEventsResponse,
|
|
62
62
|
JobEventsResponseSchema,
|
|
63
|
+
type JobKind,
|
|
64
|
+
JobKindSchema,
|
|
65
|
+
type JobListItem,
|
|
66
|
+
JobListItemSchema,
|
|
63
67
|
type JobLogsResponse,
|
|
64
68
|
JobLogsResponseSchema,
|
|
65
69
|
type JobResult,
|
|
66
70
|
JobResultSchema,
|
|
71
|
+
type JobResultSummary,
|
|
72
|
+
JobResultSummarySchema,
|
|
67
73
|
JobSchema,
|
|
68
74
|
type JobStatus,
|
|
69
75
|
JobStatusSchema,
|
|
@@ -73,8 +79,18 @@ export {
|
|
|
73
79
|
JobTargetDefinitionsResponseSchema,
|
|
74
80
|
type KnowledgeIngestBatchSource,
|
|
75
81
|
KnowledgeIngestBatchSourceSchema,
|
|
82
|
+
type KnowledgeIngestBatchSourceWithMessage,
|
|
83
|
+
KnowledgeIngestBatchSourceWithMessageSchema,
|
|
84
|
+
type KnowledgeIngestFailedFileResult,
|
|
85
|
+
KnowledgeIngestFailedFileResultSchema,
|
|
76
86
|
type KnowledgeIngestFileResult,
|
|
77
87
|
KnowledgeIngestFileResultSchema,
|
|
88
|
+
type KnowledgeIngestJobResult,
|
|
89
|
+
KnowledgeIngestJobResultCountsSchema,
|
|
90
|
+
KnowledgeIngestJobResultMetadataSchema,
|
|
91
|
+
KnowledgeIngestJobResultSchema,
|
|
92
|
+
type KnowledgeIngestSkippedFileResult,
|
|
93
|
+
KnowledgeIngestSkippedFileResultSchema,
|
|
78
94
|
PageInfoSchema,
|
|
79
95
|
type PaginatedCronJobsResponse,
|
|
80
96
|
PaginatedCronJobsResponseSchema,
|
package/src/src/jobs/schemas.ts
CHANGED
|
@@ -9,6 +9,7 @@ export const JobStatusSchema = z.enum([
|
|
|
9
9
|
]);
|
|
10
10
|
|
|
11
11
|
export const CronJobStatusSchema = z.enum(["active", "paused", "deleting"]);
|
|
12
|
+
export const JobKindSchema = z.enum(["knowledge_ingest"]).nullable();
|
|
12
13
|
|
|
13
14
|
export const ReservedJobTargetFamilySchema = z.enum(["task:*", "workflow:*", "deploy:*"]);
|
|
14
15
|
|
|
@@ -20,6 +21,12 @@ export const PageInfoSchema = z.object({
|
|
|
20
21
|
});
|
|
21
22
|
|
|
22
23
|
const JsonObjectSchema = z.record(z.unknown());
|
|
24
|
+
const KnowledgeIngestSkipReasonSchema = z.enum([
|
|
25
|
+
"hidden_path",
|
|
26
|
+
"ignored_directory",
|
|
27
|
+
"unsupported_file_type",
|
|
28
|
+
]);
|
|
29
|
+
const KnowledgeIngestFailureReasonSchema = z.enum(["parser_error", "upload_error"]);
|
|
23
30
|
|
|
24
31
|
export const KnowledgeIngestFileResultSchema = z.object({
|
|
25
32
|
source: z.string(),
|
|
@@ -33,27 +40,82 @@ export const KnowledgeIngestFileResultSchema = z.object({
|
|
|
33
40
|
warnings: z.array(z.string()),
|
|
34
41
|
});
|
|
35
42
|
|
|
43
|
+
export const KnowledgeIngestSkippedFileResultSchema = z.object({
|
|
44
|
+
source: z.string(),
|
|
45
|
+
localSourcePath: z.string().nullable(),
|
|
46
|
+
reason: KnowledgeIngestSkipReasonSchema,
|
|
47
|
+
message: z.string(),
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export const KnowledgeIngestFailedFileResultSchema = z.object({
|
|
51
|
+
source: z.string(),
|
|
52
|
+
localSourcePath: z.string(),
|
|
53
|
+
reason: KnowledgeIngestFailureReasonSchema,
|
|
54
|
+
message: z.string(),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
export const KnowledgeIngestJobResultMetadataSchema = z.object({
|
|
58
|
+
requested_count: z.number().int().nonnegative(),
|
|
59
|
+
source_mode: z.enum(["explicit_sources", "path_prefix"]),
|
|
60
|
+
knowledge_path: z.string(),
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
export const KnowledgeIngestJobResultCountsSchema = z.object({
|
|
64
|
+
requested_count: z.number().int().nonnegative(),
|
|
65
|
+
ingested_count: z.number().int().nonnegative(),
|
|
66
|
+
skipped_count: z.number().int().nonnegative(),
|
|
67
|
+
failed_count: z.number().int().nonnegative(),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
export const KnowledgeIngestJobResultSchema = z.object({
|
|
71
|
+
kind: z.literal("knowledge_ingest"),
|
|
72
|
+
version: z.literal(1),
|
|
73
|
+
metadata: KnowledgeIngestJobResultMetadataSchema,
|
|
74
|
+
summary: KnowledgeIngestJobResultCountsSchema,
|
|
75
|
+
ingested: z.array(KnowledgeIngestFileResultSchema),
|
|
76
|
+
skipped: z.array(KnowledgeIngestSkippedFileResultSchema),
|
|
77
|
+
failed: z.array(KnowledgeIngestFailedFileResultSchema),
|
|
78
|
+
});
|
|
79
|
+
|
|
36
80
|
export const JobResultSchema = z
|
|
81
|
+
.discriminatedUnion("kind", [
|
|
82
|
+
KnowledgeIngestJobResultSchema,
|
|
83
|
+
z.object({
|
|
84
|
+
kind: z.literal("value"),
|
|
85
|
+
value: z.unknown(),
|
|
86
|
+
}),
|
|
87
|
+
z.object({
|
|
88
|
+
kind: z.literal("artifacts"),
|
|
89
|
+
artifacts: z.array(z.unknown()),
|
|
90
|
+
}),
|
|
91
|
+
])
|
|
92
|
+
.nullable();
|
|
93
|
+
|
|
94
|
+
export const JobResultSummarySchema = z
|
|
37
95
|
.discriminatedUnion("kind", [
|
|
38
96
|
z.object({
|
|
39
97
|
kind: z.literal("knowledge_ingest"),
|
|
40
|
-
|
|
98
|
+
state: z.enum(["success", "partial_success", "failed"]),
|
|
99
|
+
requested_count: z.number().int().nonnegative(),
|
|
100
|
+
ingested_count: z.number().int().nonnegative(),
|
|
101
|
+
skipped_count: z.number().int().nonnegative(),
|
|
102
|
+
failed_count: z.number().int().nonnegative(),
|
|
41
103
|
}),
|
|
42
104
|
z.object({
|
|
43
105
|
kind: z.literal("value"),
|
|
44
|
-
value: z.unknown(),
|
|
45
106
|
}),
|
|
46
107
|
z.object({
|
|
47
108
|
kind: z.literal("artifacts"),
|
|
48
|
-
|
|
109
|
+
artifact_count: z.number().int().nonnegative(),
|
|
49
110
|
}),
|
|
50
111
|
])
|
|
51
112
|
.nullable();
|
|
52
113
|
|
|
53
|
-
|
|
114
|
+
const BaseJobSchema = z.object({
|
|
54
115
|
id: z.string().uuid(),
|
|
55
116
|
project_id: z.string().uuid(),
|
|
56
117
|
environment_id: z.string().uuid().nullable(),
|
|
118
|
+
branch_id: z.string().nullable().optional().default(null),
|
|
57
119
|
cron_job_id: z.string().uuid().nullable(),
|
|
58
120
|
batch_id: z.string().uuid().nullable(),
|
|
59
121
|
name: z.string(),
|
|
@@ -64,9 +126,6 @@ export const JobSchema = z.object({
|
|
|
64
126
|
timeout_seconds: z.number(),
|
|
65
127
|
backoff_limit: z.number(),
|
|
66
128
|
exit_code: z.number().nullable(),
|
|
67
|
-
failed_reason: z.string().nullable(),
|
|
68
|
-
failure_detail: z.string().nullable(),
|
|
69
|
-
result: JobResultSchema,
|
|
70
129
|
started_at: z.string().nullable(),
|
|
71
130
|
completed_at: z.string().nullable(),
|
|
72
131
|
created_by: z.string().uuid().nullable(),
|
|
@@ -74,8 +133,22 @@ export const JobSchema = z.object({
|
|
|
74
133
|
updated_at: z.string(),
|
|
75
134
|
});
|
|
76
135
|
|
|
136
|
+
export const JobSchema = BaseJobSchema.extend({
|
|
137
|
+
failed_reason: z.string().nullable().optional().default(null),
|
|
138
|
+
kind: JobKindSchema.optional().default(null),
|
|
139
|
+
failure_detail: z.string().nullable().optional().default(null),
|
|
140
|
+
result_summary: JobResultSummarySchema.optional().default(null),
|
|
141
|
+
result: JobResultSchema.optional().default(null),
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
export const JobListItemSchema = BaseJobSchema.extend({
|
|
145
|
+
kind: JobKindSchema.optional().default(null),
|
|
146
|
+
failure_detail: z.string().nullable().optional().default(null),
|
|
147
|
+
result_summary: JobResultSummarySchema.optional().default(null),
|
|
148
|
+
});
|
|
149
|
+
|
|
77
150
|
export const PaginatedJobsResponseSchema = z.object({
|
|
78
|
-
data: z.array(
|
|
151
|
+
data: z.array(JobListItemSchema),
|
|
79
152
|
page_info: PageInfoSchema,
|
|
80
153
|
});
|
|
81
154
|
|
|
@@ -111,6 +184,10 @@ export const KnowledgeIngestBatchSourceSchema = z.object({
|
|
|
111
184
|
warning_count: z.number().int().nonnegative(),
|
|
112
185
|
});
|
|
113
186
|
|
|
187
|
+
export const KnowledgeIngestBatchSourceWithMessageSchema = KnowledgeIngestBatchSourceSchema.extend({
|
|
188
|
+
message: z.string(),
|
|
189
|
+
});
|
|
190
|
+
|
|
114
191
|
export const JobBatchStatusCountsSchema = z.object({
|
|
115
192
|
submitted: z.number().int().nonnegative(),
|
|
116
193
|
working: z.number().int().nonnegative(),
|
|
@@ -125,8 +202,12 @@ export const JobBatchResultSchema = z
|
|
|
125
202
|
kind: z.literal("knowledge_ingest"),
|
|
126
203
|
total_count: z.number().int().nonnegative(),
|
|
127
204
|
completed_count: z.number().int().nonnegative(),
|
|
205
|
+
skipped_count: z.number().int().nonnegative(),
|
|
206
|
+
failed_count: z.number().int().nonnegative(),
|
|
128
207
|
processing: z.array(KnowledgeIngestBatchSourceSchema),
|
|
129
208
|
completed: z.array(KnowledgeIngestBatchSourceSchema),
|
|
209
|
+
skipped: z.array(KnowledgeIngestBatchSourceWithMessageSchema),
|
|
210
|
+
failed: z.array(KnowledgeIngestBatchSourceWithMessageSchema),
|
|
130
211
|
remaining: z.array(KnowledgeIngestBatchSourceSchema),
|
|
131
212
|
remaining_label: z.enum(["Remaining Files", "Not Ingested Files"]),
|
|
132
213
|
}),
|
|
@@ -161,6 +242,7 @@ export const CronJobSchema = z.object({
|
|
|
161
242
|
id: z.string().uuid(),
|
|
162
243
|
project_id: z.string().uuid(),
|
|
163
244
|
environment_id: z.string().uuid().nullable(),
|
|
245
|
+
branch_id: z.string().nullable().optional().default(null),
|
|
164
246
|
name: z.string(),
|
|
165
247
|
status: CronJobStatusSchema,
|
|
166
248
|
target: z.string(),
|
|
@@ -184,17 +266,32 @@ export const PaginatedCronJobsResponseSchema = z.object({
|
|
|
184
266
|
|
|
185
267
|
export type JobStatus = z.infer<typeof JobStatusSchema>;
|
|
186
268
|
export type CronJobStatus = z.infer<typeof CronJobStatusSchema>;
|
|
269
|
+
export type JobKind = z.infer<typeof JobKindSchema>;
|
|
187
270
|
export type ReservedJobTargetFamily = z.infer<typeof ReservedJobTargetFamilySchema>;
|
|
188
271
|
|
|
189
272
|
export type KnowledgeIngestFileResult = z.infer<typeof KnowledgeIngestFileResultSchema>;
|
|
273
|
+
export type KnowledgeIngestSkippedFileResult = z.infer<
|
|
274
|
+
typeof KnowledgeIngestSkippedFileResultSchema
|
|
275
|
+
>;
|
|
276
|
+
export type KnowledgeIngestFailedFileResult = z.infer<typeof KnowledgeIngestFailedFileResultSchema>;
|
|
277
|
+
export type KnowledgeIngestJobResultMetadata = z.infer<
|
|
278
|
+
typeof KnowledgeIngestJobResultMetadataSchema
|
|
279
|
+
>;
|
|
280
|
+
export type KnowledgeIngestJobResultCounts = z.infer<typeof KnowledgeIngestJobResultCountsSchema>;
|
|
281
|
+
export type KnowledgeIngestJobResult = z.infer<typeof KnowledgeIngestJobResultSchema>;
|
|
190
282
|
export type JobResult = z.infer<typeof JobResultSchema>;
|
|
283
|
+
export type JobResultSummary = z.infer<typeof JobResultSummarySchema>;
|
|
191
284
|
export type Job = z.infer<typeof JobSchema>;
|
|
285
|
+
export type JobListItem = z.infer<typeof JobListItemSchema>;
|
|
192
286
|
export type PaginatedJobsResponse = z.infer<typeof PaginatedJobsResponseSchema>;
|
|
193
287
|
export type JobEvent = z.infer<typeof JobEventSchema>;
|
|
194
288
|
export type JobEventsResponse = z.infer<typeof JobEventsResponseSchema>;
|
|
195
289
|
export type JobLogsResponse = z.infer<typeof JobLogsResponseSchema>;
|
|
196
290
|
|
|
197
291
|
export type KnowledgeIngestBatchSource = z.infer<typeof KnowledgeIngestBatchSourceSchema>;
|
|
292
|
+
export type KnowledgeIngestBatchSourceWithMessage = z.infer<
|
|
293
|
+
typeof KnowledgeIngestBatchSourceWithMessageSchema
|
|
294
|
+
>;
|
|
198
295
|
export type JobBatchStatusCounts = z.infer<typeof JobBatchStatusCountsSchema>;
|
|
199
296
|
export type JobBatchResult = z.infer<typeof JobBatchResultSchema>;
|
|
200
297
|
export type JobBatch = z.infer<typeof JobBatchSchema>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as dntShim from "../../_dnt.shims.js";
|
|
2
|
+
import { ErrorPages } from "../server/utils/error-html.js";
|
|
3
|
+
import type { ProxyContext } from "./handler.js";
|
|
4
|
+
|
|
5
|
+
type ProxyError = NonNullable<ProxyContext["error"]>;
|
|
6
|
+
|
|
7
|
+
export function jsonErrorResponse(status: number, body: Record<string, unknown>): dntShim.Response {
|
|
8
|
+
return new dntShim.Response(JSON.stringify(body), {
|
|
9
|
+
status,
|
|
10
|
+
headers: { "Content-Type": "application/json" },
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function createProxyErrorResponse(error: ProxyError): dntShim.Response {
|
|
15
|
+
if (error.redirectUrl) {
|
|
16
|
+
return new dntShim.Response(null, {
|
|
17
|
+
status: 302,
|
|
18
|
+
headers: { Location: error.redirectUrl },
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (error.slug === "release-not-found" || error.slug === "project-not-found") {
|
|
23
|
+
return new dntShim.Response(ErrorPages.notFound(), {
|
|
24
|
+
status: 404,
|
|
25
|
+
headers: { "Content-Type": "text/html; charset=utf-8" },
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return jsonErrorResponse(error.status, {
|
|
30
|
+
error: error.message,
|
|
31
|
+
status: error.status,
|
|
32
|
+
});
|
|
33
|
+
}
|
package/src/src/proxy/handler.ts
CHANGED
|
@@ -175,6 +175,12 @@ function extractUserToken(cookieHeader: string): string | undefined {
|
|
|
175
175
|
return match?.[1] ? decodeURIComponent(match[1]) : undefined;
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
+
function getStatusFromError(error: unknown): number | null {
|
|
179
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
180
|
+
const match = message.match(/failed: (\d+)/);
|
|
181
|
+
return match ? Number(match[1]) : null;
|
|
182
|
+
}
|
|
183
|
+
|
|
178
184
|
async function extractUserIdFromToken(
|
|
179
185
|
token: string,
|
|
180
186
|
apiBaseUrl: string,
|
|
@@ -461,6 +467,7 @@ export function createProxyHandler(options: ProxyHandlerOptions) {
|
|
|
461
467
|
const userToken = extractUserToken(cookieHeader);
|
|
462
468
|
|
|
463
469
|
let token: string | undefined;
|
|
470
|
+
let tokenFetchError: unknown;
|
|
464
471
|
|
|
465
472
|
if (isLocalProject) {
|
|
466
473
|
logger?.debug("Local project, skipping token fetch", { localPath });
|
|
@@ -476,6 +483,7 @@ export function createProxyHandler(options: ProxyHandlerOptions) {
|
|
|
476
483
|
try {
|
|
477
484
|
token = await tokenManager.getToken(scope, projectSlug, customDomain);
|
|
478
485
|
} catch (error) {
|
|
486
|
+
tokenFetchError = error;
|
|
479
487
|
logger?.error("Token fetch failed", error as Error, { projectSlug, customDomain });
|
|
480
488
|
}
|
|
481
489
|
}
|
|
@@ -488,6 +496,29 @@ export function createProxyHandler(options: ProxyHandlerOptions) {
|
|
|
488
496
|
|
|
489
497
|
const base = { scope, host, parsedDomain };
|
|
490
498
|
|
|
499
|
+
if (projectSlug && scope === "preview" && !token) {
|
|
500
|
+
const status = getStatusFromError(tokenFetchError);
|
|
501
|
+
if (status === 404) {
|
|
502
|
+
logger?.info("Preview project not found", { projectSlug, host });
|
|
503
|
+
return makeErrorContext(
|
|
504
|
+
base,
|
|
505
|
+
404,
|
|
506
|
+
"Preview project not found",
|
|
507
|
+
undefined,
|
|
508
|
+
undefined,
|
|
509
|
+
"project-not-found",
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
logger?.warn("Preview request has no usable token", {
|
|
514
|
+
projectSlug,
|
|
515
|
+
host,
|
|
516
|
+
hadUserToken: !!userToken,
|
|
517
|
+
hadTokenFetchError: !!tokenFetchError,
|
|
518
|
+
});
|
|
519
|
+
return makeErrorContext(base, 502, "Failed to authenticate preview request");
|
|
520
|
+
}
|
|
521
|
+
|
|
491
522
|
if (isCustomDomain && !projectSlug) {
|
|
492
523
|
if (!token) {
|
|
493
524
|
logger?.error("Cannot process custom domain without token", undefined, { domain: host });
|
|
@@ -590,6 +621,18 @@ export function createProxyHandler(options: ProxyHandlerOptions) {
|
|
|
590
621
|
);
|
|
591
622
|
}
|
|
592
623
|
|
|
624
|
+
if (!resolved.projectId) {
|
|
625
|
+
logger?.info("Preview project not found after lookup", { projectSlug, host });
|
|
626
|
+
return makeErrorContext(
|
|
627
|
+
base,
|
|
628
|
+
404,
|
|
629
|
+
"Preview project not found",
|
|
630
|
+
token,
|
|
631
|
+
undefined,
|
|
632
|
+
"project-not-found",
|
|
633
|
+
);
|
|
634
|
+
}
|
|
635
|
+
|
|
593
636
|
projectId = resolved.projectId;
|
|
594
637
|
environmentId = resolved.environmentId;
|
|
595
638
|
|