veryfront 0.1.71 → 0.1.73

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 (110) hide show
  1. package/esm/cli/commands/files/command-help.d.ts +3 -0
  2. package/esm/cli/commands/files/command-help.d.ts.map +1 -0
  3. package/esm/cli/commands/files/command-help.js +38 -0
  4. package/esm/cli/commands/files/command.d.ts +105 -0
  5. package/esm/cli/commands/files/command.d.ts.map +1 -0
  6. package/esm/cli/commands/files/command.js +250 -0
  7. package/esm/cli/commands/files/handler.d.ts +3 -0
  8. package/esm/cli/commands/files/handler.d.ts.map +1 -0
  9. package/esm/cli/commands/files/handler.js +4 -0
  10. package/esm/cli/commands/files/index.d.ts +4 -0
  11. package/esm/cli/commands/files/index.d.ts.map +1 -0
  12. package/esm/cli/commands/files/index.js +2 -0
  13. package/esm/cli/commands/knowledge/command-help.d.ts +3 -0
  14. package/esm/cli/commands/knowledge/command-help.d.ts.map +1 -0
  15. package/esm/cli/commands/knowledge/command-help.js +38 -0
  16. package/esm/cli/commands/knowledge/command.d.ts +122 -0
  17. package/esm/cli/commands/knowledge/command.d.ts.map +1 -0
  18. package/esm/cli/commands/knowledge/command.js +382 -0
  19. package/esm/cli/commands/knowledge/handler.d.ts +3 -0
  20. package/esm/cli/commands/knowledge/handler.d.ts.map +1 -0
  21. package/esm/cli/commands/knowledge/handler.js +4 -0
  22. package/esm/cli/commands/knowledge/index.d.ts +3 -0
  23. package/esm/cli/commands/knowledge/index.d.ts.map +1 -0
  24. package/esm/cli/commands/knowledge/index.js +2 -0
  25. package/esm/cli/commands/knowledge/parser-source.d.ts +2 -0
  26. package/esm/cli/commands/knowledge/parser-source.d.ts.map +1 -0
  27. package/esm/cli/commands/knowledge/parser-source.js +415 -0
  28. package/esm/cli/commands/uploads/command-help.d.ts +3 -0
  29. package/esm/cli/commands/uploads/command-help.d.ts.map +1 -0
  30. package/esm/cli/commands/uploads/command-help.js +43 -0
  31. package/esm/cli/commands/uploads/command.d.ts +140 -0
  32. package/esm/cli/commands/uploads/command.d.ts.map +1 -0
  33. package/esm/cli/commands/uploads/command.js +323 -0
  34. package/esm/cli/commands/uploads/handler.d.ts +3 -0
  35. package/esm/cli/commands/uploads/handler.d.ts.map +1 -0
  36. package/esm/cli/commands/uploads/handler.js +4 -0
  37. package/esm/cli/commands/uploads/index.d.ts +4 -0
  38. package/esm/cli/commands/uploads/index.d.ts.map +1 -0
  39. package/esm/cli/commands/uploads/index.js +2 -0
  40. package/esm/cli/help/command-definitions.d.ts.map +1 -1
  41. package/esm/cli/help/command-definitions.js +6 -0
  42. package/esm/cli/router.d.ts.map +1 -1
  43. package/esm/cli/router.js +6 -0
  44. package/esm/deno.js +1 -1
  45. package/esm/src/errors/error-registry.d.ts +2 -0
  46. package/esm/src/errors/error-registry.d.ts.map +1 -1
  47. package/esm/src/errors/error-registry.js +8 -0
  48. package/esm/src/errors/index.d.ts +1 -1
  49. package/esm/src/errors/index.d.ts.map +1 -1
  50. package/esm/src/errors/index.js +1 -1
  51. package/esm/src/html/html-shell-generator.d.ts.map +1 -1
  52. package/esm/src/html/html-shell-generator.js +6 -0
  53. package/esm/src/platform/compat/media-types.d.ts +5 -0
  54. package/esm/src/platform/compat/media-types.d.ts.map +1 -0
  55. package/esm/src/platform/compat/media-types.js +19 -0
  56. package/esm/src/platform/index.d.ts +1 -0
  57. package/esm/src/platform/index.d.ts.map +1 -1
  58. package/esm/src/platform/index.js +2 -0
  59. package/esm/src/rendering/orchestrator/pipeline.d.ts.map +1 -1
  60. package/esm/src/rendering/orchestrator/pipeline.js +116 -105
  61. package/esm/src/server/bootstrap.js +5 -1
  62. package/esm/src/server/dev-server/error-overlay/error-formatter.d.ts +4 -0
  63. package/esm/src/server/dev-server/error-overlay/error-formatter.d.ts.map +1 -1
  64. package/esm/src/server/dev-server/error-overlay/error-formatter.js +15 -0
  65. package/esm/src/server/dev-server/error-overlay/html-template.d.ts +1 -1
  66. package/esm/src/server/dev-server/error-overlay/html-template.d.ts.map +1 -1
  67. package/esm/src/server/dev-server/error-overlay/html-template.js +131 -8
  68. package/esm/src/server/dev-server/error-overlay/index.d.ts +1 -1
  69. package/esm/src/server/dev-server/error-overlay/index.d.ts.map +1 -1
  70. package/esm/src/server/dev-server/error-overlay/index.js +1 -1
  71. package/esm/src/server/dev-server/error-overlay/overlay-renderer.d.ts +1 -1
  72. package/esm/src/server/dev-server/error-overlay/overlay-renderer.d.ts.map +1 -1
  73. package/esm/src/server/dev-server/error-overlay/overlay-renderer.js +2 -2
  74. package/esm/src/server/dev-server/request-handler.d.ts.map +1 -1
  75. package/esm/src/server/dev-server/request-handler.js +6 -2
  76. package/esm/src/server/services/rendering/ssr.service.d.ts.map +1 -1
  77. package/esm/src/server/services/rendering/ssr.service.js +9 -2
  78. package/esm/src/server/utils/error-html.d.ts.map +1 -1
  79. package/esm/src/server/utils/error-html.js +26 -6
  80. package/package.json +2 -1
  81. package/src/cli/commands/files/command-help.ts +40 -0
  82. package/src/cli/commands/files/command.ts +328 -0
  83. package/src/cli/commands/files/handler.ts +6 -0
  84. package/src/cli/commands/files/index.ts +19 -0
  85. package/src/cli/commands/knowledge/command-help.ts +40 -0
  86. package/src/cli/commands/knowledge/command.ts +513 -0
  87. package/src/cli/commands/knowledge/handler.ts +6 -0
  88. package/src/cli/commands/knowledge/index.ts +2 -0
  89. package/src/cli/commands/knowledge/parser-source.ts +415 -0
  90. package/src/cli/commands/uploads/command-help.ts +45 -0
  91. package/src/cli/commands/uploads/command.ts +465 -0
  92. package/src/cli/commands/uploads/handler.ts +6 -0
  93. package/src/cli/commands/uploads/index.ts +23 -0
  94. package/src/cli/help/command-definitions.ts +6 -0
  95. package/src/cli/router.ts +6 -0
  96. package/src/deno.js +1 -1
  97. package/src/src/errors/error-registry.ts +9 -0
  98. package/src/src/errors/index.ts +1 -0
  99. package/src/src/html/html-shell-generator.ts +9 -0
  100. package/src/src/platform/compat/media-types.ts +23 -0
  101. package/src/src/platform/index.ts +3 -0
  102. package/src/src/rendering/orchestrator/pipeline.ts +186 -172
  103. package/src/src/server/bootstrap.ts +6 -1
  104. package/src/src/server/dev-server/error-overlay/error-formatter.ts +21 -0
  105. package/src/src/server/dev-server/error-overlay/html-template.ts +139 -8
  106. package/src/src/server/dev-server/error-overlay/index.ts +1 -0
  107. package/src/src/server/dev-server/error-overlay/overlay-renderer.ts +2 -1
  108. package/src/src/server/dev-server/request-handler.ts +6 -2
  109. package/src/src/server/services/rendering/ssr.service.ts +9 -2
  110. package/src/src/server/utils/error-html.ts +29 -6
@@ -0,0 +1,465 @@
1
+ import * as dntShim from "../../../_dnt.shims.js";
2
+ import { z } from "zod";
3
+ import { createFileSystem, cwd, lookupMimeType } from "../../../src/platform/index.js";
4
+ import { dirname, join, normalize, resolve } from "../../../src/platform/compat/path/index.js";
5
+ import { withSpan } from "../../../src/observability/tracing/otlp-setup.js";
6
+ import { cliLogger } from "../../utils/index.js";
7
+ import { type ApiClient, createApiClient, resolveConfigWithAuth } from "../../shared/config.js";
8
+ import type { ParsedArgs } from "../../shared/types.js";
9
+
10
+ export interface UploadItem {
11
+ type: "file" | "folder";
12
+ path: string;
13
+ file_name?: string;
14
+ size?: number;
15
+ content_type?: string | null;
16
+ status?: string;
17
+ visibility?: string;
18
+ created_at?: string;
19
+ updated_at?: string;
20
+ }
21
+
22
+ interface UploadsListResponse {
23
+ data: UploadItem[];
24
+ page_info?: {
25
+ next?: string | null;
26
+ prev?: string | null;
27
+ };
28
+ }
29
+
30
+ interface SignedUrlResponse {
31
+ signed_url: string;
32
+ expires_at: string;
33
+ }
34
+
35
+ interface CreateUploadResponse {
36
+ file_upload_url: string;
37
+ file_path: string;
38
+ upload_id: string;
39
+ required_headers: Record<string, string>;
40
+ }
41
+
42
+ const UploadListArgsSchema = z.object({
43
+ projectSlug: z.string().optional(),
44
+ projectDir: z.string().optional(),
45
+ path: z.string().optional(),
46
+ limit: z.coerce.number().min(1).max(100).optional(),
47
+ recursive: z.boolean().default(true),
48
+ json: z.boolean().default(false),
49
+ quiet: z.boolean().default(false),
50
+ });
51
+
52
+ export type UploadListOptions = z.infer<typeof UploadListArgsSchema>;
53
+
54
+ const UploadPullArgsSchema = z.object({
55
+ projectSlug: z.string().optional(),
56
+ projectDir: z.string().optional(),
57
+ uploads: z.array(z.string()).default([]),
58
+ path: z.string().optional(),
59
+ all: z.boolean().default(false),
60
+ outputDir: z.string().default(join(cwd(), "uploads")),
61
+ json: z.boolean().default(false),
62
+ quiet: z.boolean().default(false),
63
+ });
64
+
65
+ export type UploadPullOptions = z.infer<typeof UploadPullArgsSchema>;
66
+
67
+ const UploadPutArgsSchema = z.object({
68
+ projectSlug: z.string().optional(),
69
+ projectDir: z.string().optional(),
70
+ uploadPath: z.string().min(1),
71
+ from: z.string().min(1),
72
+ contentType: z.string().optional(),
73
+ json: z.boolean().default(false),
74
+ quiet: z.boolean().default(false),
75
+ });
76
+
77
+ export type UploadPutOptions = z.infer<typeof UploadPutArgsSchema>;
78
+
79
+ const UploadDeleteArgsSchema = z.object({
80
+ projectSlug: z.string().optional(),
81
+ projectDir: z.string().optional(),
82
+ uploadPath: z.string().min(1),
83
+ json: z.boolean().default(false),
84
+ quiet: z.boolean().default(false),
85
+ });
86
+
87
+ export type UploadDeleteOptions = z.infer<typeof UploadDeleteArgsSchema>;
88
+
89
+ function getStringArg(args: ParsedArgs, ...keys: string[]): string | undefined {
90
+ for (const key of keys) {
91
+ const value = args[key];
92
+ if (typeof value === "string" && value) return value;
93
+ }
94
+ return undefined;
95
+ }
96
+
97
+ function getBooleanArg(args: ParsedArgs, ...keys: string[]): boolean {
98
+ return keys.some((key) => Boolean(args[key]));
99
+ }
100
+
101
+ function printJson(value: unknown): void {
102
+ console.log(JSON.stringify(value, null, 2));
103
+ }
104
+
105
+ function formatUploadItem(item: UploadItem): string {
106
+ if (item.type === "folder") return `[folder] ${item.path}`;
107
+ const size = typeof item.size === "number" ? ` (${item.size} bytes)` : "";
108
+ return `[file] ${item.path}${size}`;
109
+ }
110
+
111
+ function showUploadsUsage(): void {
112
+ console.log(`
113
+ Veryfront Uploads
114
+
115
+ Usage:
116
+ veryfront uploads list [options]
117
+ veryfront uploads pull <upload-path...> [options]
118
+ veryfront uploads pull --path <prefix> --all [options]
119
+ veryfront uploads put <upload-path> --from <local-file> [options]
120
+ veryfront uploads delete <upload-path> [options]
121
+
122
+ Subcommands:
123
+ list List uploads in the project uploads store
124
+ pull Download one or many uploads into a local directory
125
+ put Upload or replace a file in the project uploads store
126
+ delete Delete an upload by path
127
+ `);
128
+ }
129
+
130
+ function normalizeUploadPath(uploadPath: string): string {
131
+ const normalizedPath = normalize(uploadPath).replace(/^\/+/, "");
132
+ if (!normalizedPath || normalizedPath.startsWith("..") || normalizedPath.startsWith("/")) {
133
+ throw new Error(`Invalid upload path: ${uploadPath}`);
134
+ }
135
+ return normalizedPath;
136
+ }
137
+
138
+ export function parseUploadsListArgs(
139
+ args: ParsedArgs,
140
+ ): z.SafeParseReturnType<unknown, UploadListOptions> {
141
+ return UploadListArgsSchema.safeParse({
142
+ projectSlug: getStringArg(args, "project", "p", "project-slug"),
143
+ projectDir: getStringArg(args, "project-dir", "dir", "d"),
144
+ path: getStringArg(args, "path"),
145
+ limit: args.limit,
146
+ recursive: args.recursive === undefined ? true : Boolean(args.recursive),
147
+ json: getBooleanArg(args, "json", "j"),
148
+ quiet: getBooleanArg(args, "quiet", "q"),
149
+ });
150
+ }
151
+
152
+ export function parseUploadsPullArgs(
153
+ args: ParsedArgs,
154
+ ): z.SafeParseReturnType<unknown, UploadPullOptions> {
155
+ return UploadPullArgsSchema.safeParse({
156
+ projectSlug: getStringArg(args, "project", "p", "project-slug"),
157
+ projectDir: getStringArg(args, "project-dir", "dir", "d"),
158
+ uploads: args._.slice(2).filter((value): value is string => typeof value === "string"),
159
+ path: getStringArg(args, "path"),
160
+ all: getBooleanArg(args, "all"),
161
+ outputDir: getStringArg(args, "output-dir") ?? join(cwd(), "uploads"),
162
+ json: getBooleanArg(args, "json", "j"),
163
+ quiet: getBooleanArg(args, "quiet", "q"),
164
+ });
165
+ }
166
+
167
+ export function parseUploadsPutArgs(
168
+ args: ParsedArgs,
169
+ ): z.SafeParseReturnType<unknown, UploadPutOptions> {
170
+ return UploadPutArgsSchema.safeParse({
171
+ projectSlug: getStringArg(args, "project", "p", "project-slug"),
172
+ projectDir: getStringArg(args, "project-dir", "dir", "d"),
173
+ uploadPath: typeof args._[2] === "string" ? args._[2] : "",
174
+ from: getStringArg(args, "from") ?? "",
175
+ contentType: getStringArg(args, "content-type"),
176
+ json: getBooleanArg(args, "json", "j"),
177
+ quiet: getBooleanArg(args, "quiet", "q"),
178
+ });
179
+ }
180
+
181
+ export function parseUploadsDeleteArgs(
182
+ args: ParsedArgs,
183
+ ): z.SafeParseReturnType<unknown, UploadDeleteOptions> {
184
+ return UploadDeleteArgsSchema.safeParse({
185
+ projectSlug: getStringArg(args, "project", "p", "project-slug"),
186
+ projectDir: getStringArg(args, "project-dir", "dir", "d"),
187
+ uploadPath: typeof args._[2] === "string" ? args._[2] : "",
188
+ json: getBooleanArg(args, "json", "j"),
189
+ quiet: getBooleanArg(args, "quiet", "q"),
190
+ });
191
+ }
192
+
193
+ export function buildUploadsListUrl(projectSlug: string): string {
194
+ return `/projects/${projectSlug}/uploads`;
195
+ }
196
+
197
+ export function buildUploadCreateUrl(projectSlug: string): string {
198
+ return `/projects/${projectSlug}/uploads`;
199
+ }
200
+
201
+ export function buildUploadSignedUrlPath(projectSlug: string, uploadPath: string): string {
202
+ return `/projects/${projectSlug}/uploads/${
203
+ encodeURIComponent(normalizeUploadPath(uploadPath))
204
+ }/url`;
205
+ }
206
+
207
+ function buildUploadDeleteUrl(projectSlug: string, uploadPath: string): string {
208
+ return `/projects/${projectSlug}/uploads/${encodeURIComponent(normalizeUploadPath(uploadPath))}`;
209
+ }
210
+
211
+ export async function listAllUploads(
212
+ client: ApiClient,
213
+ projectSlug: string,
214
+ options: Partial<Pick<UploadListOptions, "path" | "recursive" | "limit">> = {},
215
+ ): Promise<UploadItem[]> {
216
+ const allItems: UploadItem[] = [];
217
+ let cursor: string | undefined;
218
+
219
+ do {
220
+ const params: Record<string, string> = {
221
+ limit: String(options.limit ?? 100),
222
+ recursive: String(options.recursive ?? true),
223
+ };
224
+ if (options.path) params.path = options.path;
225
+ if (cursor) params.cursor = cursor;
226
+
227
+ const response = await client.get<UploadsListResponse>(
228
+ buildUploadsListUrl(projectSlug),
229
+ params,
230
+ );
231
+ allItems.push(...response.data);
232
+ cursor = response.page_info?.next ?? undefined;
233
+ } while (cursor);
234
+
235
+ return allItems;
236
+ }
237
+
238
+ export function resolveUploadOutputPath(uploadPath: string, outputDir: string): string {
239
+ const normalizedPath = normalizeUploadPath(uploadPath);
240
+ const fullPath = resolve(outputDir, normalizedPath);
241
+ const resolvedOutputDir = resolve(outputDir);
242
+
243
+ if (!fullPath.startsWith(`${resolvedOutputDir}/`) && fullPath !== resolvedOutputDir) {
244
+ throw new Error(`Invalid upload path: ${uploadPath}`);
245
+ }
246
+
247
+ return fullPath;
248
+ }
249
+
250
+ export async function downloadUploadToFile(
251
+ client: ApiClient,
252
+ projectSlug: string,
253
+ uploadPath: string,
254
+ outputDir: string,
255
+ ): Promise<{ uploadPath: string; localPath: string; bytes: number }> {
256
+ const fs = createFileSystem();
257
+ const signedUrl = await client.get<SignedUrlResponse>(
258
+ buildUploadSignedUrlPath(projectSlug, uploadPath),
259
+ );
260
+ const response = await dntShim.fetch(signedUrl.signed_url);
261
+
262
+ if (!response.ok) {
263
+ throw new Error(`Failed to download upload: ${uploadPath}`);
264
+ }
265
+
266
+ const bytes = new Uint8Array(await response.arrayBuffer());
267
+ const localPath = resolveUploadOutputPath(uploadPath, outputDir);
268
+ await fs.mkdir(dirname(localPath), { recursive: true });
269
+ await fs.writeFile(localPath, bytes);
270
+
271
+ return { uploadPath: normalizeUploadPath(uploadPath), localPath, bytes: bytes.byteLength };
272
+ }
273
+
274
+ export async function uploadLocalFileToUploads(
275
+ client: ApiClient,
276
+ projectSlug: string,
277
+ uploadPath: string,
278
+ localPath: string,
279
+ contentType?: string,
280
+ ): Promise<CreateUploadResponse> {
281
+ const fs = createFileSystem();
282
+ const normalizedPath = normalizeUploadPath(uploadPath);
283
+ const bytes = await fs.readFile(localPath);
284
+ const inferredContentType = contentType ?? lookupMimeType(localPath) ??
285
+ "application/octet-stream";
286
+ const createResponse = await client.post<CreateUploadResponse>(
287
+ buildUploadCreateUrl(projectSlug),
288
+ {
289
+ file_path: normalizedPath,
290
+ content_type: inferredContentType,
291
+ size: bytes.byteLength,
292
+ },
293
+ );
294
+
295
+ const uploadResponse = await dntShim.fetch(createResponse.file_upload_url, {
296
+ method: "PUT",
297
+ headers: createResponse.required_headers,
298
+ body: bytes as dntShim.BodyInit,
299
+ });
300
+
301
+ if (!uploadResponse.ok) {
302
+ throw new Error(`Failed to upload file to storage: ${normalizedPath}`);
303
+ }
304
+
305
+ return createResponse;
306
+ }
307
+
308
+ export async function deleteUpload(
309
+ client: ApiClient,
310
+ projectSlug: string,
311
+ uploadPath: string,
312
+ ): Promise<void> {
313
+ await client.delete(buildUploadDeleteUrl(projectSlug, uploadPath));
314
+ }
315
+
316
+ export async function uploadsCommand(args: ParsedArgs): Promise<void> {
317
+ const subcommand = typeof args._[1] === "string" ? args._[1] : undefined;
318
+
319
+ if (!subcommand || subcommand === "help") {
320
+ showUploadsUsage();
321
+ return;
322
+ }
323
+
324
+ await withSpan("cli.command.uploads", async () => {
325
+ switch (subcommand) {
326
+ case "list": {
327
+ const parsed = parseUploadsListArgs(args);
328
+ if (!parsed.success) {
329
+ throw new Error(`Invalid uploads list arguments: ${parsed.error.message}`);
330
+ }
331
+
332
+ const options = parsed.data;
333
+ let config = await resolveConfigWithAuth(options.projectDir);
334
+ if (options.projectSlug) config = { ...config, projectSlug: options.projectSlug };
335
+
336
+ const client = createApiClient(config);
337
+ const uploads = await listAllUploads(client, config.projectSlug, options);
338
+
339
+ if (options.json) {
340
+ printJson(uploads);
341
+ return;
342
+ }
343
+
344
+ if (!uploads.length) {
345
+ cliLogger.info("No uploads found.");
346
+ return;
347
+ }
348
+
349
+ for (const upload of uploads) {
350
+ console.log(formatUploadItem(upload));
351
+ }
352
+ return;
353
+ }
354
+
355
+ case "pull": {
356
+ const parsed = parseUploadsPullArgs(args);
357
+ if (!parsed.success) {
358
+ throw new Error(`Invalid uploads pull arguments: ${parsed.error.message}`);
359
+ }
360
+
361
+ const options = parsed.data;
362
+ let config = await resolveConfigWithAuth(options.projectDir);
363
+ if (options.projectSlug) config = { ...config, projectSlug: options.projectSlug };
364
+
365
+ const client = createApiClient(config);
366
+ let targets = options.uploads;
367
+
368
+ if (options.all) {
369
+ const uploads = await listAllUploads(client, config.projectSlug, {
370
+ path: options.path,
371
+ recursive: true,
372
+ limit: 100,
373
+ });
374
+ targets = uploads.filter((item) => item.type === "file").map((item) => item.path);
375
+ }
376
+
377
+ if (!targets.length) {
378
+ throw new Error("No uploads selected. Pass upload paths or use --path with --all.");
379
+ }
380
+
381
+ const results = [] as Array<{ uploadPath: string; localPath: string; bytes: number }>;
382
+ for (const uploadPath of targets) {
383
+ const result = await downloadUploadToFile(
384
+ client,
385
+ config.projectSlug,
386
+ uploadPath,
387
+ options.outputDir,
388
+ );
389
+ results.push(result);
390
+ if (!options.quiet && !options.json) {
391
+ cliLogger.info(`Downloaded ${uploadPath} -> ${result.localPath}`);
392
+ }
393
+ }
394
+
395
+ if (options.json) {
396
+ printJson(results);
397
+ return;
398
+ }
399
+
400
+ if (!options.quiet) {
401
+ cliLogger.info(`Pulled ${results.length} upload(s) into ${options.outputDir}.`);
402
+ }
403
+ return;
404
+ }
405
+
406
+ case "put": {
407
+ const parsed = parseUploadsPutArgs(args);
408
+ if (!parsed.success) {
409
+ throw new Error(`Invalid uploads put arguments: ${parsed.error.message}`);
410
+ }
411
+
412
+ const options = parsed.data;
413
+ let config = await resolveConfigWithAuth(options.projectDir);
414
+ if (options.projectSlug) config = { ...config, projectSlug: options.projectSlug };
415
+
416
+ const client = createApiClient(config);
417
+ const result = await uploadLocalFileToUploads(
418
+ client,
419
+ config.projectSlug,
420
+ options.uploadPath,
421
+ options.from,
422
+ options.contentType,
423
+ );
424
+
425
+ if (options.json) {
426
+ printJson(result);
427
+ return;
428
+ }
429
+
430
+ if (!options.quiet) {
431
+ cliLogger.info(`Uploaded ${options.from} -> ${normalizeUploadPath(options.uploadPath)}`);
432
+ }
433
+ return;
434
+ }
435
+
436
+ case "delete":
437
+ case "rm": {
438
+ const parsed = parseUploadsDeleteArgs(args);
439
+ if (!parsed.success) {
440
+ throw new Error(`Invalid uploads delete arguments: ${parsed.error.message}`);
441
+ }
442
+
443
+ const options = parsed.data;
444
+ let config = await resolveConfigWithAuth(options.projectDir);
445
+ if (options.projectSlug) config = { ...config, projectSlug: options.projectSlug };
446
+
447
+ const client = createApiClient(config);
448
+ await deleteUpload(client, config.projectSlug, options.uploadPath);
449
+
450
+ if (options.json) {
451
+ printJson({ success: true, path: normalizeUploadPath(options.uploadPath) });
452
+ return;
453
+ }
454
+
455
+ if (!options.quiet) {
456
+ cliLogger.info(`Deleted upload ${normalizeUploadPath(options.uploadPath)}`);
457
+ }
458
+ return;
459
+ }
460
+
461
+ default:
462
+ showUploadsUsage();
463
+ }
464
+ });
465
+ }
@@ -0,0 +1,6 @@
1
+ import type { ParsedArgs } from "../../shared/types.js";
2
+ import { uploadsCommand } from "./command.js";
3
+
4
+ export async function handleUploadsCommand(args: ParsedArgs): Promise<void> {
5
+ await uploadsCommand(args);
6
+ }
@@ -0,0 +1,23 @@
1
+ export {
2
+ buildUploadCreateUrl,
3
+ buildUploadSignedUrlPath,
4
+ buildUploadsListUrl,
5
+ deleteUpload,
6
+ downloadUploadToFile,
7
+ listAllUploads,
8
+ parseUploadsDeleteArgs,
9
+ parseUploadsListArgs,
10
+ parseUploadsPullArgs,
11
+ parseUploadsPutArgs,
12
+ resolveUploadOutputPath,
13
+ uploadLocalFileToUploads,
14
+ uploadsCommand,
15
+ } from "./command.js";
16
+ export type {
17
+ UploadDeleteOptions,
18
+ UploadItem,
19
+ UploadListOptions,
20
+ UploadPullOptions,
21
+ UploadPutOptions,
22
+ } from "./command.js";
23
+ export { handleUploadsCommand } from "./handler.js";
@@ -21,6 +21,9 @@ import { analyzeChunksHelp } from "../commands/analyze-chunks/command-help.js";
21
21
  import { generateHelp } from "../commands/generate/command-help.js";
22
22
  import { pullHelp } from "../commands/pull/command-help.js";
23
23
  import { pushHelp } from "../commands/push/command-help.js";
24
+ import { uploadsHelp } from "../commands/uploads/command-help.js";
25
+ import { filesHelp } from "../commands/files/command-help.js";
26
+ import { knowledgeHelp } from "../commands/knowledge/command-help.js";
24
27
  import { mergeHelp } from "../commands/merge/command-help.js";
25
28
  import { deployHelp } from "../commands/deploy/command-help.js";
26
29
  import { upHelp } from "../commands/up/command-help.js";
@@ -52,6 +55,9 @@ export const COMMANDS: CommandRegistry = {
52
55
  generate: generateHelp,
53
56
  pull: pullHelp,
54
57
  push: pushHelp,
58
+ uploads: uploadsHelp,
59
+ files: filesHelp,
60
+ knowledge: knowledgeHelp,
55
61
  merge: mergeHelp,
56
62
  deploy: deployHelp,
57
63
  up: upHelp,
package/src/cli/router.ts CHANGED
@@ -22,6 +22,9 @@ import { handleMCPCommand } from "./commands/mcp/handler.js";
22
22
  import { handleMergeCommand } from "./commands/merge/handler.js";
23
23
  import { handlePullCommand } from "./commands/pull/index.js";
24
24
  import { handlePushCommand } from "./commands/push/index.js";
25
+ import { handleUploadsCommand } from "./commands/uploads/index.js";
26
+ import { handleFilesCommand } from "./commands/files/index.js";
27
+ import { handleKnowledgeCommand } from "./commands/knowledge/index.js";
25
28
  import { handleRoutesCommand } from "./commands/routes/handler.js";
26
29
  import { handleServeCommand } from "./commands/serve/handler.js";
27
30
  import { handleStartCommand } from "./commands/start/handler.js";
@@ -56,6 +59,9 @@ const commands: Record<string, (args: ParsedArgs) => Promise<void>> = {
56
59
  "g": handleGenerateCommand,
57
60
  "pull": handlePullCommand,
58
61
  "push": handlePushCommand,
62
+ "uploads": handleUploadsCommand,
63
+ "files": handleFilesCommand,
64
+ "knowledge": handleKnowledgeCommand,
59
65
  "merge": handleMergeCommand,
60
66
  "deploy": handleDeployCommand,
61
67
  "up": handleUpCommand,
package/src/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.71",
3
+ "version": "0.1.73",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -591,6 +591,14 @@ export const ORCHESTRATION_ERROR = defineError({
591
591
  suggestion: "Check agent coordination logic",
592
592
  });
593
593
 
594
+ export const COST_LIMIT_EXCEEDED = defineError({
595
+ slug: "cost-limit-exceeded",
596
+ category: "AGENT",
597
+ status: 429,
598
+ title: "Cost limit exceeded",
599
+ suggestion: "Wait for the budget period to reset or increase the limit",
600
+ });
601
+
594
602
  // =============================================================================
595
603
  // GENERAL - Cross-cutting errors
596
604
  // =============================================================================
@@ -772,6 +780,7 @@ export const ERROR_REGISTRY = {
772
780
  "agent-timeout": AGENT_TIMEOUT,
773
781
  "agent-intent-error": AGENT_INTENT_ERROR,
774
782
  "orchestration-error": ORCHESTRATION_ERROR,
783
+ "cost-limit-exceeded": COST_LIMIT_EXCEEDED,
775
784
 
776
785
  // GENERAL
777
786
  "unknown-error": UNKNOWN_ERROR,
@@ -46,6 +46,7 @@ export {
46
46
  CONFIG_VALIDATION_ERROR,
47
47
  CONFIG_VALIDATION_FAILED,
48
48
  CORS_CONFIG_INVALID,
49
+ COST_LIMIT_EXCEEDED,
49
50
  DEPENDENCY_MISSING,
50
51
  // DEPLOY
51
52
  DEPLOYMENT_ERROR,
@@ -208,6 +208,14 @@ async function generateHTMLShellPartsImpl(
208
208
 
209
209
  const nonceAttr = nonce ? ` nonce="${nonce}"` : "";
210
210
 
211
+ // Expose project slug for runtime error overlay "Fix in Veryfront" button
212
+ const overlaySlug = options.projectId || meta.slug;
213
+ const slugForOverlay = useDevScripts && overlaySlug
214
+ ? `<script${nonceAttr}>window.__VF_PROJECT_SLUG__=${
215
+ JSON.stringify(overlaySlug).replace(/</g, "\\u003c")
216
+ };</script>`
217
+ : "";
218
+
211
219
  const hydrationErrorSuppression = useDevScripts ? "" : `<script${nonceAttr}>
212
220
  (function(){
213
221
  var origError = console.error;
@@ -303,6 +311,7 @@ async function generateHTMLShellPartsImpl(
303
311
  ${linkTags}
304
312
  ${styleTags}
305
313
  ${modeStyles}
314
+ ${slugForOverlay}
306
315
  </head>
307
316
  <body${bodyClass ? ` class="${bodyClass}"` : ""} suppressHydrationWarning>
308
317
  <div ${rootAttributes}>`;
@@ -0,0 +1,23 @@
1
+ import mime from "mime-types";
2
+
3
+ export function contentType(path: string): string | undefined {
4
+ const type = mime.lookup(path);
5
+ if (!type) return undefined;
6
+
7
+ const cs = mime.charset(type);
8
+ if (!cs) return type;
9
+
10
+ return `${type}; charset=${cs}`;
11
+ }
12
+
13
+ export function extension(type: string): string | undefined {
14
+ return mime.extension(type) ?? undefined;
15
+ }
16
+
17
+ export function lookup(path: string): string | undefined {
18
+ return mime.lookup(path) ?? undefined;
19
+ }
20
+
21
+ export function charset(type: string): string | undefined {
22
+ return mime.charset(type) ?? undefined;
23
+ }
@@ -55,6 +55,9 @@ export {
55
55
  type StdinReader,
56
56
  } from "./compat/stdin.js";
57
57
 
58
+ // Compat: media types
59
+ export { lookup as lookupMimeType } from "./compat/media-types.js";
60
+
58
61
  // Compat: KV store
59
62
  export { createKVStore, MemoryKv } from "./compat/kv/index.js";
60
63