veryfront 0.1.1225 → 0.1.1226

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 (34) hide show
  1. package/README.md +1 -1
  2. package/esm/cli/main.d.ts +1 -1
  3. package/esm/cli/main.js +1 -1
  4. package/esm/cli/shared/deployment/deploy-project.d.ts.map +1 -1
  5. package/esm/cli/shared/deployment/deploy-project.js +72 -10
  6. package/esm/cli/shared/update-check.d.ts +24 -9
  7. package/esm/cli/shared/update-check.d.ts.map +1 -1
  8. package/esm/cli/shared/update-check.js +74 -34
  9. package/esm/cli/templates/manifest.js +1 -1
  10. package/esm/deno.d.ts +1 -0
  11. package/esm/deno.js +2 -1
  12. package/esm/src/html/hydration-script-builder/hydration-runtime.generated.js +1 -1
  13. package/esm/src/platform/adapters/fs/veryfront/read-operations-helpers.d.ts +2 -0
  14. package/esm/src/platform/adapters/fs/veryfront/read-operations-helpers.d.ts.map +1 -1
  15. package/esm/src/platform/adapters/fs/veryfront/read-operations-helpers.js +4 -0
  16. package/esm/src/platform/adapters/fs/veryfront/read-operations.d.ts.map +1 -1
  17. package/esm/src/platform/adapters/fs/veryfront/read-operations.js +6 -1
  18. package/esm/src/platform/adapters/runtime/shared/node-filesystem-adapter.d.ts.map +1 -1
  19. package/esm/src/platform/adapters/runtime/shared/node-filesystem-adapter.js +15 -1
  20. package/esm/src/platform/compat/fs.d.ts.map +1 -1
  21. package/esm/src/platform/compat/fs.js +14 -1
  22. package/esm/src/platform/compat/http/pinned-fetch.d.ts +1 -1
  23. package/esm/src/proxy/control-plane-signature.d.ts.map +1 -1
  24. package/esm/src/proxy/control-plane-signature.js +1 -1
  25. package/esm/src/react/compat/ssr-adapter/string-renderer.d.ts.map +1 -1
  26. package/esm/src/react/compat/ssr-adapter/string-renderer.js +6 -5
  27. package/esm/src/react/compat/ssr-adapter/timeout.d.ts +7 -0
  28. package/esm/src/react/compat/ssr-adapter/timeout.d.ts.map +1 -1
  29. package/esm/src/react/compat/ssr-adapter/timeout.js +13 -0
  30. package/esm/src/runtime/runtime-bridge.d.ts.map +1 -1
  31. package/esm/src/runtime/runtime-bridge.js +20 -8
  32. package/esm/src/utils/version-constant.d.ts +1 -1
  33. package/esm/src/utils/version-constant.js +1 -1
  34. package/package.json +8 -8
package/README.md CHANGED
@@ -37,7 +37,7 @@ deno init --npm veryfront
37
37
  The default starter is `ai-agent`. Choose another template directly:
38
38
 
39
39
  ```bash
40
- npx veryfront init <PROJECT_NAME> --template <TEMPLATE>
40
+ npx veryfront@latest init <PROJECT_NAME> --template <TEMPLATE>
41
41
  ```
42
42
 
43
43
  Available starters: `ai-agent`, `minimal`, `agentic-workflow`.
package/esm/cli/main.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * @example
7
7
  * ```sh
8
- * npx veryfront dev
8
+ * npx veryfront@latest dev
9
9
  * ```
10
10
  */
11
11
  import "../_dnt.polyfills.js";
package/esm/cli/main.js CHANGED
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * @example
7
7
  * ```sh
8
- * npx veryfront dev
8
+ * npx veryfront@latest dev
9
9
  * ```
10
10
  */
11
11
  // Set the CLI logger preset before importing modules that may log during initialization.
@@ -1 +1 @@
1
- {"version":3,"file":"deploy-project.d.ts","sourceRoot":"","sources":["../../../../src/cli/shared/deployment/deploy-project.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deploy-project.d.ts","sourceRoot":"","sources":["../../../../src/cli/shared/deployment/deploy-project.ts"],"names":[],"mappings":"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"}
@@ -456,10 +456,55 @@ function isMatchingVeryfrontHostedUrl(url, target) {
456
456
  parsed.slug === target.projectSlug.toLowerCase() &&
457
457
  parsed.environment === target.environmentName.toLowerCase();
458
458
  }
459
+ const MAX_JWT_SEGMENT_CODE_UNITS = 8 * 1024;
460
+ /** Decode one base64url JWT segment into a plain object, or null if it is not one. */
461
+ function decodeJwtSegment(segment) {
462
+ if (segment === undefined)
463
+ return null;
464
+ if (segment.length === 0 || segment.length > MAX_JWT_SEGMENT_CODE_UNITS)
465
+ return null;
466
+ try {
467
+ const base64 = segment.replaceAll("-", "+").replaceAll("_", "/");
468
+ const binary = atob(base64 + "=".repeat((4 - base64.length % 4) % 4));
469
+ const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));
470
+ const parsed = JSON.parse(new TextDecoder().decode(bytes));
471
+ return typeof parsed === "object" && parsed !== null ? parsed : null;
472
+ }
473
+ catch {
474
+ return null;
475
+ }
476
+ }
477
+ /**
478
+ * Whether a stored credential could satisfy the protected-environment gate.
479
+ *
480
+ * The gate reads `userId` from the verified JWT payload and has no API-key
481
+ * branch, so presenting an opaque key only leaks it. Reads what the gate
482
+ * reads, and withholds anything it cannot recognise.
483
+ */
484
+ function isSessionCredential(apiToken) {
485
+ const segments = apiToken.split(".");
486
+ if (segments.length !== 3)
487
+ return false;
488
+ const header = decodeJwtSegment(segments[0]);
489
+ if (header === null || typeof readUntrustedOwnDataProperty(header, "alg") !== "string") {
490
+ return false;
491
+ }
492
+ const payload = decodeJwtSegment(segments[1]);
493
+ if (payload === null)
494
+ return false;
495
+ const userId = readUntrustedOwnDataProperty(payload, "userId");
496
+ return typeof userId === "string" && userId.length > 0;
497
+ }
459
498
  function buildEnvironmentReadinessProbes(target) {
460
499
  const route = target.route === undefined ? "/" : target.route;
461
500
  if (route === null)
462
501
  return [];
502
+ // Without a session credential the probe cannot get past the gate. Its
503
+ // challenge still proves routing resolves and the proxy is serving this
504
+ // environment — the most this step can establish, and the deployment it
505
+ // would otherwise fail is already committed and verified. Same allowance the
506
+ // protected custom-domain probe below already makes.
507
+ const canAuthenticate = isSessionCredential(target.apiToken);
463
508
  const targetUrl = buildEnvironmentProbeUrl(target.url, route);
464
509
  if (target.protected && !isMatchingVeryfrontHostedUrl(new URL(targetUrl), target)) {
465
510
  return [
@@ -470,15 +515,15 @@ function buildEnvironmentReadinessProbes(target) {
470
515
  },
471
516
  {
472
517
  url: buildEnvironmentProbeUrl(buildCanonicalEnvironmentUrl(target.projectSlug, target.environmentName), route),
473
- authenticate: true,
474
- acceptAuthenticationChallenge: false,
518
+ authenticate: canAuthenticate,
519
+ acceptAuthenticationChallenge: !canAuthenticate,
475
520
  },
476
521
  ];
477
522
  }
478
523
  return [{
479
524
  url: target.protected ? secureEnvironmentProbeUrl(targetUrl) : targetUrl,
480
- authenticate: target.protected,
481
- acceptAuthenticationChallenge: false,
525
+ authenticate: target.protected && canAuthenticate,
526
+ acceptAuthenticationChallenge: target.protected && !canAuthenticate,
482
527
  }];
483
528
  }
484
529
  function isVeryfrontSignInUrl(url) {
@@ -499,6 +544,16 @@ function isSignInRedirect(response, requestUrl) {
499
544
  return false;
500
545
  }
501
546
  }
547
+ /** A challenge is a sign-in redirect, a 401, or a 403; say which one arrived. */
548
+ function describeAuthenticationChallenge(probe, status, signInRedirect) {
549
+ if (probe.authenticate) {
550
+ return `Could not authenticate the protected environment URL ${probe.url}. Run veryfront login and deploy again.`;
551
+ }
552
+ if (signInRedirect) {
553
+ return `Environment URL ${probe.url} redirected to sign-in. Check its protection settings and deploy again.`;
554
+ }
555
+ return `Environment URL ${probe.url} returned HTTP ${status}. Check its protection settings and deploy again.`;
556
+ }
502
557
  function isTransientEnvironmentStatus(status) {
503
558
  return status === 404 || status === 408 || status === 425 || status === 429 || status >= 500;
504
559
  }
@@ -551,18 +606,25 @@ export async function waitForEnvironmentReady(target, options = {}) {
551
606
  if (ready)
552
607
  break;
553
608
  if (authenticationChallenge) {
554
- const message = probe.authenticate
555
- ? `Could not authenticate the protected environment URL ${probe.url}. Run veryfront login and deploy again.`
556
- : `Environment URL ${probe.url} redirected to sign-in. Check its protection settings and deploy again.`;
557
- throw new Error(message);
609
+ // A bare Error here reaches the operator as `unknown-error`.
610
+ throw DEPLOYMENT_ERROR.create({
611
+ detail: describeAuthenticationChallenge(probe, response.status, signInRedirect),
612
+ context: { url: probe.url, status: response.status },
613
+ });
558
614
  }
559
615
  if (!isTransientEnvironmentStatus(response.status)) {
560
- throw new Error(`Environment URL ${probe.url} returned HTTP ${response.status}. Check the environment configuration and deploy again.`);
616
+ throw DEPLOYMENT_ERROR.create({
617
+ detail: `Environment URL ${probe.url} returned HTTP ${response.status}. Check the environment configuration and deploy again.`,
618
+ context: { url: probe.url, status: response.status },
619
+ });
561
620
  }
562
621
  }
563
622
  const remainingMs = deadline - Date.now();
564
623
  if (remainingMs <= 0) {
565
- throw new Error(`Environment URL ${probe.url} did not become ready within ${Math.ceil(timeoutMs / 1000)}s (last response: ${lastResponse}). Check the deployment and run deploy again.`);
624
+ throw DEPLOYMENT_ERROR.create({
625
+ detail: `Environment URL ${probe.url} did not become ready within ${Math.ceil(timeoutMs / 1000)}s (last response: ${lastResponse}). Check the deployment and run deploy again.`,
626
+ context: { url: probe.url, timeoutMs },
627
+ });
566
628
  }
567
629
  await wait(Math.min(pollIntervalMs, remainingMs));
568
630
  }
@@ -1,12 +1,27 @@
1
- /**
2
- * Non-blocking update check
3
- *
4
- * Checks for newer CLI versions after command execution.
5
- * Cached for 24 hours. Never blocks command output.
6
- *
7
- * @module cli/shared/update-check
8
- */
1
+ import { type FileSystem } from "../../src/platform/index.js";
2
+ export declare const UPDATE_REGISTRY_URL = "https://registry.npmjs.org/veryfront/latest";
3
+ export declare const UPDATE_INSTALL_COMMAND = "npm install -g veryfront@latest";
4
+ interface UpdateCacheLocation {
5
+ directory: string;
6
+ file: string;
7
+ }
8
+ type UpdateCheckFileSystem = Pick<FileSystem, "readTextFile" | "mkdir" | "writeTextFile">;
9
+ type UpdateCheckFetcher = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
10
+ export interface UpdateCheckOptions {
11
+ shouldSkip?: () => boolean;
12
+ cacheLocation?: UpdateCacheLocation | null;
13
+ fileSystem?: UpdateCheckFileSystem;
14
+ fetcher?: UpdateCheckFetcher;
15
+ now?: () => number;
16
+ printNotice?: (current: string, latest: string) => void;
17
+ debug?: (message: string) => void;
18
+ }
9
19
  export declare function compareVersions(current: string, latest: string): boolean;
10
20
  export declare function shouldSkip(): boolean;
11
- export declare function checkForUpdates(currentVersion: string): Promise<void>;
21
+ export declare function getUpdateInstallCommand(context?: {
22
+ standalone: boolean;
23
+ executablePath: string;
24
+ }): string;
25
+ export declare function checkForUpdates(currentVersion: string, options?: UpdateCheckOptions): Promise<void>;
26
+ export {};
12
27
  //# sourceMappingURL=update-check.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"update-check.d.ts","sourceRoot":"","sources":["../../../src/cli/shared/update-check.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA2BH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAQxE;AAED,wBAAgB,UAAU,IAAI,OAAO,CAMpC;AASD,wBAAsB,eAAe,CACnC,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,IAAI,CAAC,CAiDf"}
1
+ {"version":3,"file":"update-check.d.ts","sourceRoot":"","sources":["../../../src/cli/shared/update-check.ts"],"names":[],"mappings":"AAYA,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAShF,eAAO,MAAM,mBAAmB,gDAAgD,CAAC;AACjF,eAAO,MAAM,sBAAsB,oCAAoC,CAAC;AAUxE,UAAU,mBAAmB;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,KAAK,qBAAqB,GAAG,IAAI,CAAC,UAAU,EAAE,cAAc,GAAG,OAAO,GAAG,eAAe,CAAC,CAAC;AAC1F,KAAK,kBAAkB,GAAG,CACxB,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,EAC7B,IAAI,CAAC,EAAE,WAAW,KACf,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEvB,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAC3C,UAAU,CAAC,EAAE,qBAAqB,CAAC;IACnC,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxD,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAWD,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAQxE;AAED,wBAAgB,UAAU,IAAI,OAAO,CAMpC;AAED,wBAAgB,uBAAuB,CACrC,OAAO,GAAE;IAAE,UAAU,EAAE,OAAO,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAGrD,GACA,MAAM,CAkBR;AA+BD,wBAAsB,eAAe,CACnC,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAmDf"}
@@ -6,23 +6,29 @@
6
6
  *
7
7
  * @module cli/shared/update-check
8
8
  */
9
+ import * as dntShim from "../../_dnt.shims.js";
9
10
  import { getEnv } from "../../src/platform/index.js";
10
11
  import { createFileSystem } from "../../src/platform/index.js";
11
12
  import { join } from "../../src/platform/compat/path/index.js";
12
13
  import { getEnvironmentConfig } from "../../src/config/index.js";
13
14
  import { isJsonMode } from "./json-output.js";
14
15
  import { brand, dim, warning as warningColor } from "../ui/colors.js";
15
- import { isQuiet } from "../utils/index.js";
16
+ import { cliLogger, isQuiet } from "../utils/index.js";
16
17
  import { detectCI } from "./interactive.js";
17
18
  const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
18
- const REGISTRY_URL = "https://jsr.io/@veryfront/veryfront/meta.json";
19
- const INSTALL_CMD = "deno install -gArf jsr:@veryfront/veryfront";
20
- function getCacheFile() {
19
+ export const UPDATE_REGISTRY_URL = "https://registry.npmjs.org/veryfront/latest";
20
+ export const UPDATE_INSTALL_COMMAND = "npm install -g veryfront@latest";
21
+ const HOMEBREW_UPDATE_COMMAND = "brew upgrade veryfront/tap/veryfront";
22
+ const INSTALL_SCRIPT_COMMAND = "curl -fsSL https://veryfront.com/install.sh | sh";
23
+ const STABLE_SEMVER_PATTERN = /^\d+\.\d+\.\d+$/;
24
+ class UpdateCheckFailure extends Error {
25
+ }
26
+ function getCacheLocation() {
21
27
  const env = getEnvironmentConfig();
22
28
  if (!env.homeDir)
23
29
  return null;
24
- const cacheDir = join(env.homeDir, ".cache", "veryfront");
25
- return join(cacheDir, "update-check.json");
30
+ const directory = join(env.homeDir, ".cache", "veryfront");
31
+ return { directory, file: join(directory, "update-check.json") };
26
32
  }
27
33
  export function compareVersions(current, latest) {
28
34
  const c = current.split(".").map(Number);
@@ -46,54 +52,88 @@ export function shouldSkip() {
46
52
  return true;
47
53
  return false;
48
54
  }
55
+ export function getUpdateInstallCommand(context = {
56
+ standalone: dntShim.Deno.build.standalone ?? false,
57
+ executablePath: dntShim.Deno.execPath(),
58
+ }) {
59
+ if (!context.standalone)
60
+ return UPDATE_INSTALL_COMMAND;
61
+ const executablePath = context.executablePath.replaceAll("\\", "/").toLowerCase();
62
+ if (executablePath.includes("/node_modules/veryfront/bin/")) {
63
+ return UPDATE_INSTALL_COMMAND;
64
+ }
65
+ if (executablePath.includes("/cellar/") ||
66
+ executablePath.includes("/homebrew/") ||
67
+ executablePath.includes("/linuxbrew/")) {
68
+ return HOMEBREW_UPDATE_COMMAND;
69
+ }
70
+ if (!executablePath.endsWith(".exe"))
71
+ return INSTALL_SCRIPT_COMMAND;
72
+ return UPDATE_INSTALL_COMMAND;
73
+ }
49
74
  function printUpdateNotice(current, latest) {
50
75
  console.error();
51
76
  console.error(` ${warningColor("!")} Update available: ${current} → ${latest}`);
52
- console.error(` ${dim("Run:")} ${brand(INSTALL_CMD)}`);
77
+ console.error(` ${dim("Run:")} ${brand(getUpdateInstallCommand())}`);
53
78
  console.error();
54
79
  }
55
- export async function checkForUpdates(currentVersion) {
56
- if (shouldSkip())
80
+ async function fetchLatestVersion(fetcher) {
81
+ const response = await fetcher(UPDATE_REGISTRY_URL);
82
+ if (!response.ok) {
83
+ await response.body?.cancel();
84
+ throw new UpdateCheckFailure(`Veryfront could not check for updates: npm registry returned ${response.status}.`);
85
+ }
86
+ const data = await response.json();
87
+ const latestVersion = data && typeof data === "object" && "version" in data
88
+ ? data.version
89
+ : undefined;
90
+ if (typeof latestVersion !== "string" || !STABLE_SEMVER_PATTERN.test(latestVersion)) {
91
+ throw new UpdateCheckFailure("Veryfront could not check for updates: npm registry returned an invalid version.");
92
+ }
93
+ return latestVersion;
94
+ }
95
+ export async function checkForUpdates(currentVersion, options = {}) {
96
+ if ((options.shouldSkip ?? shouldSkip)())
57
97
  return;
58
- const cacheFile = getCacheFile();
59
- if (!cacheFile)
98
+ const cacheLocation = options.cacheLocation === undefined
99
+ ? getCacheLocation()
100
+ : options.cacheLocation;
101
+ if (!cacheLocation)
60
102
  return;
61
- const fs = createFileSystem();
103
+ const fs = options.fileSystem ?? createFileSystem();
104
+ const now = options.now ?? Date.now;
105
+ const notice = options.printNotice ?? printUpdateNotice;
106
+ const debug = options.debug ?? ((message) => cliLogger.debug(message));
62
107
  try {
63
- const raw = await fs.readTextFile(cacheFile);
108
+ const raw = await fs.readTextFile(cacheLocation.file);
64
109
  const cache = JSON.parse(raw);
65
- if (Date.now() - cache.lastCheck < CHECK_INTERVAL_MS) {
110
+ if (now() - cache.lastCheck < CHECK_INTERVAL_MS) {
66
111
  if (cache.latestVersion &&
67
112
  compareVersions(currentVersion, cache.latestVersion)) {
68
- printUpdateNotice(currentVersion, cache.latestVersion);
113
+ notice(currentVersion, cache.latestVersion);
69
114
  }
70
115
  return;
71
116
  }
72
117
  }
73
118
  catch {
74
- // No cache proceed
119
+ // No cache. Continue with the registry check.
75
120
  }
76
121
  try {
77
- const resp = await fetch(REGISTRY_URL);
78
- if (!resp.ok) {
79
- await resp.body?.cancel();
80
- return;
81
- }
82
- const data = await resp.json();
83
- const latestVersion = data.latest;
84
- if (!latestVersion)
85
- return;
86
- const env = getEnvironmentConfig();
87
- if (!env.homeDir)
88
- return;
89
- const cacheDir = join(env.homeDir, ".cache", "veryfront");
90
- await fs.mkdir(cacheDir, { recursive: true });
91
- await fs.writeTextFile(cacheFile, JSON.stringify({ lastCheck: Date.now(), latestVersion }));
122
+ const latestVersion = await fetchLatestVersion(options.fetcher ?? fetch);
92
123
  if (compareVersions(currentVersion, latestVersion)) {
93
- printUpdateNotice(currentVersion, latestVersion);
124
+ notice(currentVersion, latestVersion);
125
+ }
126
+ try {
127
+ await fs.mkdir(cacheLocation.directory, { recursive: true });
128
+ await fs.writeTextFile(cacheLocation.file, JSON.stringify({ lastCheck: now(), latestVersion }));
129
+ }
130
+ catch {
131
+ debug("Veryfront could not cache the update check.");
94
132
  }
95
133
  }
96
- catch {
97
- // Network error silently ignore
134
+ catch (error) {
135
+ debug(error instanceof UpdateCheckFailure
136
+ ? error.message
137
+ : "Veryfront could not complete the update check.");
98
138
  }
99
139
  }
@@ -66,7 +66,7 @@ export default {
66
66
  "globals.css": "@import \"tailwindcss\";\n",
67
67
  "globals.d.ts": "declare module \"*.css\";\n",
68
68
  "public/favicon.svg": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 64 64\">\n <rect width=\"64\" height=\"64\" fill=\"#fff\"/>\n <circle cx=\"32\" cy=\"32\" r=\"20\" fill=\"#000\"/>\n</svg>\n",
69
- "README.md": "# Docs Agent\n\nA chatbot that answers questions from your own documents using Retrieval-Augmented Generation (RAG).\n\n## What's included\n\n- Q&A agent with source citation\n- Embedding-based semantic search with convention-based model selection\n- Document upload supporting PDF, DOCX, XLSX, PPTX, CSV, HTML, RTF, EPUB, TXT, and Markdown\n- `ragStore()` with local JSON storage by default, and Veryfront Cloud RAG when bootstrap is present\n- Veryfront Cloud AI Gateway routing for generation and embeddings when bootstrap is present\n- Original uploaded files stored in Veryfront Cloud project uploads when cloud bootstrap is present\n- Sample content in `/content` indexed through a dedicated ingestion route\n\n## Getting started\n\n1. Set your Veryfront Cloud bootstrap vars:\n\n ```bash\n export VERYFRONT_API_TOKEN=vf_...\n export VERYFRONT_PROJECT_SLUG=my-project\n ```\n\n2. Start the dev server:\n\n ```bash\n npx veryfront dev\n ```\n\n3. Index the sample docs in `content/`:\n\n ```bash\n curl -X POST http://localhost:3000/api/ingest\n ```\n\n4. Open the app and upload a document or ask a question.\n\nIf you are using a self-hosted Veryfront API, also set `VERYFRONT_API_URL`.\n\n## Cloud mode\n\nWith `VERYFRONT_API_TOKEN` and `VERYFRONT_PROJECT_SLUG` set, the template uses\nVeryfront Cloud automatically:\n\n- Agent generation routes through Veryfront Cloud model routing.\n- Query and document embeddings route through Veryfront Cloud embedding routing.\n- `veryfront-cloud/openai/...` and `veryfront-cloud/google/...` models use AI Gateway.\n- RAG documents, chunks, and embeddings are stored in the target project.\n\nThe default cloud embedding model is\n`veryfront-cloud/openai/text-embedding-3-small`. Set\n`VERYFRONT_DEFAULT_EMBEDDING_MODEL` only when you need a different embedding\nmodel.\n\n## Architecture\n\nRAG grounds LLM responses in your documents through three pipelines: **Ingestion**, **Query**, and **RAG**. These pipelines are orchestrated around a shared vector store.\n\n```mermaid\nflowchart LR\n ChatUI_L[\"Chat UI\"]\n\n subgraph IngestionFlow[\"Ingestion Pipeline\"]\n D[\"Documents\"] --> EXT[\"Extraction\"] --> DC[\"Chunking\"] --> DE[\"Document\\nEmbedding\"] --> ING[\"Storage\"]\n end\n\n subgraph QueryFlow[\"Query Pipeline\"]\n Q[\"Query\"] --> QE[\"Query\\nEmbedding\"] --> SS[\"Similarity\\nSearch\"]\n end\n\n subgraph RAGFlow[\"RAG Pipeline\"]\n BF[\"beforeStream\\nHook\"] --> RET[\"Retrieval\"] --> AUG[\"Augmentation\"] --> AG[\"Agent\"] --> GEN[\"Generation\"]\n end\n\n EMB((\"Embedding\\nModel\"))\n GEN_LLM((\"Generative\\nModel\"))\n VS[(\"Vector\\nStore\")]\n ChatUI_R[\"Chat UI\"]\n\n ChatUI_L --> D\n ChatUI_L --> Q\n\n QE -.- EMB\n DE -.- EMB\n\n SS --> VS\n ING --> VS\n\n Q --> BF\n VS --> RET\n AG -.- GEN_LLM\n GEN -.- GEN_LLM\n GEN --> ChatUI_R\n```\n\n### Pipelines\n\n**Ingestion**: Documents are parsed into plain text via the built-in kreuzberg extraction engine (supporting PDF, DOCX, XLSX, PPTX, HTML, RTF, EPUB, and 76+ formats), split into overlapping chunks (~1000 chars, 200 char overlap), and stored in the default `ragStore()`. In local mode that means `data/index.json`; with Veryfront Cloud bootstrap it upgrades to the cloud RAG backend automatically. The original uploaded binary is also stored in the project's Veryfront Cloud uploads store so remote projects retain the source file, not just the extracted text. Uploaded files are ingested by the upload route. Bundled files in `content/` are ingested by the `/api/ingest` route.\n\n**Query**: The user's query is embedded into the same vector space as the documents, then compared against all stored chunks using cosine similarity to find the top-*k* most relevant results.\n\n**RAG**: The `beforeStream` hook in the AG-UI route intercepts each message before it reaches the agent. It searches the document store for relevant chunks, assembles them into context, and prepends them as retrieved reference data. The agent then generates a cited response streamed back to the user.\n\n## Structure\n\n```\nstore.ts RAG store config\nagents/rag.ts Q&A agent with citation instructions\ncontent/\n getting-started.md Sample document\n architecture.md Sample document\napp/\n api/ag-ui/route.ts AG-UI endpoint\n api/ingest/route.ts Bundled content ingestion\n api/uploads/route.ts Upload, list, and delete uploads\n uploads/page.tsx Upload management panel\n page.tsx Chat UI\n layout.tsx Chat shell with sidebar and tabs\n```\n\n## Framework usage\n\n| What | Framework | Template code |\n|------|-----------|---------------|\n| Chat UI + streaming | app-mode `Chat` | `page.tsx` |\n| Upload management | `AttachmentsPanel`, `useUploadsRegistry` | `uploads/page.tsx` |\n| Source display | Built into the `Chat` preset | `page.tsx` |\n| Upload API route | `createUploadHandler` | 1 line in `route.ts` |\n| AG-UI route | `createAgUiHandler` | 1 line in `route.ts` |\n| Agent definition | `agent()` | Config object in `agents/rag.ts` |\n| RAG retrieval | `beforeStream` hook | Context injection in `api/ag-ui/route.ts` |\n| Vector store | `ragStore()` | Config in `store.ts` |\n\n## Adding documents\n\n- Drop files into `content/`, then run `curl -X POST http://localhost:3000/api/ingest`\n- Or use the upload panel in the UI for PDF, DOCX, XLSX, PPTX, CSV, HTML, RTF, EPUB, TXT, and MD files\n\n## Production notes\n\nThis is a starter template, not a production-ready setup. For production, consider:\n\n- **Vector store**: Replace the default store with pgvector, Pinecone, or Qdrant for datasets beyond ~10k chunks\n- **Reranking**: Add a cross-encoder reranker (e.g. Cohere Rerank) after retrieval to improve precision\n- **Hybrid search**: Combine dense vectors with BM25 keyword matching for better recall\n",
69
+ "README.md": "# Docs Agent\n\nA chatbot that answers questions from your own documents using Retrieval-Augmented Generation (RAG).\n\n## What's included\n\n- Q&A agent with source citation\n- Embedding-based semantic search with convention-based model selection\n- Document upload supporting PDF, DOCX, XLSX, PPTX, CSV, HTML, RTF, EPUB, TXT, and Markdown\n- `ragStore()` with local JSON storage by default, and Veryfront Cloud RAG when bootstrap is present\n- Veryfront Cloud AI Gateway routing for generation and embeddings when bootstrap is present\n- Original uploaded files stored in Veryfront Cloud project uploads when cloud bootstrap is present\n- Sample content in `/content` indexed through a dedicated ingestion route\n\n## Getting started\n\n1. Set your Veryfront Cloud bootstrap vars:\n\n ```bash\n export VERYFRONT_API_TOKEN=vf_...\n export VERYFRONT_PROJECT_SLUG=my-project\n ```\n\n2. Start the dev server:\n\n ```bash\n npx veryfront@latest dev\n ```\n\n3. Index the sample docs in `content/`:\n\n ```bash\n curl -X POST http://localhost:3000/api/ingest\n ```\n\n4. Open the app and upload a document or ask a question.\n\nIf you are using a self-hosted Veryfront API, also set `VERYFRONT_API_URL`.\n\n## Cloud mode\n\nWith `VERYFRONT_API_TOKEN` and `VERYFRONT_PROJECT_SLUG` set, the template uses\nVeryfront Cloud automatically:\n\n- Agent generation routes through Veryfront Cloud model routing.\n- Query and document embeddings route through Veryfront Cloud embedding routing.\n- `veryfront-cloud/openai/...` and `veryfront-cloud/google/...` models use AI Gateway.\n- RAG documents, chunks, and embeddings are stored in the target project.\n\nThe default cloud embedding model is\n`veryfront-cloud/openai/text-embedding-3-small`. Set\n`VERYFRONT_DEFAULT_EMBEDDING_MODEL` only when you need a different embedding\nmodel.\n\n## Architecture\n\nRAG grounds LLM responses in your documents through three pipelines: **Ingestion**, **Query**, and **RAG**. These pipelines are orchestrated around a shared vector store.\n\n```mermaid\nflowchart LR\n ChatUI_L[\"Chat UI\"]\n\n subgraph IngestionFlow[\"Ingestion Pipeline\"]\n D[\"Documents\"] --> EXT[\"Extraction\"] --> DC[\"Chunking\"] --> DE[\"Document\\nEmbedding\"] --> ING[\"Storage\"]\n end\n\n subgraph QueryFlow[\"Query Pipeline\"]\n Q[\"Query\"] --> QE[\"Query\\nEmbedding\"] --> SS[\"Similarity\\nSearch\"]\n end\n\n subgraph RAGFlow[\"RAG Pipeline\"]\n BF[\"beforeStream\\nHook\"] --> RET[\"Retrieval\"] --> AUG[\"Augmentation\"] --> AG[\"Agent\"] --> GEN[\"Generation\"]\n end\n\n EMB((\"Embedding\\nModel\"))\n GEN_LLM((\"Generative\\nModel\"))\n VS[(\"Vector\\nStore\")]\n ChatUI_R[\"Chat UI\"]\n\n ChatUI_L --> D\n ChatUI_L --> Q\n\n QE -.- EMB\n DE -.- EMB\n\n SS --> VS\n ING --> VS\n\n Q --> BF\n VS --> RET\n AG -.- GEN_LLM\n GEN -.- GEN_LLM\n GEN --> ChatUI_R\n```\n\n### Pipelines\n\n**Ingestion**: Documents are parsed into plain text via the built-in kreuzberg extraction engine (supporting PDF, DOCX, XLSX, PPTX, HTML, RTF, EPUB, and 76+ formats), split into overlapping chunks (~1000 chars, 200 char overlap), and stored in the default `ragStore()`. In local mode that means `data/index.json`; with Veryfront Cloud bootstrap it upgrades to the cloud RAG backend automatically. The original uploaded binary is also stored in the project's Veryfront Cloud uploads store so remote projects retain the source file, not just the extracted text. Uploaded files are ingested by the upload route. Bundled files in `content/` are ingested by the `/api/ingest` route.\n\n**Query**: The user's query is embedded into the same vector space as the documents, then compared against all stored chunks using cosine similarity to find the top-*k* most relevant results.\n\n**RAG**: The `beforeStream` hook in the AG-UI route intercepts each message before it reaches the agent. It searches the document store for relevant chunks, assembles them into context, and prepends them as retrieved reference data. The agent then generates a cited response streamed back to the user.\n\n## Structure\n\n```\nstore.ts RAG store config\nagents/rag.ts Q&A agent with citation instructions\ncontent/\n getting-started.md Sample document\n architecture.md Sample document\napp/\n api/ag-ui/route.ts AG-UI endpoint\n api/ingest/route.ts Bundled content ingestion\n api/uploads/route.ts Upload, list, and delete uploads\n uploads/page.tsx Upload management panel\n page.tsx Chat UI\n layout.tsx Chat shell with sidebar and tabs\n```\n\n## Framework usage\n\n| What | Framework | Template code |\n|------|-----------|---------------|\n| Chat UI + streaming | app-mode `Chat` | `page.tsx` |\n| Upload management | `AttachmentsPanel`, `useUploadsRegistry` | `uploads/page.tsx` |\n| Source display | Built into the `Chat` preset | `page.tsx` |\n| Upload API route | `createUploadHandler` | 1 line in `route.ts` |\n| AG-UI route | `createAgUiHandler` | 1 line in `route.ts` |\n| Agent definition | `agent()` | Config object in `agents/rag.ts` |\n| RAG retrieval | `beforeStream` hook | Context injection in `api/ag-ui/route.ts` |\n| Vector store | `ragStore()` | Config in `store.ts` |\n\n## Adding documents\n\n- Drop files into `content/`, then run `curl -X POST http://localhost:3000/api/ingest`\n- Or use the upload panel in the UI for PDF, DOCX, XLSX, PPTX, CSV, HTML, RTF, EPUB, TXT, and MD files\n\n## Production notes\n\nThis is a starter template, not a production-ready setup. For production, consider:\n\n- **Vector store**: Replace the default store with pgvector, Pinecone, or Qdrant for datasets beyond ~10k chunks\n- **Reranking**: Add a cross-encoder reranker (e.g. Cohere Rerank) after retrieval to improve precision\n- **Hybrid search**: Combine dense vectors with BM25 keyword matching for better recall\n",
70
70
  "store.ts": "import { ragStore } from \"veryfront/embedding\";\n\nexport const store = ragStore({\n storagePath: \"data/index.json\",\n contentDir: \"content\",\n});\n",
71
71
  "tsconfig.json": "{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"bundler\",\n \"strict\": true,\n \"jsx\": \"react-jsx\",\n \"skipLibCheck\": true,\n \"esModuleInterop\": true,\n \"noEmit\": true,\n \"allowImportingTsExtensions\": true,\n \"paths\": {\n \"@/*\": [\"./*\"],\n \"react-markdown@*\": [\"./node_modules/react-markdown\"],\n \"remark-gfm@*\": [\"./node_modules/remark-gfm\"]\n }\n },\n \"include\": [\"**/*.ts\", \"**/*.tsx\"],\n \"exclude\": [\"node_modules\"]\n}\n"
72
72
  }
package/esm/deno.d.ts CHANGED
@@ -387,6 +387,7 @@ declare namespace _default {
387
387
  build: string;
388
388
  "build:proxy-lock": string;
389
389
  "build:npm": string;
390
+ "verify:dist": string;
390
391
  release: string;
391
392
  test: string;
392
393
  "test:unit": string;
package/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.1225",
3
+ "version": "0.1.1226",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "minimumDependencyAge": {
@@ -463,6 +463,7 @@ export default {
463
463
  "build": "deno task build:prepare && deno run -A scripts/build/compile-binary.ts --output ./bin/veryfront",
464
464
  "build:proxy-lock": "deno cache --node-modules-dir=none --lock scripts/build/proxy-deno.lock cli/proxy-main.ts",
465
465
  "build:npm": "deno run -A scripts/build/generate-integrations-module.ts && deno task generate && deno run --config=scripts/test.deno.json --frozen -A scripts/build/build-npm-dnt.ts",
466
+ "verify:dist": "deno task build && deno task build:npm",
466
467
  "release": "deno run -A scripts/release.ts",
467
468
  "test": "deno task generate && DENO_TESTING=1 VF_DISABLE_LRU_INTERVAL=1 SSR_TRANSFORM_PER_PROJECT_LIMIT=0 REVALIDATION_PER_PROJECT_LIMIT=0 NODE_ENV=production LOG_FORMAT=text deno test --preload=src/testing/preload.ts --no-check --parallel --allow-all '--ignore=tests/e2e,tests/integration/compiled-binary-e2e.test.ts,scripts' --unstable-worker-options --unstable-net",
468
469
  "test:unit": "deno task generate && DENO_TESTING=1 VF_DISABLE_LRU_INTERVAL=1 SSR_TRANSFORM_PER_PROJECT_LIMIT=0 REVALIDATION_PER_PROJECT_LIMIT=0 NODE_ENV=production LOG_FORMAT=text deno test --preload=src/testing/preload.ts --no-check --parallel --allow-all --v8-flags=--max-old-space-size=8192 '--ignore=tests,src/workflow/__tests__' --unstable-worker-options --unstable-net $(find src cli -name '*.test.ts*' ! -name '*.integration.test.ts*')",