veryfront 0.1.579 → 0.1.581

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/templates/manifest.js +1 -1
  3. package/esm/deno.js +3 -3
  4. package/esm/extensions/ext-sandbox-shell-tools/src/index.d.ts.map +1 -1
  5. package/esm/extensions/ext-sandbox-shell-tools/src/index.js +2 -20
  6. package/esm/src/integrations/remote-tools.d.ts +1 -2
  7. package/esm/src/integrations/remote-tools.d.ts.map +1 -1
  8. package/esm/src/integrations/remote-tools.js +40 -12
  9. package/esm/src/mcp/server.d.ts.map +1 -1
  10. package/esm/src/mcp/server.js +1 -6
  11. package/esm/src/schemas/index.d.ts +2 -4
  12. package/esm/src/schemas/index.d.ts.map +1 -1
  13. package/esm/src/schemas/index.js +2 -4
  14. package/esm/src/server/handlers/request/agent-stream.handler.d.ts.map +1 -1
  15. package/esm/src/server/handlers/request/agent-stream.handler.js +68 -1
  16. package/esm/src/server/index.d.ts +3 -4
  17. package/esm/src/server/index.d.ts.map +1 -1
  18. package/esm/src/server/index.js +4 -6
  19. package/esm/src/tool/types.d.ts +1 -1
  20. package/esm/src/transforms/esm/http-cache-state.d.ts.map +1 -1
  21. package/esm/src/transforms/esm/http-cache-state.js +19 -0
  22. package/esm/src/transforms/mdx/esm-module-loader/cache/index.d.ts.map +1 -1
  23. package/esm/src/transforms/mdx/esm-module-loader/cache/index.js +17 -0
  24. package/esm/src/utils/index.d.ts +1 -1
  25. package/esm/src/utils/index.js +1 -1
  26. package/esm/src/utils/memory/index.d.ts +1 -1
  27. package/esm/src/utils/memory/index.d.ts.map +1 -1
  28. package/esm/src/utils/memory/index.js +1 -1
  29. package/esm/src/utils/memory/profiler.d.ts +18 -0
  30. package/esm/src/utils/memory/profiler.d.ts.map +1 -1
  31. package/esm/src/utils/memory/profiler.js +34 -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 +1 -1
package/README.md CHANGED
@@ -68,7 +68,7 @@ brew install veryfront/tap/veryfront
68
68
 
69
69
  </details>
70
70
 
71
- Follow the [Quickstart guide](https://veryfront.com/docs/code/guides/quickstart) for step-by-step setup, or use [Create a project](https://veryfront.com/docs/code/guides/create-a-project) to compare templates before you scaffold. For the full documentation, visit [veryfront.com/docs/code](https://veryfront.com/docs/code).
71
+ Follow the [Quickstart guide](https://veryfront.com/docs/code/getting-started/quickstart) for step-by-step setup, or use [Create a project](https://veryfront.com/docs/code/getting-started/create-a-project) to compare templates before you scaffold. For the full documentation, visit [veryfront.com/docs/code](https://veryfront.com/docs/code).
72
72
 
73
73
  ## Project Structure
74
74
 
@@ -104,7 +104,7 @@ export default {
104
104
  "lib/oauth.ts": "import { type OAuthToken, tokenStore } from \"./token-store.ts\";\n\nexport interface OAuthProvider {\n name: string;\n authorizationUrl: string;\n tokenUrl: string;\n clientId: string;\n clientSecret: string;\n scopes: string[];\n callbackPath: string;\n}\n\nfunction getExpiresAt(expiresIn: unknown): number | undefined {\n if (typeof expiresIn !== \"number\" || expiresIn <= 0) return undefined;\n return Date.now() + expiresIn * 1000;\n}\n\nasync function postTokenRequest(\n provider: OAuthProvider,\n body: Record<string, string>,\n errorPrefix: string,\n): Promise<any> {\n const response = await fetch(provider.tokenUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams(body),\n });\n\n if (response.ok) return response.json();\n\n const error = await response.text();\n throw new Error(`${errorPrefix}: ${response.status} - ${error}`);\n}\n\nexport function getAuthorizationUrl(\n provider: OAuthProvider,\n state: string,\n redirectUri: string,\n): string {\n const params = new URLSearchParams({\n client_id: provider.clientId,\n redirect_uri: redirectUri,\n response_type: \"code\",\n scope: provider.scopes.join(\" \"),\n state,\n access_type: \"offline\",\n prompt: \"consent\",\n });\n\n return `${provider.authorizationUrl}?${params.toString()}`;\n}\n\nexport async function exchangeCodeForTokens(\n provider: OAuthProvider,\n code: string,\n redirectUri: string,\n): Promise<OAuthToken> {\n const data = await postTokenRequest(\n provider,\n {\n client_id: provider.clientId,\n client_secret: provider.clientSecret,\n code,\n grant_type: \"authorization_code\",\n redirect_uri: redirectUri,\n },\n \"Token exchange failed\",\n );\n\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token,\n expiresAt: getExpiresAt(data.expires_in),\n tokenType: data.token_type ?? \"Bearer\",\n scope: data.scope,\n };\n}\n\nexport async function refreshAccessToken(\n provider: OAuthProvider,\n refreshToken: string,\n): Promise<OAuthToken> {\n const data = await postTokenRequest(\n provider,\n {\n client_id: provider.clientId,\n client_secret: provider.clientSecret,\n refresh_token: refreshToken,\n grant_type: \"refresh_token\",\n },\n \"Token refresh failed\",\n );\n\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token ?? refreshToken,\n expiresAt: getExpiresAt(data.expires_in),\n tokenType: data.token_type ?? \"Bearer\",\n scope: data.scope,\n };\n}\n\nexport async function getValidToken(\n provider: OAuthProvider,\n userId: string,\n service: string,\n): Promise<string | null> {\n const token = await tokenStore.getToken(userId, service);\n if (!token) return null;\n\n const isExpired = token.expiresAt\n ? token.expiresAt < Date.now() + 5 * 60 * 1000\n : false;\n\n if (!isExpired || !token.refreshToken) return token.accessToken;\n\n try {\n const newToken = await refreshAccessToken(provider, token.refreshToken);\n await tokenStore.setToken(userId, service, newToken);\n return newToken.accessToken;\n } catch {\n await tokenStore.revokeToken(userId, service);\n return null;\n }\n}\n",
105
105
  "lib/token-store-examples.ts": "/****\n * Production Token Store Examples\n *\n * Copy-paste implementations for different storage backends.\n * Each example includes encryption support via TOKEN_ENCRYPTION_KEY.\n *\n * @module\n */\n\nimport { createTokenStore, tokenStore, type TokenStore } from \"./token-store.ts\";\n\n// ============================================================================\n// Vercel KV Store\n// ============================================================================\n\n/**\n * Token store using Vercel KV (Redis-compatible)\n *\n * Required environment variables:\n * - KV_REST_API_URL\n * - KV_REST_API_TOKEN\n * - TOKEN_ENCRYPTION_KEY (recommended)\n *\n * @example\n * ```typescript\n * // lib/token-store.ts\n * import { createVercelKVStore } from './token-store-examples';\n * export const tokenStore = createVercelKVStore();\n * ```\n */\nexport function createVercelKVStore(): TokenStore {\n type VercelKV = typeof import(\"@vercel/kv\");\n let kvPromise: Promise<VercelKV> | null = null;\n\n async function getKV(): Promise<VercelKV[\"kv\"]> {\n kvPromise ??= import(\"@vercel/kv\");\n return (await kvPromise).kv;\n }\n\n return createTokenStore({\n async get(key: string): Promise<string | null> {\n const kv = await getKV();\n return kv.get<string>(key);\n },\n async set(key: string, value: string): Promise<void> {\n const kv = await getKV();\n await kv.set(key, value);\n },\n async delete(key: string): Promise<void> {\n const kv = await getKV();\n await kv.del(key);\n },\n });\n}\n\n// ============================================================================\n// Redis Store\n// ============================================================================\n\n/**\n * Token store using Redis\n *\n * Required environment variables:\n * - REDIS_URL (e.g., redis://localhost:6379)\n * - TOKEN_ENCRYPTION_KEY (recommended)\n *\n * @example\n * ```typescript\n * // lib/token-store.ts\n * import { createRedisStore } from './token-store-examples';\n * export const tokenStore = createRedisStore();\n * ```\n */\nexport function createRedisStore(): TokenStore {\n let clientPromise: Promise<ReturnType<(typeof import(\"redis\"))[\"createClient\"]>> | null = null;\n\n async function getClient(): Promise<ReturnType<(typeof import(\"redis\"))[\"createClient\"]>> {\n clientPromise ??= (async () => {\n const { createClient } = await import(\"redis\");\n const client = createClient({ url: process.env.REDIS_URL });\n await client.connect();\n return client;\n })();\n\n return clientPromise;\n }\n\n return createTokenStore({\n async get(key: string): Promise<string | null> {\n const client = await getClient();\n return client.get(key);\n },\n async set(key: string, value: string): Promise<void> {\n const client = await getClient();\n await client.set(key, value);\n },\n async delete(key: string): Promise<void> {\n const client = await getClient();\n await client.del(key);\n },\n });\n}\n\n// ============================================================================\n// PostgreSQL Store\n// ============================================================================\n\n/**\n * Token store using PostgreSQL\n *\n * Required environment variables:\n * - DATABASE_URL (e.g., postgres://user:pass@host:5432/db)\n * - TOKEN_ENCRYPTION_KEY (recommended)\n *\n * Required table (create with migration):\n * ```sql\n * CREATE TABLE oauth_tokens (\n * key VARCHAR(255) PRIMARY KEY,\n * value TEXT NOT NULL,\n * created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n * updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n * );\n * CREATE INDEX idx_oauth_tokens_key ON oauth_tokens(key);\n * ```\n *\n * @example\n * ```typescript\n * // lib/token-store.ts\n * import { createPostgresStore } from './token-store-examples';\n * export const tokenStore = createPostgresStore();\n * ```\n */\nexport function createPostgresStore(): TokenStore {\n let poolPromise: Promise<import(\"pg\").Pool> | null = null;\n\n async function getPool(): Promise<import(\"pg\").Pool> {\n poolPromise ??= (async () => {\n const { Pool } = await import(\"pg\");\n return new Pool({ connectionString: process.env.DATABASE_URL });\n })();\n\n return poolPromise;\n }\n\n return createTokenStore({\n async get(key: string): Promise<string | null> {\n const pool = await getPool();\n const result = await pool.query(\"SELECT value FROM oauth_tokens WHERE key = $1\", [key]);\n return result.rows[0]?.value ?? null;\n },\n async set(key: string, value: string): Promise<void> {\n const pool = await getPool();\n await pool.query(\n `INSERT INTO oauth_tokens (key, value, updated_at)\n VALUES ($1, $2, NOW())\n ON CONFLICT (key) DO UPDATE SET value = $2, updated_at = NOW()`,\n [key, value],\n );\n },\n async delete(key: string): Promise<void> {\n const pool = await getPool();\n await pool.query(\"DELETE FROM oauth_tokens WHERE key = $1\", [key]);\n },\n });\n}\n\n// ============================================================================\n// SQLite Store (for edge/serverless with D1, Turso, etc.)\n// ============================================================================\n\n/**\n * Token store using SQLite (Cloudflare D1, Turso, better-sqlite3)\n *\n * Required table:\n * ```sql\n * CREATE TABLE oauth_tokens (\n * key TEXT PRIMARY KEY,\n * value TEXT NOT NULL,\n * updated_at INTEGER DEFAULT (strftime('%s', 'now'))\n * );\n * ```\n *\n * @param db - SQLite database instance (D1Database, Connection, or Database)\n *\n * @example With Cloudflare D1\n * ```typescript\n * // In your API route\n * export async function GET(request: Request, { env }) {\n * const tokenStore = createSQLiteStore(env.DB);\n * // ...\n * }\n * ```\n *\n * @example With Turso\n * ```typescript\n * import { createClient } from '@libsql/client';\n * const db = createClient({ url: process.env.TURSO_URL, authToken: process.env.TURSO_AUTH_TOKEN });\n * export const tokenStore = createSQLiteStore(db);\n * ```\n */\nexport function createSQLiteStore(db: {\n prepare(sql: string): {\n bind(...args: unknown[]): { first(): Promise<{ value?: string } | null>; run(): Promise<void> };\n };\n}): TokenStore {\n return createTokenStore({\n async get(key: string): Promise<string | null> {\n const result = await db.prepare(\"SELECT value FROM oauth_tokens WHERE key = ?\").bind(key).first();\n return result?.value ?? null;\n },\n async set(key: string, value: string): Promise<void> {\n await db\n .prepare(\n `INSERT OR REPLACE INTO oauth_tokens (key, value, updated_at)\n VALUES (?, ?, strftime('%s', 'now'))`,\n )\n .bind(key, value)\n .run();\n },\n async delete(key: string): Promise<void> {\n await db.prepare(\"DELETE FROM oauth_tokens WHERE key = ?\").bind(key).run();\n },\n });\n}\n\n// ============================================================================\n// Cloudflare Workers KV Store\n// ============================================================================\n\n/**\n * Token store using Cloudflare Workers KV\n *\n * @param kv - KV namespace binding from worker environment\n *\n * @example\n * ```typescript\n * // In your worker\n * export default {\n * async fetch(request, env) {\n * const tokenStore = createWorkersKVStore(env.OAUTH_TOKENS);\n * // ...\n * }\n * };\n * ```\n */\nexport function createWorkersKVStore(kv: {\n get(key: string): Promise<string | null>;\n put(key: string, value: string): Promise<void>;\n delete(key: string): Promise<void>;\n}): TokenStore {\n return createTokenStore({\n get(key: string): Promise<string | null> {\n return kv.get(key);\n },\n set(key: string, value: string): Promise<void> {\n return kv.put(key, value);\n },\n delete(key: string): Promise<void> {\n return kv.delete(key);\n },\n });\n}\n\n// ============================================================================\n// Prisma Store\n// ============================================================================\n\n/**\n * Token store using Prisma ORM\n *\n * Required Prisma schema:\n * ```prisma\n * model OAuthToken {\n * key String @id\n * value String\n * updatedAt DateTime @updatedAt\n * }\n * ```\n *\n * @example\n * ```typescript\n * import { PrismaClient } from '@prisma/client';\n * const prisma = new PrismaClient();\n * export const tokenStore = createPrismaStore(prisma);\n * ```\n */\nexport function createPrismaStore(prisma: {\n oAuthToken: {\n findUnique(args: { where: { key: string } }): Promise<{ value: string } | null>;\n upsert(args: {\n where: { key: string };\n update: { value: string };\n create: { key: string; value: string };\n }): Promise<unknown>;\n delete(args: { where: { key: string } }): Promise<unknown>;\n };\n}): TokenStore {\n return createTokenStore({\n async get(key: string): Promise<string | null> {\n const record = await prisma.oAuthToken.findUnique({ where: { key } });\n return record?.value ?? null;\n },\n async set(key: string, value: string): Promise<void> {\n await prisma.oAuthToken.upsert({\n where: { key },\n update: { value },\n create: { key, value },\n });\n },\n async delete(key: string): Promise<void> {\n try {\n await prisma.oAuthToken.delete({ where: { key } });\n } catch {\n // Ignore if not found\n }\n },\n });\n}\n\n// ============================================================================\n// Drizzle ORM Store\n// ============================================================================\n\n/**\n * Token store using Drizzle ORM\n *\n * Required schema:\n * ```typescript\n * import { pgTable, text, timestamp } from 'drizzle-orm/pg-core';\n *\n * export const oauthTokens = pgTable('oauth_tokens', {\n * key: text('key').primaryKey(),\n * value: text('value').notNull(),\n * updatedAt: timestamp('updated_at').defaultNow(),\n * });\n * ```\n *\n * @example\n * ```typescript\n * import { drizzle } from 'drizzle-orm/postgres-js';\n * import postgres from 'postgres';\n * import { oauthTokens } from './schema';\n *\n * const client = postgres(process.env.DATABASE_URL!);\n * const db = drizzle(client);\n * export const tokenStore = createDrizzleStore(db, oauthTokens);\n * ```\n */\nexport function createDrizzleStore<T extends { key: unknown; value: unknown }>(\n db: {\n select(): {\n from(table: T): { where(condition: unknown): { get(): Promise<{ value: string } | undefined> } };\n };\n insert(table: T): {\n values(data: { key: string; value: string }): {\n onConflictDoUpdate(args: { target: unknown; set: { value: string } }): { execute(): Promise<void> };\n };\n };\n delete(table: T): { where(condition: unknown): { execute(): Promise<void> } };\n },\n table: T & { key: unknown; value: unknown },\n eq: (col: unknown, val: unknown) => unknown,\n): TokenStore {\n return createTokenStore({\n async get(key: string): Promise<string | null> {\n const result = await db.select().from(table).where(eq(table.key, key)).get();\n return result?.value ?? null;\n },\n async set(key: string, value: string): Promise<void> {\n await db\n .insert(table)\n .values({ key, value })\n .onConflictDoUpdate({ target: table.key, set: { value } })\n .execute();\n },\n async delete(key: string): Promise<void> {\n await db.delete(table).where(eq(table.key, key)).execute();\n },\n });\n}\n\n// ============================================================================\n// Auto-Select Store (Recommended)\n// ============================================================================\n\n/**\n * Automatically selects the appropriate token store based on environment\n *\n * Detection order:\n * 1. DATABASE_URL -> PostgreSQL\n * 2. KV_REST_API_URL -> Vercel KV\n * 3. REDIS_URL -> Redis\n * 4. Fallback -> In-memory (development only)\n *\n * @example\n * ```typescript\n * // lib/token-store.ts\n * import { createAutoStore } from './token-store-examples';\n * export const tokenStore = createAutoStore();\n * ```\n */\nexport function createAutoStore(): TokenStore {\n const env = process.env;\n\n if (env.DATABASE_URL) {\n console.log(\"[Token Store] Using PostgreSQL storage\");\n return createPostgresStore();\n }\n\n if (env.KV_REST_API_URL && env.KV_REST_API_TOKEN) {\n console.log(\"[Token Store] Using Vercel KV storage\");\n return createVercelKVStore();\n }\n\n if (env.REDIS_URL) {\n console.log(\"[Token Store] Using Redis storage\");\n return createRedisStore();\n }\n\n console.warn(\n \"[Token Store] No production storage configured. \" +\n \"Using in-memory storage (tokens will be lost on restart). \" +\n \"Set DATABASE_URL, KV_REST_API_URL, or REDIS_URL for production.\",\n );\n\n return tokenStore;\n}\n",
106
106
  "lib/token-store.ts": "/********************************************************************************\n * OAuth Token Store\n *\n * Manages OAuth tokens for connected services.\n *\n * ## Storage Modes\n *\n * **Development (default)**: In-memory storage - tokens are lost on restart.\n * **Production**: Configure via environment variables:\n * - DATABASE_URL: Uses database storage (Postgres, SQLite, MySQL)\n * - KV_REST_API_URL + KV_REST_API_TOKEN: Uses Vercel KV\n * - REDIS_URL: Uses Redis\n * - TOKEN_ENCRYPTION_KEY: Enables AES-256-GCM encryption (recommended)\n *\n * ## Security\n *\n * Tokens contain sensitive OAuth credentials. In production:\n * 1. Always use encrypted storage (set TOKEN_ENCRYPTION_KEY)\n * 2. Use HTTPS for all connections\n * 3. Implement proper access control\n * 4. Rotate encryption keys periodically\n *\n * @see lib/token-store-examples.ts for complete production implementations\n ********************************************************************************/\n\nexport interface OAuthToken {\n accessToken: string;\n refreshToken?: string;\n expiresAt?: number;\n tokenType?: string;\n scope?: string;\n}\n\nexport interface TokenStore {\n getToken(userId: string, service: string): Promise<OAuthToken | null>;\n setToken(userId: string, service: string, token: OAuthToken): Promise<void>;\n revokeToken(userId: string, service: string): Promise<void>;\n isConnected(userId: string, service: string): Promise<boolean>;\n}\n\n/** Token store configuration for production backends */\nexport interface TokenStoreConfig {\n get: (key: string) => Promise<string | null>;\n set: (key: string, value: string) => Promise<void>;\n delete: (key: string) => Promise<void>;\n}\n\nconst AUTO_KEY_STORAGE = \"__veryfront_auto_encryption_key__\";\nconst TOKENS_KEY = \"__veryfront_oauth_tokens__\";\n\nconst globalStore = globalThis as Record<string, unknown>;\n\n// ============================================================================\n// Encryption Utilities\n// ============================================================================\n\nexport async function encryptToken(token: OAuthToken): Promise<string> {\n const key = getEncryptionKey();\n if (!key) return JSON.stringify(token);\n\n const data = new TextEncoder().encode(JSON.stringify(token));\n const iv = crypto.getRandomValues(new Uint8Array(12));\n const rawKey = new Uint8Array(key).buffer;\n\n const cryptoKey = await crypto.subtle.importKey(\"raw\", rawKey, \"AES-GCM\", false, [\"encrypt\"]);\n const encrypted = await crypto.subtle.encrypt({ name: \"AES-GCM\", iv }, cryptoKey, data);\n\n const combined = new Uint8Array(iv.length + encrypted.byteLength);\n combined.set(iv);\n combined.set(new Uint8Array(encrypted), iv.length);\n\n return `encrypted:${btoa(String.fromCharCode(...combined))}`;\n}\n\nexport async function decryptToken(encrypted: string): Promise<OAuthToken | null> {\n if (!encrypted.startsWith(\"encrypted:\")) {\n try {\n return JSON.parse(encrypted) as OAuthToken;\n } catch {\n return null;\n }\n }\n\n const key = getEncryptionKey();\n if (!key) {\n console.error(\"[Token Store] Cannot decrypt: TOKEN_ENCRYPTION_KEY not set\");\n return null;\n }\n\n try {\n const base64 = encrypted.slice(\"encrypted:\".length);\n const combined = Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));\n\n const iv = combined.slice(0, 12);\n const ciphertext = combined.slice(12);\n const rawKey = new Uint8Array(key).buffer;\n\n const cryptoKey = await crypto.subtle.importKey(\"raw\", rawKey, \"AES-GCM\", false, [\"decrypt\"]);\n const decrypted = await crypto.subtle.decrypt({ name: \"AES-GCM\", iv }, cryptoKey, ciphertext);\n\n return JSON.parse(new TextDecoder().decode(decrypted)) as OAuthToken;\n } catch {\n console.error(\"[Token Store] Decryption failed\");\n return null;\n }\n}\n\nexport function generateEncryptionKey(): string {\n const bytes = crypto.getRandomValues(new Uint8Array(32));\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\nfunction getEnvVar(name: string): string | undefined {\n if (typeof process !== \"undefined\") return process.env?.[name];\n return (globalThis as { Deno?: { env?: { get?: (key: string) => string | undefined } } }).Deno\n ?.env?.get?.(name);\n}\n\nfunction hexToKeyBytes(keyHex: string): Uint8Array | null {\n if (keyHex.length !== 64) {\n console.error(\"[Token Store] TOKEN_ENCRYPTION_KEY must be 64 hex characters (32 bytes)\");\n return null;\n }\n\n const key = new Uint8Array(32);\n for (let i = 0; i < 32; i++) {\n key[i] = parseInt(keyHex.slice(i * 2, i * 2 + 2), 16);\n }\n return key;\n}\n\n/** Get encryption key from environment or auto-generate for development */\nfunction getEncryptionKey(): Uint8Array | null {\n const keyHex = getEnvVar(\"TOKEN_ENCRYPTION_KEY\");\n if (keyHex) return hexToKeyBytes(keyHex);\n\n if (!globalStore[AUTO_KEY_STORAGE]) {\n globalStore[AUTO_KEY_STORAGE] = generateEncryptionKey();\n }\n\n return hexToKeyBytes(globalStore[AUTO_KEY_STORAGE] as string);\n}\n\n// ============================================================================\n// Storage Mode Detection\n// ============================================================================\n\nexport type StorageMode = \"memory\" | \"database\" | \"kv\" | \"redis\" | \"custom\";\n\nexport function getStorageMode(): StorageMode {\n const env = typeof process !== \"undefined\"\n ? process.env\n : (globalThis as { Deno?: { env?: { toObject?: () => Record<string, string> } } }).Deno?.env\n ?.toObject?.() ?? {};\n\n if (env.DATABASE_URL) return \"database\";\n if (env.KV_REST_API_URL) return \"kv\";\n if (env.REDIS_URL) return \"redis\";\n return \"memory\";\n}\n\nexport function isEncryptionEnabled(): boolean {\n return getEncryptionKey() !== null;\n}\n\nfunction isProductionRuntime(): boolean {\n return getEnvVar(\"NODE_ENV\") === \"production\";\n}\n\n// ============================================================================\n// In-Memory Store (Development)\n// ============================================================================\n\nconst tokens = (globalStore[TOKENS_KEY] as Map<string, OAuthToken> | undefined) ??\n new Map<string, OAuthToken>();\nglobalStore[TOKENS_KEY] = tokens;\n\nfunction getKey(userId: string, service: string): string {\n return `${userId}:${service}`;\n}\n\nasync function isConnected(\n store: Pick<TokenStore, \"getToken\">,\n userId: string,\n service: string,\n): Promise<boolean> {\n const token = await store.getToken(userId, service);\n return !!token && (!token.expiresAt || token.expiresAt > Date.now());\n}\n\nconst inMemoryStore: TokenStore = {\n async getToken(userId: string, service: string): Promise<OAuthToken | null> {\n return tokens.get(getKey(userId, service)) ?? null;\n },\n\n async setToken(userId: string, service: string, token: OAuthToken): Promise<void> {\n tokens.set(getKey(userId, service), token);\n },\n\n async revokeToken(userId: string, service: string): Promise<void> {\n tokens.delete(getKey(userId, service));\n },\n\n async isConnected(userId: string, service: string): Promise<boolean> {\n return isConnected(this, userId, service);\n },\n};\n\n// ============================================================================\n// Token Store Factory\n// ============================================================================\n\nexport function createTokenStore(config: TokenStoreConfig): TokenStore {\n return {\n async getToken(userId: string, service: string): Promise<OAuthToken | null> {\n const data = await config.get(getKey(userId, service));\n if (!data) return null;\n return decryptToken(data);\n },\n\n async setToken(userId: string, service: string, token: OAuthToken): Promise<void> {\n await config.set(getKey(userId, service), await encryptToken(token));\n },\n\n async revokeToken(userId: string, service: string): Promise<void> {\n await config.delete(getKey(userId, service));\n },\n\n async isConnected(userId: string, service: string): Promise<boolean> {\n return isConnected(this, userId, service);\n },\n };\n}\n\n// ============================================================================\n// Default Export (Auto-detects environment)\n// ============================================================================\n\nexport function createDefaultTokenStore(): TokenStore {\n if (isProductionRuntime()) {\n throw new Error(\n \"In-memory token storage is not allowed in production. \" +\n \"Configure DATABASE_URL, KV_REST_API_URL, or REDIS_URL and wire a durable store from \" +\n \"lib/token-store-examples.ts.\",\n );\n }\n\n // The starter keeps the development store explicit. Production adapters in\n // token-store-examples.ts require provider-specific clients and credentials.\n return inMemoryStore;\n}\n\nlet defaultTokenStore: TokenStore | null = null;\n\nfunction getDefaultTokenStore(): TokenStore {\n defaultTokenStore ??= createDefaultTokenStore();\n return defaultTokenStore;\n}\n\nexport const tokenStore: TokenStore = {\n getToken(userId: string, service: string): Promise<OAuthToken | null> {\n return getDefaultTokenStore().getToken(userId, service);\n },\n\n setToken(userId: string, service: string, token: OAuthToken): Promise<void> {\n return getDefaultTokenStore().setToken(userId, service, token);\n },\n\n revokeToken(userId: string, service: string): Promise<void> {\n return getDefaultTokenStore().revokeToken(userId, service);\n },\n\n isConnected(userId: string, service: string): Promise<boolean> {\n return getDefaultTokenStore().isConnected(userId, service);\n },\n};\n\nif (\n !isProductionRuntime() &&\n getStorageMode() === \"memory\"\n) {\n console.warn(\n \"[Token Store] Using in-memory storage (development mode). \" +\n \"Tokens will be lost on restart. \" +\n \"Set DATABASE_URL, KV_REST_API_URL, or REDIS_URL for production.\",\n );\n}\n",
107
- "lib/user-id.ts": "import type { ToolExecutionContext } from \"veryfront/tool\";\n\nfunction isProductionRuntime(): boolean {\n return Deno.env.get(\"NODE_ENV\") === \"production\";\n}\n\nfunction devUserId(): string {\n return Deno.env.get(\"VERYFRONT_DEV_USER_ID\") ?? \"dev-user\";\n}\n\nfunction requireUserId(value: string | null | undefined): string {\n if (typeof value === \"string\" && value.length > 0) {\n return value;\n }\n\n if (!isProductionRuntime()) {\n return devUserId();\n }\n\n throw new Error(\n \"Authenticated user id is required in production. \" +\n \"Pass the authenticated user's id from your session, JWT, or auth provider.\",\n );\n}\n\nexport function requireUserIdFromRequest(request: Request): string {\n return requireUserId(\n request.headers.get(\"x-veryfront-user-id\") ?? request.headers.get(\"x-user-id\"),\n );\n}\n\nexport function requireUserIdFromContext(context?: ToolExecutionContext): string {\n return requireUserId(context?.endUserId ?? context?.userId);\n}\n",
107
+ "lib/user-id.ts": "import type { ToolExecutionContext } from \"veryfront/tool\";\n\nfunction isProductionRuntime(): boolean {\n return Deno.env.get(\"NODE_ENV\") === \"production\";\n}\n\nfunction devUserId(): string {\n return Deno.env.get(\"VERYFRONT_DEV_USER_ID\") ?? \"dev-user\";\n}\n\nfunction requireUserId(value: string | null | undefined): string {\n if (typeof value === \"string\" && value.length > 0) {\n return value;\n }\n\n if (!isProductionRuntime()) {\n return devUserId();\n }\n\n throw new Error(\n \"Authenticated user id is required in production. \" +\n \"Pass the authenticated user's id from your session, JWT, or auth provider.\",\n );\n}\n\nexport function requireUserIdFromRequest(request: Request): string {\n return requireUserId(\n request.headers.get(\"x-veryfront-user-id\") ?? request.headers.get(\"x-user-id\"),\n );\n}\n\nexport function requireUserIdFromContext(context?: ToolExecutionContext): string {\n return requireUserId(context?.userId);\n}\n",
108
108
  "SETUP.md": "# Integration Setup Guide\n\nThis guide helps you set up credentials for all 50+ service integrations available in Veryfront.\n\n## Quick Start\n\n```bash\n# Create a new project with integrations\nveryfront init my-app --with ai --integrations slack,github,notion\n\n# Start development\ncd my-app\nveryfront dev\n```\n\nVisit `http://localhost:3000/api/auth/{service}` to connect each service.\n\n---\n\n## Table of Contents\n\n- [Google Services](#google-services) (Gmail, Calendar, Drive, Docs, Sheets)\n- [Microsoft Services](#microsoft-services) (Outlook, Teams, SharePoint, OneDrive)\n- [Atlassian Services](#atlassian-services) (Jira, Confluence)\n- [Communication](#communication) (Slack, Discord, Twilio, Zoom, Webex)\n- [Project Management](#project-management) (Asana, Monday, Trello, ClickUp, Linear, Notion)\n- [Developer Tools](#developer-tools) (GitHub, GitLab, Bitbucket, Figma, Sentry, PostHog)\n- [CRM & Sales](#crm--sales) (Salesforce, HubSpot, Pipedrive, Intercom, Zendesk, Freshdesk)\n- [Databases](#databases) (Supabase, Neon, Airtable, Snowflake)\n- [Cloud & Storage](#cloud--storage) (AWS, Dropbox, Box)\n- [Finance](#finance) (Stripe, QuickBooks, Xero)\n- [Marketing](#marketing) (Mailchimp, Twitter)\n- [E-commerce](#e-commerce) (Shopify)\n- [AI & Analytics](#ai--analytics) (Anthropic, Mixpanel)\n\n---\n\n## Google Services\n\n**Gmail, Calendar, Drive, Docs, Sheets** all use the same Google OAuth credentials.\n\n### Setup Steps\n\n1. Go to [Google Cloud Console](https://console.cloud.google.com/apis/credentials)\n2. Create a new project or select existing\n3. Enable required APIs:\n - Gmail API\n - Google Calendar API\n - Google Drive API\n - Google Docs API\n - Google Sheets API\n4. Go to **OAuth consent screen**:\n - User Type: External (or Internal for Workspace)\n - Add scopes for each API you need\n5. Go to **Credentials** > **Create Credentials** > **OAuth client ID**:\n - Application type: Web application\n - Authorized redirect URIs:\n ```\n http://localhost:3000/api/auth/gmail/callback\n http://localhost:3000/api/auth/calendar/callback\n http://localhost:3000/api/auth/drive/callback\n http://localhost:3000/api/auth/docs-google/callback\n http://localhost:3000/api/auth/sheets/callback\n ```\n\n### Environment Variables\n\n```env\nGOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com\nGOOGLE_CLIENT_SECRET=your-client-secret\n```\n\n### Required Scopes by Service\n\n| Service | Scopes |\n| -------- | -------------------------------------------------------------------------------------------------------------------------------- |\n| Gmail | `gmail.readonly`, `gmail.send`, `gmail.modify`, `gmail.labels`, `gmail.compose`, `https://mail.google.com/` for permanent delete |\n| Calendar | `calendar.readonly`, `calendar.events` |\n| Drive | `drive.readonly`, `drive.file` |\n| Docs | `documents.readonly`, `documents` |\n| Sheets | `spreadsheets.readonly`, `spreadsheets` |\n\n---\n\n## Microsoft Services\n\n**Outlook, Teams, SharePoint, OneDrive** use Microsoft OAuth (Azure AD).\n\n### Setup Steps\n\n1. Go to [Azure Portal](https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade)\n2. Click **New registration**:\n - Name: Your app name\n - Supported account types: Accounts in any organizational directory\n - Redirect URI: Web, `http://localhost:3000/api/auth/outlook/callback`\n3. After creation, go to **Certificates & secrets**:\n - Create a new client secret\n4. Go to **API permissions**:\n - Add Microsoft Graph permissions\n\n### Environment Variables\n\n```env\nMICROSOFT_CLIENT_ID=your-application-client-id\nMICROSOFT_CLIENT_SECRET=your-client-secret\nMICROSOFT_TENANT_ID=common\n```\n\n### Required Scopes by Service\n\n| Service | Scopes |\n| ---------- | ------------------------------------------------------------- |\n| Outlook | `Mail.Read`, `Mail.Send`, `Calendars.ReadWrite` |\n| Teams | `Team.ReadBasic.All`, `Chat.ReadWrite`, `ChannelMessage.Send` |\n| SharePoint | `Sites.Read.All`, `Files.ReadWrite.All` |\n| OneDrive | `Files.Read`, `Files.ReadWrite` |\n\n---\n\n## Atlassian Services\n\n**Jira and Confluence** use Atlassian OAuth 2.0 (3LO).\n\n### Setup Steps\n\n1. Go to [Atlassian Developer Console](https://developer.atlassian.com/console/myapps/)\n2. Click **Create** > **OAuth 2.0 integration**\n3. Configure:\n - Name: Your app name\n - Callback URL: `http://localhost:3000/api/auth/jira/callback`\n4. Add required scopes in **Permissions**\n5. Get your Cloud ID: Visit `https://your-domain.atlassian.net/_edge/tenant_info`\n\n### Environment Variables\n\n```env\nATLASSIAN_CLIENT_ID=your-client-id\nATLASSIAN_CLIENT_SECRET=your-client-secret\nATLASSIAN_CLOUD_ID=your-cloud-id\n```\n\n### Required Scopes\n\n| Service | Scopes |\n| ---------- | --------------------------------------------------------- |\n| Jira | `read:jira-work`, `write:jira-work`, `read:jira-user` |\n| Confluence | `read:confluence-content.all`, `write:confluence-content` |\n\n---\n\n## Communication\n\n### Slack\n\n1. Go to [Slack API Apps](https://api.slack.com/apps)\n2. Click **Create New App** > **From scratch**\n3. Go to **OAuth & Permissions**:\n - Add redirect URL: `http://localhost:3000/api/auth/slack/callback`\n - Add scopes: `channels:history`, `channels:read`, `chat:write`, `groups:history`, `groups:read`, `im:history`, `im:read`, `mpim:history`, `mpim:read`, `users:read`\n4. **Install to Workspace**\n\n```env\nSLACK_CLIENT_ID=your-client-id\nSLACK_CLIENT_SECRET=your-client-secret\n```\n\n### Discord\n\n1. Go to [Discord Developer Portal](https://discord.com/developers/applications)\n2. Create **New Application**\n3. Go to **OAuth2**:\n - Add redirect: `http://localhost:3000/api/auth/discord/callback`\n - Scopes: `identify`, `guilds`, `messages.read`\n\n```env\nDISCORD_CLIENT_ID=your-client-id\nDISCORD_CLIENT_SECRET=your-client-secret\n```\n\n### Twilio (SMS/WhatsApp)\n\n1. Go to [Twilio Console](https://console.twilio.com/)\n2. Get Account SID and Auth Token from dashboard\n3. Get or buy a phone number for sending\n\n```env\nTWILIO_ACCOUNT_SID=your-account-sid\nTWILIO_AUTH_TOKEN=your-auth-token\nTWILIO_PHONE_NUMBER=+1234567890\n```\n\n### Zoom\n\n1. Go to [Zoom App Marketplace](https://marketplace.zoom.us/develop/create)\n2. Create **OAuth App**\n3. Configure redirect: `http://localhost:3000/api/auth/zoom/callback`\n4. Add scopes: `meeting:read`, `meeting:write`, `user:read`\n\n```env\nZOOM_CLIENT_ID=your-client-id\nZOOM_CLIENT_SECRET=your-client-secret\n```\n\n### Webex\n\n1. Go to [Webex for Developers](https://developer.webex.com/my-apps)\n2. Create new integration\n3. Redirect URI: `http://localhost:3000/api/auth/webex/callback`\n4. Scopes: `spark:messages_read`, `spark:messages_write`, `spark:rooms_read`\n\n```env\nWEBEX_CLIENT_ID=your-client-id\nWEBEX_CLIENT_SECRET=your-client-secret\n```\n\n---\n\n## Project Management\n\n### Asana\n\n1. Go to [Asana Developer Console](https://app.asana.com/0/developer-console)\n2. Create new app\n3. Set redirect URL: `http://localhost:3000/api/auth/asana/callback`\n\n```env\nASANA_CLIENT_ID=your-client-id\nASANA_CLIENT_SECRET=your-client-secret\n```\n\n### Monday.com\n\n1. Go to [Monday Apps](https://auth.monday.com/oauth2/authorize)\n2. Create new app in your account's Developer section\n3. Configure OAuth with redirect: `http://localhost:3000/api/auth/monday/callback`\n\n```env\nMONDAY_CLIENT_ID=your-client-id\nMONDAY_CLIENT_SECRET=your-client-secret\n```\n\n### Trello\n\n1. Go to [Trello Power-Ups Admin](https://trello.com/power-ups/admin)\n2. Create new Power-Up\n3. Configure OAuth redirect: `http://localhost:3000/api/auth/trello/callback`\n\n```env\nTRELLO_API_KEY=your-api-key\nTRELLO_API_SECRET=your-api-secret\n```\n\n### ClickUp\n\n1. Go to [ClickUp API Settings](https://app.clickup.com/settings/apps)\n2. Create new app\n3. Redirect URL: `http://localhost:3000/api/auth/clickup/callback`\n\n```env\nCLICKUP_CLIENT_ID=your-client-id\nCLICKUP_CLIENT_SECRET=your-client-secret\n```\n\n### Linear\n\n1. Go to [Linear Settings > API](https://linear.app/settings/api)\n2. Create OAuth application\n3. Callback URL: `http://localhost:3000/api/auth/linear/callback`\n\n```env\nLINEAR_CLIENT_ID=your-client-id\nLINEAR_CLIENT_SECRET=your-client-secret\n```\n\n### Notion\n\n1. Go to [Notion Integrations](https://www.notion.so/my-integrations)\n2. Create new **public** integration (for OAuth)\n3. Set redirect URI: `http://localhost:3000/api/auth/notion/callback`\n4. **Important**: Share pages with your integration\n\n```env\nNOTION_CLIENT_ID=your-oauth-client-id\nNOTION_CLIENT_SECRET=your-oauth-client-secret\n```\n\n---\n\n## Developer Tools\n\n### GitHub\n\n1. Go to [GitHub Developer Settings](https://github.com/settings/developers)\n2. Create **New OAuth App**\n3. Authorization callback: `http://localhost:3000/api/auth/github/callback`\n\n```env\nGITHUB_CLIENT_ID=your-client-id\nGITHUB_CLIENT_SECRET=your-client-secret\n```\n\n### GitLab\n\n1. Go to [GitLab Applications](https://gitlab.com/-/profile/applications)\n2. Create new application\n3. Redirect URI: `http://localhost:3000/api/auth/gitlab/callback`\n4. Scopes: `read_user`, `read_api`, `read_repository`\n\n```env\nGITLAB_CLIENT_ID=your-application-id\nGITLAB_CLIENT_SECRET=your-secret\n```\n\n### Bitbucket\n\n1. Go to [Bitbucket App Passwords](https://bitbucket.org/account/settings/app-passwords/) or create OAuth consumer\n2. For OAuth: Workspace settings > OAuth consumers\n3. Callback URL: `http://localhost:3000/api/auth/bitbucket/callback`\n\n```env\nBITBUCKET_CLIENT_ID=your-client-id\nBITBUCKET_CLIENT_SECRET=your-client-secret\n```\n\n### Figma\n\n1. Go to [Figma Developers](https://www.figma.com/developers/apps)\n2. Create new app\n3. Callback URL: `http://localhost:3000/api/auth/figma/callback`\n\n```env\nFIGMA_CLIENT_ID=your-client-id\nFIGMA_CLIENT_SECRET=your-client-secret\n```\n\n### Sentry\n\n1. Go to [Sentry Developer Settings](https://sentry.io/settings/developer-settings/)\n2. Create new public integration\n3. Redirect URL: `http://localhost:3000/api/auth/sentry/callback`\n\n```env\nSENTRY_CLIENT_ID=your-client-id\nSENTRY_CLIENT_SECRET=your-client-secret\n```\n\n### PostHog\n\nUses API key authentication (no OAuth).\n\n1. Go to your PostHog project settings\n2. Create a personal API key\n\n```env\nPOSTHOG_API_KEY=phx_your-api-key\nPOSTHOG_HOST=https://app.posthog.com\n```\n\n---\n\n## CRM & Sales\n\n### Salesforce\n\n1. Go to [Salesforce Setup](https://login.salesforce.com/) > App Manager\n2. Create **New Connected App**\n3. Enable OAuth, add callback: `http://localhost:3000/api/auth/salesforce/callback`\n4. Required scopes: `api`, `refresh_token`\n\n```env\nSALESFORCE_CLIENT_ID=your-consumer-key\nSALESFORCE_CLIENT_SECRET=your-consumer-secret\n```\n\n### HubSpot\n\n1. Go to [HubSpot Developers](https://developers.hubspot.com/)\n2. Create app in your developer account\n3. Configure OAuth redirect: `http://localhost:3000/api/auth/hubspot/callback`\n4. Select required scopes\n\n```env\nHUBSPOT_CLIENT_ID=your-client-id\nHUBSPOT_CLIENT_SECRET=your-client-secret\n```\n\n### Pipedrive\n\n1. Go to [Pipedrive Marketplace Manager](https://developers.pipedrive.com/)\n2. Create new app\n3. OAuth redirect: `http://localhost:3000/api/auth/pipedrive/callback`\n\n```env\nPIPEDRIVE_CLIENT_ID=your-client-id\nPIPEDRIVE_CLIENT_SECRET=your-client-secret\n```\n\n### Intercom\n\n1. Go to [Intercom Developer Hub](https://developers.intercom.com/)\n2. Create new app\n3. Configure OAuth: `http://localhost:3000/api/auth/intercom/callback`\n\n```env\nINTERCOM_CLIENT_ID=your-client-id\nINTERCOM_CLIENT_SECRET=your-client-secret\n```\n\n### Zendesk\n\n1. Go to Admin Center > Apps and integrations > APIs > Zendesk API\n2. Create OAuth client\n3. Redirect URL: `http://localhost:3000/api/auth/zendesk/callback`\n\n```env\nZENDESK_CLIENT_ID=your-client-id\nZENDESK_CLIENT_SECRET=your-client-secret\nZENDESK_SUBDOMAIN=your-subdomain\n```\n\n### Freshdesk\n\nUses API key authentication.\n\n1. Go to Profile Settings in Freshdesk\n2. Find your API Key\n\n```env\nFRESHDESK_API_KEY=your-api-key\nFRESHDESK_DOMAIN=your-domain.freshdesk.com\n```\n\n---\n\n## Databases\n\n### Supabase\n\nUses API key (no OAuth needed).\n\n1. Go to your Supabase project dashboard\n2. Go to Settings > API\n3. Copy the `anon` or `service_role` key\n\n```env\nSUPABASE_URL=https://your-project.supabase.co\nSUPABASE_ANON_KEY=your-anon-key\nSUPABASE_SERVICE_ROLE_KEY=your-service-role-key\n```\n\n### Neon\n\nUses API key authentication.\n\n1. Go to [Neon Console](https://console.neon.tech/)\n2. Create API key in Account Settings\n\n```env\nNEON_API_KEY=your-api-key\nNEON_PROJECT_ID=your-project-id\n```\n\n### Airtable\n\n1. Go to [Airtable Account](https://airtable.com/account)\n2. Create personal access token or OAuth app\n3. For OAuth: [Airtable OAuth](https://airtable.com/create/oauth)\n\n```env\nAIRTABLE_API_KEY=your-api-key\n# Or for OAuth:\nAIRTABLE_CLIENT_ID=your-client-id\nAIRTABLE_CLIENT_SECRET=your-client-secret\n```\n\n### Snowflake\n\nUses account credentials (key-pair or password).\n\n1. Get your Snowflake account identifier\n2. Create a user with appropriate permissions\n3. (Optional) Set up key-pair authentication\n\n```env\nSNOWFLAKE_ACCOUNT=your-account-identifier\nSNOWFLAKE_USERNAME=your-username\nSNOWFLAKE_PASSWORD=your-password\nSNOWFLAKE_WAREHOUSE=your-warehouse\nSNOWFLAKE_DATABASE=your-database\n```\n\n---\n\n## Cloud & Storage\n\n### AWS\n\nUses IAM credentials.\n\n1. Go to [AWS IAM Console](https://console.aws.amazon.com/iam/)\n2. Create a new IAM user with programmatic access\n3. Attach policies for services you need (S3, EC2, Lambda, etc.)\n\n```env\nAWS_ACCESS_KEY_ID=your-access-key\nAWS_SECRET_ACCESS_KEY=your-secret-key\nAWS_REGION=us-east-1\n```\n\n### Dropbox\n\n1. Go to [Dropbox App Console](https://www.dropbox.com/developers/apps)\n2. Create app with Full Dropbox or App folder access\n3. OAuth2 redirect: `http://localhost:3000/api/auth/dropbox/callback`\n\n```env\nDROPBOX_CLIENT_ID=your-app-key\nDROPBOX_CLIENT_SECRET=your-app-secret\n```\n\n### Box\n\n1. Go to [Box Developer Console](https://app.box.com/developers/console)\n2. Create new app with OAuth 2.0\n3. Redirect URI: `http://localhost:3000/api/auth/box/callback`\n\n```env\nBOX_CLIENT_ID=your-client-id\nBOX_CLIENT_SECRET=your-client-secret\n```\n\n---\n\n## Finance\n\n### Stripe\n\nUses API key (no OAuth for basic usage).\n\n1. Go to [Stripe Dashboard](https://dashboard.stripe.com/apikeys)\n2. Get your secret key (use test key for development)\n\n```env\nSTRIPE_SECRET_KEY=sk_test_your-secret-key\nSTRIPE_PUBLISHABLE_KEY=pk_test_your-publishable-key\n```\n\n### QuickBooks\n\n1. Go to [Intuit Developer](https://developer.intuit.com/)\n2. Create app and get OAuth credentials\n3. Redirect URI: `http://localhost:3000/api/auth/quickbooks/callback`\n\n```env\nQUICKBOOKS_CLIENT_ID=your-client-id\nQUICKBOOKS_CLIENT_SECRET=your-client-secret\n```\n\n### Xero\n\n1. Go to [Xero Developer](https://developer.xero.com/app/manage)\n2. Create app\n3. Redirect URI: `http://localhost:3000/api/auth/xero/callback`\n\n```env\nXERO_CLIENT_ID=your-client-id\nXERO_CLIENT_SECRET=your-client-secret\n```\n\n---\n\n## Marketing\n\n### Mailchimp\n\n1. Go to [Mailchimp Account API Keys](https://us1.admin.mailchimp.com/account/api/)\n2. For OAuth: Register app at [Mailchimp OAuth](https://admin.mailchimp.com/account/oauth2/)\n3. Redirect: `http://localhost:3000/api/auth/mailchimp/callback`\n\n```env\nMAILCHIMP_CLIENT_ID=your-client-id\nMAILCHIMP_CLIENT_SECRET=your-client-secret\n# Or API key:\nMAILCHIMP_API_KEY=your-api-key-us1\n```\n\n### Twitter/X\n\n1. Go to [Twitter Developer Portal](https://developer.twitter.com/en/portal/dashboard)\n2. Create project and app\n3. Enable OAuth 2.0\n4. Callback URL: `http://localhost:3000/api/auth/twitter/callback`\n\n```env\nTWITTER_CLIENT_ID=your-client-id\nTWITTER_CLIENT_SECRET=your-client-secret\n```\n\n---\n\n## E-commerce\n\n### Shopify\n\n1. Go to [Shopify Partners](https://partners.shopify.com/)\n2. Create new app\n3. App URL and redirect: `http://localhost:3000/api/auth/shopify/callback`\n\n```env\nSHOPIFY_CLIENT_ID=your-api-key\nSHOPIFY_CLIENT_SECRET=your-api-secret\nSHOPIFY_SHOP_NAME=your-store.myshopify.com\n```\n\n---\n\n## AI & Analytics\n\n### Anthropic (Admin API)\n\nFor organization management and usage tracking.\n\n1. Go to [Anthropic Console](https://console.anthropic.com/)\n2. Create Admin API key (requires admin access)\n\n```env\nANTHROPIC_ADMIN_API_KEY=your-admin-api-key\n```\n\n### Mixpanel\n\nUses API key/secret for data export.\n\n1. Go to [Mixpanel Project Settings](https://mixpanel.com/settings/project)\n2. Get Project Token for tracking\n3. Get API Secret for data export\n\n```env\nMIXPANEL_PROJECT_TOKEN=your-project-token\nMIXPANEL_API_SECRET=your-api-secret\n```\n\n---\n\n## Testing Your Setup\n\nAfter configuring credentials:\n\n```bash\n# Start the dev server\nveryfront dev\n\n# Test each integration by visiting:\n# http://localhost:3000/api/auth/{service}\n\n# Check connection status\ncurl http://localhost:3000/api/connections\n```\n\n## Troubleshooting\n\n### Common Issues\n\n| Error | Solution |\n| ---------------------- | -------------------------------------------------------------- |\n| \"Invalid redirect URI\" | Ensure callback URL matches exactly (including trailing slash) |\n| \"Invalid client\" | Check CLIENT_ID is correct and app is published |\n| \"Access denied\" | Verify all required scopes are added |\n| \"Token expired\" | Implement refresh token flow or re-authenticate |\n\n### Debug Mode\n\nEnable debug logging:\n\n```bash\nDEBUG=veryfront:oauth veryfront dev\n```\n\n### Token Storage\n\nBy default, tokens are stored in memory. For production:\n\n1. Implement `TokenStore` interface in `lib/token-store.ts`\n2. Use Redis, database, or encrypted file storage\n3. Handle token refresh automatically\n\n## Production Checklist\n\n- [ ] Update all redirect URIs to production domain\n- [ ] Implement persistent token storage\n- [ ] Set up token encryption\n- [ ] Configure rate limiting\n- [ ] Add error monitoring (Sentry)\n- [ ] Test OAuth flows end-to-end\n- [ ] Review and minimize required scopes\n\n## Need Help?\n\n- Run `veryfront doctor` to diagnose issues\n- Check the [Veryfront Documentation](https://veryfront.com/docs)\n- Join our [Discord community](https://discord.gg/veryfront)\n"
109
109
  }
110
110
  },
package/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.579",
3
+ "version": "0.1.581",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "workspace": [
@@ -337,8 +337,8 @@ export default {
337
337
  "verify:quick": "deno task generate:manifests:check && deno fmt --check src/ cli/ react/ && DENO_NO_PACKAGE_JSON=1 deno lint src/ cli/ react/ && deno task lint:style && deno task lint:cli-boundary && deno task lint:wildcard-exports && deno task lint:barrel-jsdoc && deno task lint:ban-zod && deno task lint:core-deps && deno task lint:dependency-boundaries && deno task lint:extension-contracts && deno task lint:extension-capabilities && deno task docs:validate && deno task typecheck",
338
338
  "docs": "deno run --allow-read --allow-write --allow-run --allow-env scripts/docs/generate-api-reference.ts",
339
339
  "docs:coverage": "deno run --allow-read scripts/docs/docs-coverage.ts",
340
- "docs:copy": "rm -rf ../../docs/docs/code/reference && cp -r docs/reference/ ../../docs/docs/code/reference/",
341
- "docs:validate": "deno run --allow-read scripts/docs/validate-api-reference.ts && deno run --allow-read scripts/docs/validate-guides.ts && deno test --config=scripts/test.deno.json --no-check --allow-read scripts/docs/docs-coverage.test.ts && deno test --no-check --allow-read tests/docs/guide-contracts.test.ts tests/docs/guide-content.test.ts && deno test --no-check --allow-all tests/docs/guide-examples.test.ts tests/docs/guide-code-examples.test.ts && deno run -A scripts/lint/check-doc-links.ts",
340
+ "docs:copy": "rm -rf ../../docs/docs/code/api-reference && cp -r docs/api-reference/ ../../docs/docs/code/api-reference/",
341
+ "docs:validate": "deno run --allow-read scripts/docs/validate-api-reference.ts && deno run --allow-read scripts/docs/validate-guides.ts && deno run --allow-read scripts/docs/validate-public-docs.ts && deno test --config=scripts/test.deno.json --no-check --allow-read scripts/docs/docs-coverage.test.ts && deno test --no-check --allow-read tests/docs/guide-contracts.test.ts tests/docs/guide-content.test.ts && deno test --no-check --allow-all tests/docs/guide-examples.test.ts tests/docs/guide-code-examples.test.ts && deno run -A scripts/lint/check-doc-links.ts",
342
342
  "docs:verify-npm": "node scripts/docs/verify-npm-exports.mjs && node scripts/docs/verify-npm-node.mjs",
343
343
  "docs:check-links": "deno run -A scripts/lint/check-doc-links.ts",
344
344
  "lint:ban-zod": "deno run --allow-read scripts/lint/ban-zod-imports.ts",
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/extensions/ext-sandbox-shell-tools/src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EACL,KAAK,4BAA4B,EACjC,KAAK,yBAAyB,EAE/B,MAAM,0CAA0C,CAAC;AAElD,KAAK,eAAe,GAAG,CACrB,KAAK,EAAE,4BAA4B,KAChC,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC,CAAC;AAEjD,wBAAgB,+BAA+B,CAC7C,kBAAkB,EAAE,eAAe,GAClC,yBAAyB,CAE3B;AAED,QAAA,MAAM,QAAQ,2BAGZ,CAAC;AAsBH,QAAA,MAAM,oBAAoB,EAAE,gBAa1B,CAAC;AAEH,eAAe,oBAAoB,CAAC;AACpC,OAAO,EAAE,QAAQ,IAAI,mCAAmC,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/extensions/ext-sandbox-shell-tools/src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EACL,KAAK,4BAA4B,EACjC,KAAK,yBAAyB,EAE/B,MAAM,0CAA0C,CAAC;AAElD,KAAK,eAAe,GAAG,CACrB,KAAK,EAAE,4BAA4B,KAChC,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC,CAAC;AAEjD,wBAAgB,+BAA+B,CAC7C,kBAAkB,EAAE,eAAe,GAClC,yBAAyB,CAE3B;AAED,QAAA,MAAM,QAAQ,2BAEZ,CAAC;AAEH,QAAA,MAAM,oBAAoB,EAAE,gBAa1B,CAAC;AAEH,eAAe,oBAAoB,CAAC;AACpC,OAAO,EAAE,QAAQ,IAAI,mCAAmC,EAAE,CAAC"}
@@ -3,32 +3,14 @@
3
3
  *
4
4
  * @module extensions/ext-sandbox-shell-tools
5
5
  */
6
+ import { createBashTool as createBashToolImpl } from "bash-tool";
6
7
  import { SandboxShellToolsProviderName, } from "../../../src/extensions/sandbox/index.js";
7
8
  export function createSandboxShellToolsProvider(createBashToolImpl) {
8
9
  return async (input) => await createBashToolImpl(input);
9
10
  }
10
11
  const provider = createSandboxShellToolsProvider(async (input) => {
11
- const { createBashTool } = await importBashTool();
12
- return await createBashTool(input);
12
+ return await createBashToolImpl(input);
13
13
  });
14
- async function importBashTool() {
15
- try {
16
- return await import("bash-tool");
17
- }
18
- catch (error) {
19
- if (!isMissingPackageError(error))
20
- throw error;
21
- throw new Error('Sandbox shell tools require the optional package "bash-tool". ' +
22
- "Install bash-tool@1.3.16 or pass createBashTool explicitly.");
23
- }
24
- }
25
- function isMissingPackageError(error) {
26
- const message = error instanceof Error ? error.message : String(error);
27
- return message.includes("Cannot find package") ||
28
- message.includes("Cannot find module") ||
29
- message.includes("ERR_MODULE_NOT_FOUND") ||
30
- message.includes("Module not found");
31
- }
32
14
  const extSandboxShellTools = () => ({
33
15
  name: "ext-sandbox-shell-tools",
34
16
  version: "0.1.0",
@@ -1,6 +1,5 @@
1
1
  import type { ToolDefinition } from "../tool/index.js";
2
2
  type RemoteIntegrationToolExecutionContext = {
3
- endUserId?: string;
4
3
  runId?: string;
5
4
  agentId?: string;
6
5
  };
@@ -22,7 +21,7 @@ export declare function isRemoteIntegrationTool(toolName: string): boolean;
22
21
  * Execute a remote integration tool via the API.
23
22
  * Called by the agent runtime when a tool isn't found in the local registry.
24
23
  */
25
- export declare function executeRemoteIntegrationTool(toolName: string, args: Record<string, unknown>, contextOrEndUserId?: string | RemoteIntegrationToolExecutionContext): Promise<unknown>;
24
+ export declare function executeRemoteIntegrationTool(toolName: string, args: Record<string, unknown>, context?: RemoteIntegrationToolExecutionContext): Promise<unknown>;
26
25
  /**
27
26
  * Sync integration config from veryfront.config.ts to the API.
28
27
  * This is a full-replace operation. Called by the MCP server path
@@ -1 +1 @@
1
- {"version":3,"file":"remote-tools.d.ts","sourceRoot":"","sources":["../../../src/src/integrations/remote-tools.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAgBvD,KAAK,qCAAqC,GAAG;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAiIF;;;;;;;GAOG;AACH,wBAAsB,mCAAmC,IAAI,OAAO,CAClE,cAAc,EAAE,CACjB,CAoBA;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAKjE;AAED;;;GAGG;AACH,wBAAsB,4BAA4B,CAChD,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,kBAAkB,CAAC,EAAE,MAAM,GAAG,qCAAqC,GAClE,OAAO,CAAC,OAAO,CAAC,CAclB;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,GACjE,OAAO,CAAC,IAAI,CAAC,CAwBf"}
1
+ {"version":3,"file":"remote-tools.d.ts","sourceRoot":"","sources":["../../../src/src/integrations/remote-tools.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAgBvD,KAAK,qCAAqC,GAAG;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AA+JF;;;;;;;GAOG;AACH,wBAAsB,mCAAmC,IAAI,OAAO,CAClE,cAAc,EAAE,CACjB,CAoBA;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAKjE;AAED;;;GAGG;AACH,wBAAsB,4BAA4B,CAChD,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE,qCAAqC,GAC9C,OAAO,CAAC,OAAO,CAAC,CAclB;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,GACjE,OAAO,CAAC,IAAI,CAAC,CAwBf"}
@@ -11,12 +11,6 @@
11
11
  import * as dntShim from "../../_dnt.shims.js";
12
12
  import { logger } from "../utils/index.js";
13
13
  import { getApiBaseUrlEnv, getApiTokenEnv } from "../config/env.js";
14
- function normalizeRemoteExecutionContext(contextOrEndUserId) {
15
- if (typeof contextOrEndUserId === "string") {
16
- return { endUserId: contextOrEndUserId };
17
- }
18
- return contextOrEndUserId;
19
- }
20
14
  // ---------------------------------------------------------------------------
21
15
  // Per-request token resolution
22
16
  // ---------------------------------------------------------------------------
@@ -54,6 +48,39 @@ function parseJsonText(text) {
54
48
  return undefined;
55
49
  }
56
50
  }
51
+ function stripLegacyEndUserIdFromConnectUrl(connectUrl) {
52
+ try {
53
+ const isAbsolute = /^[a-zA-Z][a-zA-Z\d+.-]*:/.test(connectUrl);
54
+ const isProtocolRelative = connectUrl.startsWith("//");
55
+ const isRootRelative = connectUrl.startsWith("/") && !isProtocolRelative;
56
+ const url = new URL(connectUrl, "https://veryfront.invalid");
57
+ if (!url.searchParams.has("endUserId"))
58
+ return connectUrl;
59
+ url.searchParams.delete("endUserId");
60
+ if (isAbsolute)
61
+ return url.toString();
62
+ if (isProtocolRelative)
63
+ return `//${url.host}${url.pathname}${url.search}${url.hash}`;
64
+ const relativeUrl = `${url.pathname}${url.search}${url.hash}`;
65
+ return isRootRelative ? relativeUrl : relativeUrl.slice(1);
66
+ }
67
+ catch {
68
+ return connectUrl;
69
+ }
70
+ }
71
+ function stripLegacyEndUserIdFromToolResult(value) {
72
+ if (Array.isArray(value)) {
73
+ return value.map(stripLegacyEndUserIdFromToolResult);
74
+ }
75
+ if (!value || typeof value !== "object")
76
+ return value;
77
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
78
+ key,
79
+ key === "connectUrl" && typeof entry === "string"
80
+ ? stripLegacyEndUserIdFromConnectUrl(entry)
81
+ : stripLegacyEndUserIdFromToolResult(entry),
82
+ ]));
83
+ }
57
84
  async function fetchToolList(baseUrl, token) {
58
85
  const response = await fetch(`${baseUrl}/integrations/tools/list`, {
59
86
  method: "POST",
@@ -93,18 +120,19 @@ async function callRemoteTool(baseUrl, token, toolName, args, context) {
93
120
  // If MCP CallToolResult format, extract content
94
121
  if (result?.content && Array.isArray(result.content)) {
95
122
  const text = joinCallToolText(result.content);
96
- if (result.structuredContent)
97
- return result.structuredContent;
123
+ if (result.structuredContent) {
124
+ return stripLegacyEndUserIdFromToolResult(result.structuredContent);
125
+ }
98
126
  if (result.isError) {
99
127
  // Try to preserve structured error data (e.g., authentication_required with connectUrl)
100
128
  const parsed = parseJsonText(text);
101
129
  if (parsed && typeof parsed === "object")
102
- return parsed;
130
+ return stripLegacyEndUserIdFromToolResult(parsed);
103
131
  return { error: "tool_error", message: text };
104
132
  }
105
133
  return parseJsonText(text) ?? text;
106
134
  }
107
- return result;
135
+ return stripLegacyEndUserIdFromToolResult(result);
108
136
  }
109
137
  // ---------------------------------------------------------------------------
110
138
  // Public API — called by agent runtime per-request
@@ -153,13 +181,13 @@ export function isRemoteIntegrationTool(toolName) {
153
181
  * Execute a remote integration tool via the API.
154
182
  * Called by the agent runtime when a tool isn't found in the local registry.
155
183
  */
156
- export async function executeRemoteIntegrationTool(toolName, args, contextOrEndUserId) {
184
+ export async function executeRemoteIntegrationTool(toolName, args, context) {
157
185
  const baseUrl = getApiBaseUrlEnv();
158
186
  const token = resolveRequestToken();
159
187
  if (!baseUrl || !token) {
160
188
  return { error: "no_api_token", message: "No API token available" };
161
189
  }
162
- return callRemoteTool(baseUrl, token, toolName, args, normalizeRemoteExecutionContext(contextOrEndUserId));
190
+ return callRemoteTool(baseUrl, token, toolName, args, context);
163
191
  }
164
192
  /**
165
193
  * Sync integration config from veryfront.config.ts to the API.
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/src/mcp/server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAI7D,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,YAAY,CAAC;AAIjE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAWzE,KAAK,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,EAAE,CAAC;AA2CzD,UAAU,cAAc;IACtB,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,OAAO,CAAC;KAChB,CAAC;CACH;AAOD,gDAAgD;AAChD,MAAM,WAAW,uBAAuB;IACtC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,GAAG,SAAS,CAAC,CAAC;IACnE,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAID,2BAA2B;AAC3B,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAC,UAAU,CASd;IACX,OAAO,CAAC,QAAQ,CAAkD;IAClE,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,iBAAiB,CAAC,CAA0B;IACpD,OAAO,CAAC,kBAAkB,CAAS;IACnC,OAAO,CAAC,cAAc,CAAwB;IAC9C,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,CAAC,YAAY,CAAqC;IACzD,OAAO,CAAC,kBAAkB,CAA+B;IACzD,OAAO,CAAC,mBAAmB,CAA8C;IAEzE,2EAA2E;IAC3E,cAAc,CAAC,EAAE,CAAC,YAAY,EAAE;QAAE,OAAO,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;gBAElF,MAAM,EAAE,eAAe;IAWnC;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAyCjC,kBAAkB,IAAI,IAAI;IAI1B,sBAAsB,IAAI,IAAI;IAI9B,oBAAoB,IAAI,IAAI;IAI5B;;;;;;OAMG;IACH,oBAAoB,CAAC,MAAM,EAAE,uBAAuB,GAAG,IAAI;IAK3D,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO;IAY5E,aAAa,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,CAAC;IAmBhG,OAAO,CAAC,QAAQ;IAiDhB,OAAO,CAAC,UAAU;YAgCJ,SAAS;IA6BvB,OAAO,CAAC,QAAQ;IAiHhB,OAAO,CAAC,qBAAqB;IAuB7B,OAAO,CAAC,aAAa;IAoBrB,OAAO,CAAC,YAAY;IA6CpB,OAAO,CAAC,WAAW;IAgBnB,OAAO,CAAC,SAAS;IAuCjB,OAAO,CAAC,QAAQ;IAUhB,OAAO,CAAC,WAAW;IAmBnB,OAAO,CAAC,OAAO;IAYf,OAAO,CAAC,aAAa;IAgBrB,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,SAAS;IAIjB,0EAA0E;IAC1E,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIpC,iBAAiB,IAAI,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC;IAiB5D,OAAO,CAAC,qBAAqB;YAgBf,YAAY;IAoB1B,OAAO,CAAC,cAAc;YAsBR,0BAA0B;CA0BzC;AAED,wBAAwB;AACxB,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAElE"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/src/mcp/server.ts"],"names":[],"mappings":"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"}
@@ -12,7 +12,6 @@ import { SessionManager } from "./session.js";
12
12
  import { TaskStore } from "./task-store.js";
13
13
  const logger = baseLogger.component("mcp-server");
14
14
  const MAX_CONTEXT_HEADER_LENGTH = 255;
15
- const END_USER_ID_PATTERN = /^[a-zA-Z0-9._@-]+$/;
16
15
  const PROJECT_ID_PATTERN = /^[a-zA-Z0-9._-]+$/;
17
16
  class JsonRpcError extends Error {
18
17
  code;
@@ -542,10 +541,6 @@ export class MCPServer {
542
541
  }
543
542
  extractRequestContext(request) {
544
543
  const context = {};
545
- const endUserId = readAllowedHeader(request, "x-end-user-id", END_USER_ID_PATTERN);
546
- if (endUserId) {
547
- context.endUserId = endUserId;
548
- }
549
544
  const projectId = readAllowedHeader(request, "x-project-id", PROJECT_ID_PATTERN);
550
545
  if (projectId) {
551
546
  context.projectId = projectId;
@@ -584,7 +579,7 @@ export class MCPServer {
584
579
  return {
585
580
  "Access-Control-Allow-Origin": matchedOrigin,
586
581
  "Access-Control-Allow-Methods": "POST, GET, DELETE, OPTIONS",
587
- "Access-Control-Allow-Headers": "Content-Type, Authorization, MCP-Session-Id, X-End-User-Id, X-Project-Id",
582
+ "Access-Control-Allow-Headers": "Content-Type, Authorization, MCP-Session-Id, X-Project-Id",
588
583
  "Vary": "Origin",
589
584
  };
590
585
  }
@@ -1,13 +1,11 @@
1
1
  /**
2
- * Reusable validation schemas common types (email, slug, URL, UUID,
2
+ * Reusable validation schemas: common types (email, slug, URL, UUID,
3
3
  * pagination) and primitives (file paths, hex colors, semver, timestamps),
4
4
  * plus the `defineSchema` lazy-factory helper.
5
5
  *
6
6
  * `defineSchema` resolves the `SchemaValidator` contract on first use. The
7
7
  * default zod-backed implementation lives in `@veryfront/ext-schema-zod` and is
8
- * registered at app bootstrap by `createBuiltinExtensions()`. Tests that
9
- * exercise schemas without going through full bootstrap import
10
- * `./_test-setup.ts` to register the adapter directly.
8
+ * registered at app bootstrap by `createBuiltinExtensions()`.
11
9
  *
12
10
  * @example
13
11
  * ```ts
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/schemas/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,yBAAyB,CAAC;AAGjC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,OAAO,EACL,gBAAgB,IAAI,gBAAgB,EACpC,KAAK,UAAU,EACf,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,aAAa,EACb,KAAK,SAAS,EACd,KAAK,KAAK,EACV,kBAAkB,EAClB,cAAc,EACd,mBAAmB,EACnB,oBAAoB,EACpB,aAAa,EACb,uBAAuB,EACvB,YAAY,EACZ,aAAa,EACb,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,IAAI,EACT,KAAK,cAAc,EACnB,KAAK,GAAG,EACR,KAAK,IAAI,GACV,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,EACnB,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,MAAM,EACX,KAAK,SAAS,GACf,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/schemas/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,yBAAyB,CAAC;AAGjC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,OAAO,EACL,gBAAgB,IAAI,gBAAgB,EACpC,KAAK,UAAU,EACf,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,aAAa,EACb,KAAK,SAAS,EACd,KAAK,KAAK,EACV,kBAAkB,EAClB,cAAc,EACd,mBAAmB,EACnB,oBAAoB,EACpB,aAAa,EACb,uBAAuB,EACvB,YAAY,EACZ,aAAa,EACb,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,IAAI,EACT,KAAK,cAAc,EACnB,KAAK,GAAG,EACR,KAAK,IAAI,GACV,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,EACnB,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,MAAM,EACX,KAAK,SAAS,GACf,MAAM,iBAAiB,CAAC"}
@@ -1,13 +1,11 @@
1
1
  /**
2
- * Reusable validation schemas common types (email, slug, URL, UUID,
2
+ * Reusable validation schemas: common types (email, slug, URL, UUID,
3
3
  * pagination) and primitives (file paths, hex colors, semver, timestamps),
4
4
  * plus the `defineSchema` lazy-factory helper.
5
5
  *
6
6
  * `defineSchema` resolves the `SchemaValidator` contract on first use. The
7
7
  * default zod-backed implementation lives in `@veryfront/ext-schema-zod` and is
8
- * registered at app bootstrap by `createBuiltinExtensions()`. Tests that
9
- * exercise schemas without going through full bootstrap import
10
- * `./_test-setup.ts` to register the adapter directly.
8
+ * registered at app bootstrap by `createBuiltinExtensions()`.
11
9
  *
12
10
  * @example
13
11
  * ```ts
@@ -1 +1 @@
1
- {"version":3,"file":"agent-stream.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/agent-stream.handler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AACpF,OAAO,EAEL,KAAK,+BAA+B,EACrC,MAAM,wCAAwC,CAAC;AAChD,OAAO,EACL,4BAA4B,EAE7B,MAAM,2CAA2C,CAAC;AAwBnD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AAKnG,MAAM,WAAW,sBACf,SAAQ,yBAAyB,EAAE,+BAA+B;IAClE,4BAA4B,CAAC,EAAE,OAAO,4BAA4B,CAAC;CACpE;AA8FD,qBAAa,kBAAmB,SAAQ,WAAW;IASrC,OAAO,CAAC,QAAQ,CAAC,IAAI;IARjC,QAAQ,EAAE,eAAe,CAMvB;gBAE2B,IAAI,GAAE,sBAAoC;IAIvE,OAAO,CAAC,sBAAsB;IAwBxB,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;CAoHxE"}
1
+ {"version":3,"file":"agent-stream.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/agent-stream.handler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AACpF,OAAO,EAEL,KAAK,+BAA+B,EACrC,MAAM,wCAAwC,CAAC;AAChD,OAAO,EACL,4BAA4B,EAE7B,MAAM,2CAA2C,CAAC;AAwBnD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AAUnG,MAAM,WAAW,sBACf,SAAQ,yBAAyB,EAAE,+BAA+B;IAClE,4BAA4B,CAAC,EAAE,OAAO,4BAA4B,CAAC;CACpE;AAmJD,qBAAa,kBAAmB,SAAQ,WAAW;IASrC,OAAO,CAAC,QAAQ,CAAC,IAAI;IARjC,QAAQ,EAAE,eAAe,CAMvB;gBAE2B,IAAI,GAAE,sBAAoC;IAIvE,OAAO,CAAC,sBAAsB;IAwBxB,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;CAoJxE"}
@@ -10,6 +10,7 @@ import { BaseHandler } from "../response/base.js";
10
10
  import { PRIORITY_MEDIUM_API } from "../../../utils/constants/index.js";
11
11
  import { getHostEnv } from "../../../platform/compat/process.js";
12
12
  import { serverLogger } from "../../../utils/index.js";
13
+ import { EnvironmentVariableCache, fetchProjectEnvVars, runWithProjectEnv, } from "../../project-env/index.js";
13
14
  const defaultDeps = {
14
15
  ...defaultChannelInvokeDeps,
15
16
  sessionManager: agentRunSessionManager,
@@ -17,6 +18,46 @@ const defaultDeps = {
17
18
  };
18
19
  const logger = serverLogger.component("agent-stream-handler");
19
20
  const RUN_STREAM_PATH_REGEX = /^\/api\/control-plane\/runs\/([^/]+)\/stream$/;
21
+ // Per-environment env var cache shared across all agent stream requests (60s TTL)
22
+ const _agentEnvVarCache = new EnvironmentVariableCache((environmentId, token, projectSlug) => {
23
+ const apiBaseUrl = getHostEnv("VERYFRONT_API_URL") ?? "https://api.veryfront.org";
24
+ return fetchProjectEnvVars(apiBaseUrl, projectSlug, environmentId, token);
25
+ });
26
+ // Cache: projectSlug → production environmentId (stable across restarts)
27
+ const _productionEnvIdCache = new Map();
28
+ async function _resolveProductionEnvironmentId(projectSlug, token) {
29
+ const cached = _productionEnvIdCache.get(projectSlug);
30
+ if (cached)
31
+ return cached;
32
+ const apiBaseUrl = getHostEnv("VERYFRONT_API_URL") ?? "https://api.veryfront.org";
33
+ try {
34
+ const res = await fetch(`${apiBaseUrl}/projects/${encodeURIComponent(projectSlug)}/environments`, { headers: { Authorization: `Bearer ${token}`, Accept: "application/json" } });
35
+ if (!res.ok) {
36
+ await res.body?.cancel();
37
+ return null;
38
+ }
39
+ const body = await res.json();
40
+ const env = body.data?.find((e) => e.name === "production") ?? body.data?.[0];
41
+ if (!env?.id)
42
+ return null;
43
+ _productionEnvIdCache.set(projectSlug, env.id);
44
+ return env.id;
45
+ }
46
+ catch {
47
+ return null;
48
+ }
49
+ }
50
+ function buildAgentStreamEnv(input) {
51
+ const apiUrl = getHostEnv("VERYFRONT_API_URL") ?? "https://api.veryfront.org";
52
+ return {
53
+ ...input.envVars,
54
+ // Framework-owned values must override project env to keep request-scoped
55
+ // credentials bound to trusted Veryfront endpoints and the current project.
56
+ ...(input.proxyToken ? { VERYFRONT_API_TOKEN: input.proxyToken } : {}),
57
+ VERYFRONT_API_URL: apiUrl,
58
+ ...(input.projectSlug ? { VERYFRONT_PROJECT_SLUG: input.projectSlug } : {}),
59
+ };
60
+ }
20
61
  function buildAgentSourceRunOptions(sourceContext) {
21
62
  switch (sourceContext.type) {
22
63
  case "branch":
@@ -137,7 +178,33 @@ export class AgentStreamHandler extends BaseHandler {
137
178
  return this.respond(builder.json({ error: "Agent not found" }, 404));
138
179
  }
139
180
  const runtimeInput = toRuntimeRunAgentInput(payload);
140
- const response = await createRuntimeAgentStreamResponse(runtimeInput, agent, this.deps);
181
+ // Load project env vars so source-defined MCP tool headers resolve
182
+ // via _getProjectEnv(). Control-plane requests don't go through the proxy and
183
+ // therefore don't carry x-environment-id, so we discover the production env ID
184
+ // from the API (one fetch per project per server lifetime, then cached).
185
+ let envVarsForAgent = {};
186
+ if (ctx.projectSlug && ctx.proxyToken) {
187
+ const environmentId = ctx.environmentId ??
188
+ await _resolveProductionEnvironmentId(ctx.projectSlug, ctx.proxyToken);
189
+ if (environmentId) {
190
+ envVarsForAgent = await _agentEnvVarCache.get(environmentId, ctx.proxyToken, ctx.projectSlug);
191
+ logger.debug("Agent stream env vars loaded", {
192
+ runId: payload.runId,
193
+ projectSlug: ctx.projectSlug,
194
+ environmentId,
195
+ count: Object.keys(envVarsForAgent).length,
196
+ });
197
+ }
198
+ }
199
+ const runAgentStream = () => createRuntimeAgentStreamResponse(runtimeInput, agent, this.deps);
200
+ const shouldIsolateEnv = !!ctx.proxyToken;
201
+ const response = shouldIsolateEnv
202
+ ? await runWithProjectEnv(buildAgentStreamEnv({
203
+ envVars: envVarsForAgent,
204
+ proxyToken: ctx.proxyToken,
205
+ projectSlug: ctx.projectSlug,
206
+ }), runAgentStream)
207
+ : await runAgentStream();
141
208
  logger.info("Internal agent stream response created", {
142
209
  runId: payload.runId,
143
210
  threadId: payload.threadId,
@@ -1,9 +1,8 @@
1
1
  /**
2
- * Server Module Public API
2
+ * Server runtime APIs.
3
3
  *
4
- * This module exports the public interface for the Veryfront server.
5
- * For routing utilities, import from "#veryfront/routing" directly.
6
- * For observability utilities, import from "#veryfront/observability" directly.
4
+ * Creates and runs a Veryfront server in tests, custom runtimes, and
5
+ * production adapters.
7
6
  *
8
7
  * @module server
9
8
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/server/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,yBAAyB,CAAC;AAKjC,OAAO,EACL,SAAS,EACT,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,cAAc,EACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,qBAAqB,EACrB,KAAK,4BAA4B,EAClC,MAAM,wBAAwB,CAAC;AAahC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,qBAAqB,EAAE,CAAC;AAC5D,OAAO,EACL,qBAAqB,EACrB,KAAK,4BAA4B,EACjC,KAAK,0BAA0B,EAC/B,wBAAwB,EACxB,KAAK,+BAA+B,EACpC,oBAAoB,EACpB,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,EAC3B,KAAK,2BAA2B,EAChC,KAAK,4BAA4B,EACjC,KAAK,4BAA4B,EACjC,KAAK,oCAAoC,EACzC,KAAK,6BAA6B,EAClC,KAAK,iCAAiC,GACvC,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,4BAA4B,GAC7B,CAAC;AACF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,CAAC;AAC1B,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEjE,uEAAuE;AACvE,UAAU,iBAAiB;IACzB,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,sFAAsF;IACtF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACnE;AAED,0CAA0C;AAC1C,MAAM,WAAW,mBAAoB,SAAQ,iBAAiB;IAC5D,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,iDAAiD;AACjD,MAAM,WAAW,0BAA2B,SAAQ,iBAAiB;IACnE,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,kDAAkD;IAClD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,uGAAuG;IACvG,kBAAkB,CAAC,EAAE,SAAS,GAAG,YAAY,CAAC;IAC9C,oFAAoF;IACpF,eAAe,CAAC,EAAE,gBAAgB,CAAC;IACnC,4DAA4D;IAC5D,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAED;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,mBAAmB,GAAG,0BAA0B,CAAC;AAElF,uDAAuD;AACvD,MAAM,WAAW,eAAe;IAC9B,4DAA4D;IAC5D,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACrB,kCAAkC;IAClC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,GAAG,EAAE,MAAM,CAAC;CACb;AAED,sEAAsE;AACtE,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG;IACrE;;;OAGG;IACH,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC;;;;OAIG;IACH,UAAU,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,CAAC;CACrC,CAAC;AAwCF,wEAAwE;AACxE,wBAAsB,aAAa,CACjC,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GACxF,OAAO,CAAC,gBAAgB,CAAC,CA8G3B;AAED;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,eAAe,CAAC,CAkD1B"}
@@ -1,9 +1,8 @@
1
1
  /**
2
- * Server Module Public API
2
+ * Server runtime APIs.
3
3
  *
4
- * This module exports the public interface for the Veryfront server.
5
- * For routing utilities, import from "#veryfront/routing" directly.
6
- * For observability utilities, import from "#veryfront/observability" directly.
4
+ * Creates and runs a Veryfront server in tests, custom runtimes, and
5
+ * production adapters.
7
6
  *
8
7
  * @module server
9
8
  *
@@ -251,5 +250,4 @@ export async function startServer(options = {}) {
251
250
  };
252
251
  }
253
252
  // Note: Wildcard re-exports removed to prevent circular dependency risks.
254
- // Import from "#veryfront/routing" for Route, RouteMatch, PageRouteMatcher, etc.
255
- // Import from "#veryfront/observability" for tracing and metrics utilities.
253
+ // Use public routing, middleware, and observability modules for those surfaces.
@@ -59,7 +59,7 @@ export interface ToolExecutionContext {
59
59
  toolCallId?: string;
60
60
  /** Project identity used by integration token resolution */
61
61
  projectId?: string;
62
- /** End-user identity for per-user token resolution in integration tools */
62
+ /** Trusted runtime user identity supplied by hosted integration tooling */
63
63
  endUserId?: string;
64
64
  /** Abort signal for cooperative cancellation during long-running tool execution */
65
65
  abortSignal?: AbortSignal;
@@ -1 +1 @@
1
- {"version":3,"file":"http-cache-state.d.ts","sourceRoot":"","sources":["../../../../src/src/transforms/esm/http-cache-state.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAkBtE,wBAAgB,cAAc,IAAI,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAE9D;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAGpD;AAED,wBAAgB,yBAAyB,IAAI,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAEzE;AAED,gGAAgG;AAChG,wBAAgB,0BAA0B,IAAI,OAAO,CAEpD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE;IACN,WAAW,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IACnD,eAAe,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IACzC,sBAAsB,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;CAC/D,GAAG,IAAI,GACP,IAAI,CAcN"}
1
+ {"version":3,"file":"http-cache-state.d.ts","sourceRoot":"","sources":["../../../../src/src/transforms/esm/http-cache-state.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAwCtE,wBAAgB,cAAc,IAAI,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAE9D;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAGpD;AAED,wBAAgB,yBAAyB,IAAI,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAEzE;AAED,gGAAgG;AAChG,wBAAgB,0BAA0B,IAAI,OAAO,CAEpD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE;IACN,WAAW,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IACnD,eAAe,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IACzC,sBAAsB,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;CAC/D,GAAG,IAAI,GACP,IAAI,CAcN"}
@@ -8,6 +8,7 @@
8
8
  */
9
9
  import { LRUCache } from "../../utils/lru-wrapper.js";
10
10
  import { HTTP_MODULE_CACHE_MAX_ENTRIES } from "../../utils/constants/cache.js";
11
+ import { registerCache } from "../../utils/memory/index.js";
11
12
  import { inFlightHttpFetches, processingStackStorage } from "./in-flight-manager.js";
12
13
  const defaultCachedPaths = new LRUCache({
13
14
  maxEntries: HTTP_MODULE_CACHE_MAX_ENTRIES,
@@ -21,6 +22,24 @@ const defaultLastDistributedRefresh = new LRUCache({
21
22
  let injectedCachedPaths = null;
22
23
  let injectedProcessingStack = null;
23
24
  let injectedLastDistributedRefresh = null;
25
+ function getCacheEntryCount(cache) {
26
+ const size = cache.size;
27
+ return typeof size === "number" ? size : -1;
28
+ }
29
+ registerCache("http-bundle-paths", () => ({
30
+ name: "http-bundle-paths",
31
+ entries: getCacheEntryCount(getCachedPaths()),
32
+ maxEntries: HTTP_MODULE_CACHE_MAX_ENTRIES,
33
+ }));
34
+ registerCache("http-bundle-ttl-refreshes", () => ({
35
+ name: "http-bundle-ttl-refreshes",
36
+ entries: getCacheEntryCount(getLastDistributedRefresh()),
37
+ maxEntries: HTTP_MODULE_CACHE_MAX_ENTRIES,
38
+ }));
39
+ registerCache("http-bundle-in-flight", () => ({
40
+ name: "http-bundle-in-flight",
41
+ entries: inFlightHttpFetches.size,
42
+ }));
24
43
  export function getCachedPaths() {
25
44
  return injectedCachedPaths ?? defaultCachedPaths;
26
45
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/mdx/esm-module-loader/cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAG5D,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C,MAAM,MAAM,iBAAiB,GACzB;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAClB;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAI9D,eAAO,MAAM,kBAAkB,wBAE7B,CAAC;AAyGH,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAsBvF;AAED,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAezE;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAK3C;AAQD,2DAA2D;AAC3D,wBAAgB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAElD;AAED,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,CA0ElE;AAOD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAevD;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAc1D;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAIzD;AAmBD,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,EACnB,YAAY,CAAC,EAAE,MAAM,EAAE,oDAAoD;AAC3E,eAAe,CAAC,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,EAChE,YAAY,SAAwB,GACnC,OAAO,CAAC,iBAAiB,CAAC,CAwH5B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/mdx/esm-module-loader/cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAI5D,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C,MAAM,MAAM,iBAAiB,GACzB;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAClB;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAI9D,eAAO,MAAM,kBAAkB,wBAE7B,CAAC;AA2HH,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAsBvF;AAED,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAezE;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAK3C;AAQD,2DAA2D;AAC3D,wBAAgB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAElD;AAED,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,CA0ElE;AAOD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAevD;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAc1D;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAIzD;AAmBD,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,EACnB,YAAY,CAAC,EAAE,MAAM,EAAE,oDAAoD;AAC3E,eAAe,CAAC,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,EAChE,YAAY,SAAwB,GACnC,OAAO,CAAC,iBAAiB,CAAC,CAwH5B"}
@@ -12,6 +12,7 @@ import { REACT_DEFAULT_VERSION } from "../../../../utils/constants/cdn.js";
12
12
  import { isNotFoundError } from "../../../../platform/compat/fs.js";
13
13
  import { LOG_PREFIX_MDX_LOADER } from "../constants.js";
14
14
  import { LRUCache } from "../../../../utils/lru-wrapper.js";
15
+ import { registerCache } from "../../../../utils/memory/index.js";
15
16
  import { buildMdxEsmPathCacheKey, MDX_ESM_ALL_FILE_URL_PATTERN_SOURCE } from "../cache-format.js";
16
17
  import { ensureMdxModuleDependencies } from "../module-fetcher/dependency-recovery.js";
17
18
  export { getLocalFs } from "./local-fs.js";
@@ -115,6 +116,22 @@ function hasUnresolvedVfModules(code) {
115
116
  }
116
117
  const modulePathCaches = new Map();
117
118
  const modulePathCacheLoaded = new Set();
119
+ function getModulePathCacheEntryCount() {
120
+ let entries = 0;
121
+ for (const cache of modulePathCaches.values())
122
+ entries += cache.size;
123
+ return entries;
124
+ }
125
+ registerCache("mdx-esm-path-caches", () => ({
126
+ name: "mdx-esm-path-caches",
127
+ entries: getModulePathCacheEntryCount(),
128
+ cacheDirs: modulePathCaches.size,
129
+ }));
130
+ registerCache("mdx-esm-verified-deps", () => ({
131
+ name: "mdx-esm-verified-deps",
132
+ entries: verifiedModuleDeps.size,
133
+ maxEntries: MAX_VERIFIED_MODULE_DEPS,
134
+ }));
118
135
  export async function getModulePathCache(cacheDir) {
119
136
  const existing = modulePathCaches.get(cacheDir);
120
137
  if (existing && modulePathCacheLoaded.has(cacheDir))
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Internal utilities runtime detection, structured logging, constants
2
+ * Runtime utilities: runtime detection, structured logging, constants
3
3
  * (breakpoints, timeouts, HTTP codes), hashing, memoization, and feature flags.
4
4
  *
5
5
  * @module utils
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Internal utilities runtime detection, structured logging, constants
2
+ * Runtime utilities: runtime detection, structured logging, constants
3
3
  * (breakpoints, timeouts, HTTP codes), hashing, memoization, and feature flags.
4
4
  *
5
5
  * @module utils
@@ -3,5 +3,5 @@
3
3
  *
4
4
  * @module utils/memory
5
5
  */
6
- export { type CacheStats, checkMemoryPressure, clearAllCaches, forceGC, type GCStats, getCacheStats, getHeapStats, getMemorySnapshot, type HeapStats, type MemorySnapshot, registerCache, setHeapWarningThreshold, startMemoryMonitoring, stopMemoryMonitoring, unregisterCache, } from "./profiler.js";
6
+ export { type CacheStats, checkMemoryPressure, clearAllCaches, forceGC, type GCStats, getCacheStats, getHeapStats, getMemoryMonitoringLogContext, getMemorySnapshot, getTopCacheStats, type HeapStats, type MemoryMonitoringLogContext, type MemorySnapshot, type MonitoringCacheStats, registerCache, setHeapWarningThreshold, startMemoryMonitoring, stopMemoryMonitoring, unregisterCache, } from "./profiler.js";
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/utils/memory/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,KAAK,UAAU,EACf,mBAAmB,EACnB,cAAc,EACd,OAAO,EACP,KAAK,OAAO,EACZ,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,aAAa,EACb,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,EACpB,eAAe,GAChB,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/utils/memory/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,KAAK,UAAU,EACf,mBAAmB,EACnB,cAAc,EACd,OAAO,EACP,KAAK,OAAO,EACZ,aAAa,EACb,YAAY,EACZ,6BAA6B,EAC7B,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,SAAS,EACd,KAAK,0BAA0B,EAC/B,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,aAAa,EACb,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,EACpB,eAAe,GAChB,MAAM,eAAe,CAAC"}
@@ -3,4 +3,4 @@
3
3
  *
4
4
  * @module utils/memory
5
5
  */
6
- export { checkMemoryPressure, clearAllCaches, forceGC, getCacheStats, getHeapStats, getMemorySnapshot, registerCache, setHeapWarningThreshold, startMemoryMonitoring, stopMemoryMonitoring, unregisterCache, } from "./profiler.js";
6
+ export { checkMemoryPressure, clearAllCaches, forceGC, getCacheStats, getHeapStats, getMemoryMonitoringLogContext, getMemorySnapshot, getTopCacheStats, registerCache, setHeapWarningThreshold, startMemoryMonitoring, stopMemoryMonitoring, unregisterCache, } from "./profiler.js";
@@ -21,6 +21,22 @@ export interface MemorySnapshot {
21
21
  totalCacheEntries: number;
22
22
  gcStats?: GCStats;
23
23
  }
24
+ export interface MonitoringCacheStats {
25
+ name: string;
26
+ entries: number;
27
+ maxEntries?: number;
28
+ estimatedSizeBytes?: number;
29
+ backend?: string;
30
+ }
31
+ export interface MemoryMonitoringLogContext {
32
+ heapUsedMB: number;
33
+ heapTotalMB: number;
34
+ heapLimitMB: number;
35
+ heapUsedPercent: number;
36
+ rssMB?: number;
37
+ totalCacheEntries: number;
38
+ topCaches: MonitoringCacheStats[];
39
+ }
24
40
  export interface GCStats {
25
41
  majorGCs: number;
26
42
  minorGCs: number;
@@ -31,6 +47,8 @@ export declare function unregisterCache(name: string): void;
31
47
  export declare function getHeapStats(): HeapStats;
32
48
  export declare function getCacheStats(): CacheStats[];
33
49
  export declare function getMemorySnapshot(): MemorySnapshot;
50
+ export declare function getTopCacheStats(caches: CacheStats[], limit?: number): MonitoringCacheStats[];
51
+ export declare function getMemoryMonitoringLogContext(snapshot: MemorySnapshot, topCacheLimit?: number): MemoryMonitoringLogContext;
34
52
  export declare function forceGC(): Promise<boolean>;
35
53
  export declare function startMemoryMonitoring(intervalMs?: number): void;
36
54
  export declare function stopMemoryMonitoring(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"profiler.d.ts","sourceRoot":"","sources":["../../../../src/src/utils/memory/profiler.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAMD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,UAAU,GAAG,IAAI,CAG5E;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAElD;AAED,wBAAgB,YAAY,IAAI,SAAS,CAiBxC;AAkBD,wBAAgB,aAAa,IAAI,UAAU,EAAE,CAa5C;AAED,wBAAgB,iBAAiB,IAAI,cAAc,CAWlD;AAED,wBAAsB,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAUhD;AAED,wBAAgB,qBAAqB,CAAC,UAAU,SAAwC,GAAG,IAAI,CAqC9F;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAM3C;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAE/D;AAED,wBAAgB,cAAc,IAAI,IAAI,CAMrC;AAwBD,wBAAgB,mBAAmB,IAAI;IACrC,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB,CAiBA;AAED,YAAY,EAAE,cAAc,IAAI,kBAAkB,EAAE,CAAC"}
1
+ {"version":3,"file":"profiler.d.ts","sourceRoot":"","sources":["../../../../src/src/utils/memory/profiler.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,0BAA0B;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,oBAAoB,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAMD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,UAAU,GAAG,IAAI,CAG5E;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAElD;AAED,wBAAgB,YAAY,IAAI,SAAS,CAiBxC;AAkBD,wBAAgB,aAAa,IAAI,UAAU,EAAE,CAa5C;AAED,wBAAgB,iBAAiB,IAAI,cAAc,CAWlD;AAcD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,KAAK,SAAI,GAAG,oBAAoB,EAAE,CAMxF;AAED,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,cAAc,EACxB,aAAa,SAAI,GAChB,0BAA0B,CAY5B;AAED,wBAAsB,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAUhD;AAED,wBAAgB,qBAAqB,CAAC,UAAU,SAAwC,GAAG,IAAI,CAiC9F;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAM3C;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAE/D;AAED,wBAAgB,cAAc,IAAI,IAAI,CAMrC;AAwBD,wBAAgB,mBAAmB,IAAI;IACrC,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB,CAiBA;AAED,YAAY,EAAE,cAAc,IAAI,kBAAkB,EAAE,CAAC"}
@@ -79,6 +79,36 @@ export function getMemorySnapshot() {
79
79
  totalCacheEntries,
80
80
  };
81
81
  }
82
+ function toMonitoringCacheStats(cache) {
83
+ return {
84
+ name: cache.name,
85
+ entries: cache.entries,
86
+ ...(cache.maxEntries !== undefined ? { maxEntries: cache.maxEntries } : {}),
87
+ ...(cache.estimatedSizeBytes !== undefined
88
+ ? { estimatedSizeBytes: cache.estimatedSizeBytes }
89
+ : {}),
90
+ ...(cache.backend !== undefined ? { backend: cache.backend } : {}),
91
+ };
92
+ }
93
+ export function getTopCacheStats(caches, limit = 8) {
94
+ return [...caches]
95
+ .filter((cache) => cache.entries > 0)
96
+ .sort((a, b) => b.entries - a.entries || a.name.localeCompare(b.name))
97
+ .slice(0, limit)
98
+ .map(toMonitoringCacheStats);
99
+ }
100
+ export function getMemoryMonitoringLogContext(snapshot, topCacheLimit = 8) {
101
+ const { heap } = snapshot;
102
+ return {
103
+ heapUsedMB: heap.usedHeapSizeMB,
104
+ heapTotalMB: heap.totalHeapSizeMB,
105
+ heapLimitMB: heap.heapSizeLimitMB,
106
+ heapUsedPercent: heap.heapUsedPercent,
107
+ rssMB: heap.rss,
108
+ totalCacheEntries: snapshot.totalCacheEntries,
109
+ topCaches: getTopCacheStats(snapshot.caches, topCacheLimit),
110
+ };
111
+ }
82
112
  export async function forceGC() {
83
113
  try {
84
114
  const buffer = new Uint8Array(100 * 1024 * 1024);
@@ -98,19 +128,14 @@ export function startMemoryMonitoring(intervalMs = DEFAULT_MEMORY_MONITORING_INT
98
128
  memoryCheckInterval = dntShim.setInterval(() => {
99
129
  const snapshot = getMemorySnapshot();
100
130
  const { heap } = snapshot;
101
- logger.info("Memory status", {
102
- heapUsedMB: heap.usedHeapSizeMB,
103
- heapTotalMB: heap.totalHeapSizeMB,
104
- heapLimitMB: heap.heapSizeLimitMB,
105
- heapUsedPercent: heap.heapUsedPercent,
106
- rssMB: heap.rss,
107
- totalCacheEntries: snapshot.totalCacheEntries,
108
- });
131
+ const monitoringContext = getMemoryMonitoringLogContext(snapshot);
132
+ logger.info("Memory status", monitoringContext);
109
133
  const thresholdPercent = heapGrowthWarningThreshold * 100;
110
134
  if (heap.heapUsedPercent > thresholdPercent) {
111
135
  logger.warn("HIGH MEMORY USAGE", {
112
136
  heapUsedPercent: heap.heapUsedPercent,
113
137
  threshold: thresholdPercent,
138
+ topCaches: monitoringContext.topCaches,
114
139
  caches: snapshot.caches.map((c) => `${c.name}: ${c.entries}`).join(", "),
115
140
  });
116
141
  }
@@ -119,6 +144,7 @@ export function startMemoryMonitoring(intervalMs = DEFAULT_MEMORY_MONITORING_INT
119
144
  logger.warn("Rapid heap growth detected", {
120
145
  growthMB: heapGrowthMB,
121
146
  intervalMs,
147
+ topCaches: monitoringContext.topCaches,
122
148
  });
123
149
  }
124
150
  lastHeapUsed = heap.usedHeapSizeMB;
@@ -1,3 +1,3 @@
1
1
  /** Shared version value. */
2
- export declare const VERSION = "0.1.579";
2
+ export declare const VERSION = "0.1.581";
3
3
  //# sourceMappingURL=version-constant.d.ts.map
@@ -1,4 +1,4 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
3
  /** Shared version value. */
4
- export const VERSION = "0.1.579";
4
+ export const VERSION = "0.1.581";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.579",
3
+ "version": "0.1.581",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",