veryfront 0.1.757 → 0.1.759
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/cli/templates/manifest.js +2 -2
- package/esm/deno.js +1 -1
- package/esm/src/agent/memory/index.d.ts +1 -1
- package/esm/src/agent/memory/index.d.ts.map +1 -1
- package/esm/src/agent/memory/index.js +1 -1
- package/esm/src/agent/memory/memory-interface.d.ts +7 -0
- package/esm/src/agent/memory/memory-interface.d.ts.map +1 -1
- package/esm/src/agent/memory/memory.d.ts +25 -0
- package/esm/src/agent/memory/memory.d.ts.map +1 -1
- package/esm/src/agent/memory/memory.js +38 -0
- package/esm/src/agent/runtime/defaults.d.ts +0 -2
- package/esm/src/agent/runtime/defaults.d.ts.map +1 -1
- package/esm/src/agent/runtime/defaults.js +0 -2
- package/esm/src/agent/runtime/index.d.ts +9 -0
- package/esm/src/agent/runtime/index.d.ts.map +1 -1
- package/esm/src/agent/runtime/index.js +58 -21
- package/esm/src/agent/schemas/agent.schema.d.ts +1 -0
- package/esm/src/agent/schemas/agent.schema.d.ts.map +1 -1
- package/esm/src/agent/schemas/agent.schema.js +3 -0
- package/esm/src/agent/streaming/tool-execution-data-event-bridge.d.ts.map +1 -1
- package/esm/src/agent/streaming/tool-execution-data-event-bridge.js +11 -1
- package/esm/src/agent/types.d.ts +8 -0
- package/esm/src/agent/types.d.ts.map +1 -1
- package/esm/src/integrations/_data.d.ts.map +1 -1
- package/esm/src/integrations/_data.js +2 -4
- package/esm/src/platform/compat/process/env.d.ts.map +1 -1
- package/esm/src/platform/compat/process/env.js +13 -2
- package/esm/src/security/sandbox/worker-egress-guard.d.ts +20 -0
- package/esm/src/security/sandbox/worker-egress-guard.d.ts.map +1 -1
- package/esm/src/security/sandbox/worker-egress-guard.js +115 -2
- package/esm/src/transforms/mdx/esm-module-loader/cache/index.d.ts.map +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/cache/index.js +19 -1
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +1 -1
|
@@ -216,7 +216,7 @@ export default {
|
|
|
216
216
|
".env.example": "# Google Docs Integration\n# Create OAuth credentials at https://console.cloud.google.com/apis/credentials\n# Make sure to enable:\n# - Google Docs API: https://console.cloud.google.com/apis/library/docs.googleapis.com\n# - Google Drive API: https://console.cloud.google.com/apis/library/drive.googleapis.com\n\nGOOGLE_CLIENT_ID=your_client_id_here\nGOOGLE_CLIENT_SECRET=your_client_secret_here\n",
|
|
217
217
|
"app/api/auth/docs-google/callback/route.ts": "import { createOAuthCallbackHandler, docsGoogleConfig } from \"veryfront/oauth\";\nimport { tokenStore } from \"../../../../../lib/token-store.ts\";\nimport { oauthMemoryTokenStore } from \"../../../../../lib/oauth-memory-store.ts\";\n\nconst hybridTokenStore = {\n getTokens(serviceId: string, userId: string) {\n return tokenStore.getToken(userId, serviceId);\n },\n async setTokens(\n serviceId: string,\n userId: string,\n tokens: { accessToken: string; refreshToken?: string; expiresAt?: number },\n ) {\n await tokenStore.setToken(userId, serviceId, tokens);\n },\n async clearTokens(serviceId: string, userId: string) {\n await tokenStore.revokeToken(userId, serviceId);\n },\n setState(\n state: string,\n meta: {\n userId: string;\n serviceId: string;\n codeVerifier?: string;\n redirectUri?: string;\n scopes?: string[];\n createdAt: number;\n },\n ) {\n return oauthMemoryTokenStore.setState(state, meta);\n },\n consumeState(state: string) {\n return oauthMemoryTokenStore.consumeState(state);\n },\n};\n\nexport const GET = createOAuthCallbackHandler(docsGoogleConfig, { tokenStore: hybridTokenStore });\n",
|
|
218
218
|
"app/api/auth/docs-google/route.ts": "import { createOAuthInitHandler, docsGoogleConfig } from \"veryfront/oauth\";\nimport { oauthMemoryTokenStore } from \"../../../../../lib/oauth-memory-store.ts\";\nimport { requireUserIdFromRequest } from \"../../../../../lib/user-id.ts\";\n\nfunction getUserId(request: Request): string {\n return requireUserIdFromRequest(request);\n}\n\nexport const GET = createOAuthInitHandler(docsGoogleConfig, {\n tokenStore: oauthMemoryTokenStore,\n getUserId,\n});",
|
|
219
|
-
"lib/docs-client.ts": "/**\n * Google Docs API Client\n *\n * Provides a type-safe interface to Google Docs API operations.\n */\n\nimport { getValidToken } from \"./oauth.ts\";\n\nfunction getEnv(key: string): string | undefined {\n // @ts-ignore - Deno global\n if (typeof Deno !== \"undefined\") return Deno.env.get(key);\n // @ts-ignore - process global\n if (typeof process !== \"undefined\" && process.env) return process.env[key];\n return undefined;\n}\n\nconst DOCS_API_BASE = \"https://docs.googleapis.com/v1\";\nconst DRIVE_API_BASE = \"https://www.googleapis.com/drive/v3\";\n\nexport interface Document {\n documentId: string;\n title: string;\n body: {\n content: StructuralElement[];\n };\n revisionId: string;\n suggestionsViewMode: string;\n documentStyle: DocumentStyle;\n}\n\nexport interface StructuralElement {\n startIndex: number;\n endIndex: number;\n paragraph?: Paragraph;\n table?: Table;\n sectionBreak?: SectionBreak;\n}\n\nexport interface Paragraph {\n elements: ParagraphElement[];\n paragraphStyle?: ParagraphStyle;\n bullet?: Bullet;\n}\n\nexport interface ParagraphElement {\n startIndex: number;\n endIndex: number;\n textRun?: TextRun;\n inlineObjectElement?: InlineObjectElement;\n}\n\nexport interface TextRun {\n content: string;\n textStyle?: TextStyle;\n}\n\nexport interface TextStyle {\n bold?: boolean;\n italic?: boolean;\n underline?: boolean;\n strikethrough?: boolean;\n fontSize?: Dimension;\n foregroundColor?: Color;\n backgroundColor?: Color;\n fontFamily?: string;\n link?: Link;\n}\n\nexport interface Link {\n url?: string;\n bookmarkId?: string;\n headingId?: string;\n}\n\nexport interface Dimension {\n magnitude: number;\n unit: string;\n}\n\nexport interface Color {\n rgbColor?: RgbColor;\n}\n\nexport interface RgbColor {\n red: number;\n green: number;\n blue: number;\n}\n\nexport interface ParagraphStyle {\n headingId?: string;\n namedStyleType?: string;\n alignment?: string;\n lineSpacing?: number;\n direction?: string;\n spacingMode?: string;\n spaceAbove?: Dimension;\n spaceBelow?: Dimension;\n indentFirstLine?: Dimension;\n indentStart?: Dimension;\n indentEnd?: Dimension;\n}\n\nexport interface Bullet {\n listId: string;\n nestingLevel?: number;\n textStyle?: TextStyle;\n}\n\nexport interface Table {\n rows: number;\n columns: number;\n tableRows: TableRow[];\n tableStyle?: TableStyle;\n}\n\nexport interface TableRow {\n startIndex: number;\n endIndex: number;\n tableCells: TableCell[];\n}\n\nexport interface TableCell {\n startIndex: number;\n endIndex: number;\n content: StructuralElement[];\n tableCellStyle?: TableCellStyle;\n}\n\nexport interface TableCellStyle {\n rowSpan?: number;\n columnSpan?: number;\n backgroundColor?: Color;\n borderLeft?: TableCellBorder;\n borderRight?: TableCellBorder;\n borderTop?: TableCellBorder;\n borderBottom?: TableCellBorder;\n paddingLeft?: Dimension;\n paddingRight?: Dimension;\n paddingTop?: Dimension;\n paddingBottom?: Dimension;\n}\n\nexport interface TableCellBorder {\n color?: Color;\n width?: Dimension;\n dashStyle?: string;\n}\n\nexport interface TableStyle {\n tableColumnProperties?: TableColumnProperties[];\n}\n\nexport interface TableColumnProperties {\n width?: Dimension;\n widthType?: string;\n}\n\nexport interface SectionBreak {\n sectionStyle?: SectionStyle;\n}\n\nexport interface SectionStyle {\n columnSeparatorStyle?: string;\n contentDirection?: string;\n marginTop?: Dimension;\n marginBottom?: Dimension;\n marginRight?: Dimension;\n marginLeft?: Dimension;\n pageNumberStart?: number;\n}\n\nexport interface DocumentStyle {\n background?: Background;\n pageNumberStart?: number;\n marginTop?: Dimension;\n marginBottom?: Dimension;\n marginRight?: Dimension;\n marginLeft?: Dimension;\n pageSize?: Size;\n marginHeader?: Dimension;\n marginFooter?: Dimension;\n useFirstPageHeaderFooter?: boolean;\n}\n\nexport interface Background {\n color?: Color;\n}\n\nexport interface Size {\n height?: Dimension;\n width?: Dimension;\n}\n\nexport interface InlineObjectElement {\n inlineObjectId: string;\n textStyle?: TextStyle;\n}\n\nexport interface DocumentFile {\n id: string;\n name: string;\n mimeType: string;\n createdTime: string;\n modifiedTime: string;\n webViewLink: string;\n iconLink?: string;\n thumbnailLink?: string;\n}\n\nexport interface CreateDocumentOptions {\n title: string;\n}\n\nexport interface BatchUpdateRequest {\n requests: Request[];\n}\n\nexport interface Request {\n insertText?: InsertTextRequest;\n deleteContentRange?: DeleteContentRangeRequest;\n replaceAllText?: ReplaceAllTextRequest;\n updateTextStyle?: UpdateTextStyleRequest;\n updateParagraphStyle?: UpdateParagraphStyleRequest;\n insertPageBreak?: InsertPageBreakRequest;\n insertTable?: InsertTableRequest;\n deleteTableRow?: DeleteTableRowRequest;\n deleteTableColumn?: DeleteTableColumnRequest;\n createParagraphBullets?: CreateParagraphBulletsRequest;\n deleteParagraphBullets?: DeleteParagraphBulletsRequest;\n}\n\nexport interface InsertTextRequest {\n text: string;\n location: Location;\n}\n\nexport interface DeleteContentRangeRequest {\n range: Range;\n}\n\nexport interface ReplaceAllTextRequest {\n containsText: ContainsText;\n replaceText: string;\n}\n\nexport interface UpdateTextStyleRequest {\n range: Range;\n textStyle: TextStyle;\n fields: string;\n}\n\nexport interface UpdateParagraphStyleRequest {\n range: Range;\n paragraphStyle: ParagraphStyle;\n fields: string;\n}\n\nexport interface InsertPageBreakRequest {\n location: Location;\n}\n\nexport interface InsertTableRequest {\n rows: number;\n columns: number;\n location: Location;\n}\n\nexport interface DeleteTableRowRequest {\n tableCellLocation: TableCellLocation;\n}\n\nexport interface DeleteTableColumnRequest {\n tableCellLocation: TableCellLocation;\n}\n\nexport interface CreateParagraphBulletsRequest {\n range: Range;\n bulletPreset: string;\n}\n\nexport interface DeleteParagraphBulletsRequest {\n range: Range;\n}\n\nexport interface Location {\n index: number;\n segmentId?: string;\n}\n\nexport interface Range {\n startIndex: number;\n endIndex: number;\n segmentId?: string;\n}\n\nexport interface ContainsText {\n text: string;\n matchCase: boolean;\n}\n\nexport interface TableCellLocation {\n tableStartLocation: Location;\n rowIndex: number;\n columnIndex: number;\n}\n\nexport interface BatchUpdateResponse {\n documentId: string;\n replies: Reply[];\n writeControl?: WriteControl;\n}\n\nexport interface Reply {\n [key: string]: unknown;\n}\n\nexport interface WriteControl {\n requiredRevisionId: string;\n targetRevisionId: string;\n}\n\n/**\n * Google Docs OAuth provider configuration\n */\nexport const docsOAuthProvider = {\n name: \"docs-google\",\n authorizationUrl: \"https://accounts.google.com/o/oauth2/v2/auth\",\n tokenUrl: \"https://oauth2.googleapis.com/token\",\n clientId: getEnv(\"GOOGLE_CLIENT_ID\") ?? \"\",\n clientSecret: getEnv(\"GOOGLE_CLIENT_SECRET\") ?? \"\",\n scopes: [\n \"https://www.googleapis.com/auth/documents.readonly\",\n \"https://www.googleapis.com/auth/documents\",\n \"https://www.googleapis.com/auth/drive.readonly\",\n ],\n callbackPath: \"/api/auth/docs-google/callback\",\n};\n\nexport function createDocsClient(userId: string): {\n listDocuments(options?: {\n maxResults?: number;\n orderBy?: \"createdTime\" | \"modifiedTime\" | \"name\";\n }): Promise<DocumentFile[]>;\n getDocument(documentId: string): Promise<Document>;\n createDocument(options: CreateDocumentOptions): Promise<Document>;\n updateDocument(documentId: string, requests: Request[]): Promise<BatchUpdateResponse>;\n insertText(documentId: string, text: string, index: number): Promise<BatchUpdateResponse>;\n deleteContent(documentId: string, startIndex: number, endIndex: number): Promise<BatchUpdateResponse>;\n replaceAllText(\n documentId: string,\n searchText: string,\n replaceText: string,\n matchCase?: boolean,\n ): Promise<BatchUpdateResponse>;\n searchDocuments(query: string, maxResults?: number): Promise<DocumentFile[]>;\n extractText(document: Document): string;\n createDocumentWithContent(title: string, content: string): Promise<Document>;\n} {\n async function getAccessToken(): Promise<string> {\n const token = await getValidToken(docsOAuthProvider, userId, \"docs-google\");\n if (!token) throw new Error(\"Google Docs not connected. Please connect your Google account first.\");\n return token;\n }\n\n async function apiRequest<T>(\n baseUrl: string,\n label: string,\n endpoint: string,\n options: RequestInit = {},\n ): Promise<T> {\n const accessToken = await getAccessToken();\n\n const response = await fetch(`${baseUrl}${endpoint}`, {\n ...options,\n headers: {\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n ...options.headers,\n },\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`${label} API error: ${response.status} - ${error}`);\n }\n\n return response.json();\n }\n\n function docsApiRequest<T>(endpoint: string, options: RequestInit = {}): Promise<T> {\n return apiRequest<T>(DOCS_API_BASE, \"Docs\", endpoint, options);\n }\n\n function driveApiRequest<T>(endpoint: string, options: RequestInit = {}): Promise<T> {\n return apiRequest<T>(DRIVE_API_BASE, \"Drive\", endpoint, options);\n }\n\n function extractText(document: Document): string {\n const textParts: string[] = [];\n\n function processElement(element: StructuralElement): void {\n if (element.paragraph) {\n for (const el of element.paragraph.elements) {\n if (el.textRun) textParts.push(el.textRun.content);\n }\n return;\n }\n\n if (!element.table) return;\n\n for (const row of element.table.tableRows) {\n for (const cell of row.tableCells) {\n for (const child of cell.content) processElement(child);\n }\n }\n }\n\n for (const element of document.body.content) processElement(element);\n return textParts.join(\"\");\n }\n\n async function listDocuments(options: {\n maxResults?: number;\n orderBy?: \"createdTime\" | \"modifiedTime\" | \"name\";\n } = {}): Promise<DocumentFile[]> {\n const params = new URLSearchParams({\n q: \"mimeType='application/vnd.google-apps.document' and trashed=false\",\n fields: \"files(id,name,mimeType,createdTime,modifiedTime,webViewLink,iconLink,thumbnailLink)\",\n pageSize: String(options.maxResults ?? 20),\n orderBy: `${options.orderBy ?? \"modifiedTime\"} desc`,\n });\n\n const result = await driveApiRequest<{ files: DocumentFile[] }>(`/files?${params.toString()}`);\n return result.files ?? [];\n }\n\n async function searchDocuments(query: string, maxResults = 20): Promise<DocumentFile[]> {\n const params = new URLSearchParams({\n q: `mimeType='application/vnd.google-apps.document' and trashed=false and fullText contains '${query}'`,\n fields: \"files(id,name,mimeType,createdTime,modifiedTime,webViewLink,iconLink,thumbnailLink)\",\n pageSize: String(maxResults),\n orderBy: \"modifiedTime desc\",\n });\n\n const result = await driveApiRequest<{ files: DocumentFile[] }>(`/files?${params.toString()}`);\n return result.files ?? [];\n }\n\n function getDocument(documentId: string): Promise<Document> {\n return docsApiRequest<Document>(`/documents/${documentId}`);\n }\n\n function createDocument(options: CreateDocumentOptions): Promise<Document> {\n return docsApiRequest<Document>(\"/documents\", {\n method: \"POST\",\n body: JSON.stringify({ title: options.title }),\n });\n }\n\n function updateDocument(documentId: string, requests: Request[]): Promise<BatchUpdateResponse> {\n return docsApiRequest<BatchUpdateResponse>(`/documents/${documentId}:batchUpdate`, {\n method: \"POST\",\n body: JSON.stringify({ requests }),\n });\n }\n\n function insertText(documentId: string, text: string, index: number): Promise<BatchUpdateResponse> {\n return updateDocument(documentId, [\n {\n insertText: {\n text,\n location: { index },\n },\n },\n ]);\n }\n\n function deleteContent(documentId: string, startIndex: number, endIndex: number): Promise<BatchUpdateResponse> {\n return updateDocument(documentId, [\n {\n deleteContentRange: {\n range: { startIndex, endIndex },\n },\n },\n ]);\n }\n\n function replaceAllText(\n documentId: string,\n searchText: string,\n replaceText: string,\n matchCase = false,\n ): Promise<BatchUpdateResponse> {\n return updateDocument(documentId, [\n {\n replaceAllText: {\n containsText: {\n text: searchText,\n matchCase,\n },\n replaceText,\n },\n },\n ]);\n }\n\n async function createDocumentWithContent(title: string, content: string): Promise<Document> {\n const doc = await createDocument({ title });\n await insertText(doc.documentId, content, 1);\n return getDocument(doc.documentId);\n }\n\n return {\n listDocuments,\n getDocument,\n createDocument,\n updateDocument,\n insertText,\n deleteContent,\n replaceAllText,\n searchDocuments,\n extractText,\n createDocumentWithContent,\n };\n}\n\nexport type DocsClient = ReturnType<typeof createDocsClient>;\n",
|
|
219
|
+
"lib/docs-client.ts": "/**\n * Google Docs API Client\n *\n * Provides a type-safe interface to Google Docs API operations.\n */\n\nimport { getValidToken } from \"./oauth.ts\";\n\nfunction getEnv(key: string): string | undefined {\n // @ts-ignore - Deno global\n if (typeof Deno !== \"undefined\") return Deno.env.get(key);\n // @ts-ignore - process global\n if (typeof process !== \"undefined\" && process.env) return process.env[key];\n return undefined;\n}\n\nconst DOCS_API_BASE = \"https://docs.googleapis.com/v1\";\nconst DRIVE_API_BASE = \"https://www.googleapis.com/drive/v3\";\n\nexport interface Document {\n documentId: string;\n title: string;\n body: {\n content: StructuralElement[];\n };\n revisionId: string;\n suggestionsViewMode: string;\n documentStyle: DocumentStyle;\n}\n\nexport interface StructuralElement {\n startIndex: number;\n endIndex: number;\n paragraph?: Paragraph;\n table?: Table;\n sectionBreak?: SectionBreak;\n}\n\nexport interface Paragraph {\n elements: ParagraphElement[];\n paragraphStyle?: ParagraphStyle;\n bullet?: Bullet;\n}\n\nexport interface ParagraphElement {\n startIndex: number;\n endIndex: number;\n textRun?: TextRun;\n inlineObjectElement?: InlineObjectElement;\n}\n\nexport interface TextRun {\n content: string;\n textStyle?: TextStyle;\n}\n\nexport interface TextStyle {\n bold?: boolean;\n italic?: boolean;\n underline?: boolean;\n strikethrough?: boolean;\n fontSize?: Dimension;\n foregroundColor?: Color;\n backgroundColor?: Color;\n fontFamily?: string;\n link?: Link;\n}\n\nexport interface Link {\n url?: string;\n bookmarkId?: string;\n headingId?: string;\n}\n\nexport interface Dimension {\n magnitude: number;\n unit: string;\n}\n\nexport interface Color {\n rgbColor?: RgbColor;\n}\n\nexport interface RgbColor {\n red: number;\n green: number;\n blue: number;\n}\n\nexport interface ParagraphStyle {\n headingId?: string;\n namedStyleType?: string;\n alignment?: string;\n lineSpacing?: number;\n direction?: string;\n spacingMode?: string;\n spaceAbove?: Dimension;\n spaceBelow?: Dimension;\n indentFirstLine?: Dimension;\n indentStart?: Dimension;\n indentEnd?: Dimension;\n}\n\nexport interface Bullet {\n listId: string;\n nestingLevel?: number;\n textStyle?: TextStyle;\n}\n\nexport interface Table {\n rows: number;\n columns: number;\n tableRows: TableRow[];\n tableStyle?: TableStyle;\n}\n\nexport interface TableRow {\n startIndex: number;\n endIndex: number;\n tableCells: TableCell[];\n}\n\nexport interface TableCell {\n startIndex: number;\n endIndex: number;\n content: StructuralElement[];\n tableCellStyle?: TableCellStyle;\n}\n\nexport interface TableCellStyle {\n rowSpan?: number;\n columnSpan?: number;\n backgroundColor?: Color;\n borderLeft?: TableCellBorder;\n borderRight?: TableCellBorder;\n borderTop?: TableCellBorder;\n borderBottom?: TableCellBorder;\n paddingLeft?: Dimension;\n paddingRight?: Dimension;\n paddingTop?: Dimension;\n paddingBottom?: Dimension;\n}\n\nexport interface TableCellBorder {\n color?: Color;\n width?: Dimension;\n dashStyle?: string;\n}\n\nexport interface TableStyle {\n tableColumnProperties?: TableColumnProperties[];\n}\n\nexport interface TableColumnProperties {\n width?: Dimension;\n widthType?: string;\n}\n\nexport interface SectionBreak {\n sectionStyle?: SectionStyle;\n}\n\nexport interface SectionStyle {\n columnSeparatorStyle?: string;\n contentDirection?: string;\n marginTop?: Dimension;\n marginBottom?: Dimension;\n marginRight?: Dimension;\n marginLeft?: Dimension;\n pageNumberStart?: number;\n}\n\nexport interface DocumentStyle {\n background?: Background;\n pageNumberStart?: number;\n marginTop?: Dimension;\n marginBottom?: Dimension;\n marginRight?: Dimension;\n marginLeft?: Dimension;\n pageSize?: Size;\n marginHeader?: Dimension;\n marginFooter?: Dimension;\n useFirstPageHeaderFooter?: boolean;\n}\n\nexport interface Background {\n color?: Color;\n}\n\nexport interface Size {\n height?: Dimension;\n width?: Dimension;\n}\n\nexport interface InlineObjectElement {\n inlineObjectId: string;\n textStyle?: TextStyle;\n}\n\nexport interface DocumentFile {\n id: string;\n name: string;\n mimeType: string;\n createdTime: string;\n modifiedTime: string;\n webViewLink: string;\n iconLink?: string;\n thumbnailLink?: string;\n}\n\nexport interface CreateDocumentOptions {\n title: string;\n}\n\nexport interface BatchUpdateRequest {\n requests: Request[];\n}\n\nexport interface Request {\n insertText?: InsertTextRequest;\n deleteContentRange?: DeleteContentRangeRequest;\n replaceAllText?: ReplaceAllTextRequest;\n updateTextStyle?: UpdateTextStyleRequest;\n updateParagraphStyle?: UpdateParagraphStyleRequest;\n insertPageBreak?: InsertPageBreakRequest;\n insertTable?: InsertTableRequest;\n deleteTableRow?: DeleteTableRowRequest;\n deleteTableColumn?: DeleteTableColumnRequest;\n createParagraphBullets?: CreateParagraphBulletsRequest;\n deleteParagraphBullets?: DeleteParagraphBulletsRequest;\n}\n\nexport interface InsertTextRequest {\n text: string;\n location: Location;\n}\n\nexport interface DeleteContentRangeRequest {\n range: Range;\n}\n\nexport interface ReplaceAllTextRequest {\n containsText: ContainsText;\n replaceText: string;\n}\n\nexport interface UpdateTextStyleRequest {\n range: Range;\n textStyle: TextStyle;\n fields: string;\n}\n\nexport interface UpdateParagraphStyleRequest {\n range: Range;\n paragraphStyle: ParagraphStyle;\n fields: string;\n}\n\nexport interface InsertPageBreakRequest {\n location: Location;\n}\n\nexport interface InsertTableRequest {\n rows: number;\n columns: number;\n location: Location;\n}\n\nexport interface DeleteTableRowRequest {\n tableCellLocation: TableCellLocation;\n}\n\nexport interface DeleteTableColumnRequest {\n tableCellLocation: TableCellLocation;\n}\n\nexport interface CreateParagraphBulletsRequest {\n range: Range;\n bulletPreset: string;\n}\n\nexport interface DeleteParagraphBulletsRequest {\n range: Range;\n}\n\nexport interface Location {\n index: number;\n segmentId?: string;\n}\n\nexport interface Range {\n startIndex: number;\n endIndex: number;\n segmentId?: string;\n}\n\nexport interface ContainsText {\n text: string;\n matchCase: boolean;\n}\n\nexport interface TableCellLocation {\n tableStartLocation: Location;\n rowIndex: number;\n columnIndex: number;\n}\n\nexport interface BatchUpdateResponse {\n documentId: string;\n replies: Reply[];\n writeControl?: WriteControl;\n}\n\nexport interface Reply {\n [key: string]: unknown;\n}\n\nexport interface WriteControl {\n requiredRevisionId: string;\n targetRevisionId: string;\n}\n\n/**\n * Google Docs OAuth provider configuration\n */\nexport const docsOAuthProvider = {\n name: \"docs-google\",\n authorizationUrl: \"https://accounts.google.com/o/oauth2/v2/auth\",\n tokenUrl: \"https://oauth2.googleapis.com/token\",\n clientId: getEnv(\"GOOGLE_CLIENT_ID\") ?? \"\",\n clientSecret: getEnv(\"GOOGLE_CLIENT_SECRET\") ?? \"\",\n scopes: [\n \"https://www.googleapis.com/auth/documents.readonly\",\n \"https://www.googleapis.com/auth/documents\",\n \"https://www.googleapis.com/auth/docs\",\n \"https://www.googleapis.com/auth/drive.readonly\",\n ],\n callbackPath: \"/api/auth/docs-google/callback\",\n};\n\nexport function createDocsClient(userId: string): {\n listDocuments(options?: {\n maxResults?: number;\n orderBy?: \"createdTime\" | \"modifiedTime\" | \"name\";\n }): Promise<DocumentFile[]>;\n getDocument(documentId: string): Promise<Document>;\n createDocument(options: CreateDocumentOptions): Promise<Document>;\n updateDocument(documentId: string, requests: Request[]): Promise<BatchUpdateResponse>;\n insertText(documentId: string, text: string, index: number): Promise<BatchUpdateResponse>;\n deleteContent(documentId: string, startIndex: number, endIndex: number): Promise<BatchUpdateResponse>;\n replaceAllText(\n documentId: string,\n searchText: string,\n replaceText: string,\n matchCase?: boolean,\n ): Promise<BatchUpdateResponse>;\n searchDocuments(query: string, maxResults?: number): Promise<DocumentFile[]>;\n extractText(document: Document): string;\n createDocumentWithContent(title: string, content: string): Promise<Document>;\n} {\n async function getAccessToken(): Promise<string> {\n const token = await getValidToken(docsOAuthProvider, userId, \"docs-google\");\n if (!token) throw new Error(\"Google Docs not connected. Please connect your Google account first.\");\n return token;\n }\n\n async function apiRequest<T>(\n baseUrl: string,\n label: string,\n endpoint: string,\n options: RequestInit = {},\n ): Promise<T> {\n const accessToken = await getAccessToken();\n\n const response = await fetch(`${baseUrl}${endpoint}`, {\n ...options,\n headers: {\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n ...options.headers,\n },\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`${label} API error: ${response.status} - ${error}`);\n }\n\n return response.json();\n }\n\n function docsApiRequest<T>(endpoint: string, options: RequestInit = {}): Promise<T> {\n return apiRequest<T>(DOCS_API_BASE, \"Docs\", endpoint, options);\n }\n\n function driveApiRequest<T>(endpoint: string, options: RequestInit = {}): Promise<T> {\n return apiRequest<T>(DRIVE_API_BASE, \"Drive\", endpoint, options);\n }\n\n function extractText(document: Document): string {\n const textParts: string[] = [];\n\n function processElement(element: StructuralElement): void {\n if (element.paragraph) {\n for (const el of element.paragraph.elements) {\n if (el.textRun) textParts.push(el.textRun.content);\n }\n return;\n }\n\n if (!element.table) return;\n\n for (const row of element.table.tableRows) {\n for (const cell of row.tableCells) {\n for (const child of cell.content) processElement(child);\n }\n }\n }\n\n for (const element of document.body.content) processElement(element);\n return textParts.join(\"\");\n }\n\n async function listDocuments(options: {\n maxResults?: number;\n orderBy?: \"createdTime\" | \"modifiedTime\" | \"name\";\n } = {}): Promise<DocumentFile[]> {\n const params = new URLSearchParams({\n q: \"mimeType='application/vnd.google-apps.document' and trashed=false\",\n fields: \"files(id,name,mimeType,createdTime,modifiedTime,webViewLink,iconLink,thumbnailLink)\",\n pageSize: String(options.maxResults ?? 20),\n orderBy: `${options.orderBy ?? \"modifiedTime\"} desc`,\n });\n\n const result = await driveApiRequest<{ files: DocumentFile[] }>(`/files?${params.toString()}`);\n return result.files ?? [];\n }\n\n async function searchDocuments(query: string, maxResults = 20): Promise<DocumentFile[]> {\n const params = new URLSearchParams({\n q: `mimeType='application/vnd.google-apps.document' and trashed=false and fullText contains '${query}'`,\n fields: \"files(id,name,mimeType,createdTime,modifiedTime,webViewLink,iconLink,thumbnailLink)\",\n pageSize: String(maxResults),\n orderBy: \"modifiedTime desc\",\n });\n\n const result = await driveApiRequest<{ files: DocumentFile[] }>(`/files?${params.toString()}`);\n return result.files ?? [];\n }\n\n function getDocument(documentId: string): Promise<Document> {\n return docsApiRequest<Document>(`/documents/${documentId}`);\n }\n\n function createDocument(options: CreateDocumentOptions): Promise<Document> {\n return docsApiRequest<Document>(\"/documents\", {\n method: \"POST\",\n body: JSON.stringify({ title: options.title }),\n });\n }\n\n function updateDocument(documentId: string, requests: Request[]): Promise<BatchUpdateResponse> {\n return docsApiRequest<BatchUpdateResponse>(`/documents/${documentId}:batchUpdate`, {\n method: \"POST\",\n body: JSON.stringify({ requests }),\n });\n }\n\n function insertText(documentId: string, text: string, index: number): Promise<BatchUpdateResponse> {\n return updateDocument(documentId, [\n {\n insertText: {\n text,\n location: { index },\n },\n },\n ]);\n }\n\n function deleteContent(documentId: string, startIndex: number, endIndex: number): Promise<BatchUpdateResponse> {\n return updateDocument(documentId, [\n {\n deleteContentRange: {\n range: { startIndex, endIndex },\n },\n },\n ]);\n }\n\n function replaceAllText(\n documentId: string,\n searchText: string,\n replaceText: string,\n matchCase = false,\n ): Promise<BatchUpdateResponse> {\n return updateDocument(documentId, [\n {\n replaceAllText: {\n containsText: {\n text: searchText,\n matchCase,\n },\n replaceText,\n },\n },\n ]);\n }\n\n async function createDocumentWithContent(title: string, content: string): Promise<Document> {\n const doc = await createDocument({ title });\n await insertText(doc.documentId, content, 1);\n return getDocument(doc.documentId);\n }\n\n return {\n listDocuments,\n getDocument,\n createDocument,\n updateDocument,\n insertText,\n deleteContent,\n replaceAllText,\n searchDocuments,\n extractText,\n createDocumentWithContent,\n };\n}\n\nexport type DocsClient = ReturnType<typeof createDocsClient>;\n",
|
|
220
220
|
"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\") return undefined;\n return Date.now() + expiresIn * 1000;\n}\n\nasync function postForm(url: string, body: Record<string, string>): Promise<any> {\n const response = await fetch(url, {\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 throw new Error(\n `Token request failed: ${response.status} - ${await response.text()}`,\n );\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 postForm(provider.tokenUrl, {\n client_id: provider.clientId,\n client_secret: provider.clientSecret,\n code,\n grant_type: \"authorization_code\",\n redirect_uri: redirectUri,\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 postForm(provider.tokenUrl, {\n client_id: provider.clientId,\n client_secret: provider.clientSecret,\n refresh_token: refreshToken,\n grant_type: \"refresh_token\",\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",
|
|
221
221
|
"tools/create-document.ts": "import { tool } from \"veryfront/tool\";\nimport { defineSchema } from \"veryfront/schemas\";\nimport { createDocsClient } from \"../../lib/docs-client.ts\";\n\nconst DEFAULT_USER_ID = \"demo-user\";\n\nexport default tool({\n id: \"create-document\",\n description:\n \"Create a new Google Docs document with optional initial content. Returns the new document ID and URL.\",\n inputSchema: defineSchema((v) => v.object({\n title: v.string().describe(\"Title of the new document\"),\n content: v\n .string()\n .optional()\n .describe(\"Optional initial text content to insert into the document\"),\n }))(),\n async execute({ title, content }) {\n const client = createDocsClient(DEFAULT_USER_ID);\n\n const document = content\n ? await client.createDocumentWithContent(title, content)\n : await client.createDocument({ title });\n\n const [docMeta] = await client.listDocuments({ maxResults: 1 });\n const webViewLink = docMeta?.id === document.documentId ? docMeta.webViewLink : undefined;\n\n return {\n documentId: document.documentId,\n title: document.title,\n url: webViewLink ?? `https://docs.google.com/document/d/${document.documentId}/edit`,\n revisionId: document.revisionId,\n };\n },\n});\n",
|
|
222
222
|
"tools/get-document.ts": "import { tool } from \"veryfront/tool\";\nimport { defineSchema } from \"veryfront/schemas\";\nimport { createDocsClient } from \"../../lib/docs-client.ts\";\n\nconst DEFAULT_USER_ID = \"demo-user\";\n\nexport default tool({\n id: \"get-document\",\n description:\n \"Get a Google Docs document's content and metadata. Returns the full document structure including text, formatting, and styles.\",\n inputSchema: defineSchema((v) => v.object({\n documentId: v.string().describe(\"The ID of the document to retrieve\"),\n extractTextOnly: v\n .boolean()\n .default(false)\n .describe(\"If true, only return plain text content without formatting\"),\n }))(),\n async execute({ documentId, extractTextOnly }) {\n const client = createDocsClient(DEFAULT_USER_ID);\n const document = await client.getDocument(documentId);\n\n const { documentId: id, title, revisionId } = document;\n\n if (extractTextOnly) {\n return {\n documentId: id,\n title,\n revisionId,\n text: client.extractText(document),\n };\n }\n\n return {\n documentId: id,\n title,\n revisionId,\n body: document.body,\n documentStyle: document.documentStyle,\n };\n },\n});\n",
|
|
@@ -230,7 +230,7 @@ export default {
|
|
|
230
230
|
".env.example": "# Google Drive Integration\n# Create OAuth credentials at https://console.cloud.google.com/apis/credentials\n# Make sure to enable:\n# - Google Drive API: https://console.cloud.google.com/apis/library/drive.googleapis.com\n#\n# Note: These credentials are shared across all Google integrations (Gmail, Calendar, Sheets, Drive)\n\nGOOGLE_CLIENT_ID=your_client_id_here\nGOOGLE_CLIENT_SECRET=your_client_secret_here\n",
|
|
231
231
|
"app/api/auth/drive/callback/route.ts": "/**\n * Google Drive OAuth Callback\n *\n * Handles the OAuth callback from Google and stores the tokens.\n */\n\nimport { createOAuthCallbackHandler, driveConfig } from \"veryfront/oauth\";\nimport { tokenStore } from \"../../../../../lib/token-store.ts\";\nimport { oauthMemoryTokenStore } from \"../../../../../lib/oauth-memory-store.ts\";\n\nconst hybridTokenStore = {\n getTokens(serviceId: string, userId: string) {\n return tokenStore.getToken(userId, serviceId);\n },\n async setTokens(\n serviceId: string,\n userId: string,\n tokens: { accessToken: string; refreshToken?: string; expiresAt?: number },\n ) {\n await tokenStore.setToken(userId, serviceId, tokens);\n },\n async clearTokens(serviceId: string, userId: string) {\n await tokenStore.revokeToken(userId, serviceId);\n },\n setState(\n state: string,\n meta: {\n userId: string;\n serviceId: string;\n codeVerifier?: string;\n redirectUri?: string;\n scopes?: string[];\n createdAt: number;\n },\n ) {\n return oauthMemoryTokenStore.setState(state, meta);\n },\n consumeState(state: string) {\n return oauthMemoryTokenStore.consumeState(state);\n },\n};\n\nexport const GET = createOAuthCallbackHandler(driveConfig, { tokenStore: hybridTokenStore });\n",
|
|
232
232
|
"app/api/auth/drive/route.ts": "import { createOAuthInitHandler, driveConfig } from \"veryfront/oauth\";\nimport { oauthMemoryTokenStore } from \"../../../../../lib/oauth-memory-store.ts\";\nimport { requireUserIdFromRequest } from \"../../../../../lib/user-id.ts\";\n\nfunction getUserId(request: Request): string {\n return requireUserIdFromRequest(request);\n}\n\nexport const GET = createOAuthInitHandler(driveConfig, {\n tokenStore: oauthMemoryTokenStore,\n getUserId,\n});",
|
|
233
|
-
"lib/drive-client.ts": "import { getValidToken } from \"./oauth.ts\";\n\nfunction getEnv(key: string): string | undefined {\n // @ts-ignore - Deno global\n if (typeof Deno !== \"undefined\") return Deno.env.get(key);\n // @ts-ignore - process global\n if (typeof process !== \"undefined\" && process.env) return process.env[key];\n return undefined;\n}\n\nconst DRIVE_API_BASE = \"https://www.googleapis.com/drive/v3\";\n\nexport interface DriveFile {\n id: string;\n name: string;\n mimeType: string;\n kind: string;\n createdTime: string;\n modifiedTime: string;\n size?: string;\n webViewLink?: string;\n webContentLink?: string;\n iconLink?: string;\n thumbnailLink?: string;\n parents?: string[];\n starred?: boolean;\n trashed?: boolean;\n shared?: boolean;\n owners?: Array<{\n displayName: string;\n emailAddress: string;\n photoLink?: string;\n }>;\n lastModifyingUser?: {\n displayName: string;\n emailAddress: string;\n photoLink?: string;\n };\n capabilities?: {\n canEdit?: boolean;\n canComment?: boolean;\n canShare?: boolean;\n canDelete?: boolean;\n canDownload?: boolean;\n };\n}\n\nexport interface DriveFileList {\n files: DriveFile[];\n nextPageToken?: string;\n incompleteSearch?: boolean;\n}\n\nexport interface CreateFolderOptions {\n name: string;\n parentId?: string;\n description?: string;\n}\n\nexport interface UploadFileOptions {\n name: string;\n content: string;\n mimeType: string;\n parentId?: string;\n description?: string;\n}\n\nexport interface ListFilesOptions {\n folderId?: string;\n pageSize?: number;\n pageToken?: string;\n orderBy?: string;\n query?: string;\n}\n\nexport interface SearchFilesOptions {\n query: string;\n pageSize?: number;\n pageToken?: string;\n orderBy?: string;\n}\n\nexport const driveOAuthProvider = {\n name: \"drive\",\n authorizationUrl: \"https://accounts.google.com/o/oauth2/v2/auth\",\n tokenUrl: \"https://oauth2.googleapis.com/token\",\n clientId: getEnv(\"GOOGLE_CLIENT_ID\") ?? \"\",\n clientSecret: getEnv(\"GOOGLE_CLIENT_SECRET\") ?? \"\",\n scopes: [\n \"https://www.googleapis.com/auth/drive
|
|
233
|
+
"lib/drive-client.ts": "import { getValidToken } from \"./oauth.ts\";\n\nfunction getEnv(key: string): string | undefined {\n // @ts-ignore - Deno global\n if (typeof Deno !== \"undefined\") return Deno.env.get(key);\n // @ts-ignore - process global\n if (typeof process !== \"undefined\" && process.env) return process.env[key];\n return undefined;\n}\n\nconst DRIVE_API_BASE = \"https://www.googleapis.com/drive/v3\";\n\nexport interface DriveFile {\n id: string;\n name: string;\n mimeType: string;\n kind: string;\n createdTime: string;\n modifiedTime: string;\n size?: string;\n webViewLink?: string;\n webContentLink?: string;\n iconLink?: string;\n thumbnailLink?: string;\n parents?: string[];\n starred?: boolean;\n trashed?: boolean;\n shared?: boolean;\n owners?: Array<{\n displayName: string;\n emailAddress: string;\n photoLink?: string;\n }>;\n lastModifyingUser?: {\n displayName: string;\n emailAddress: string;\n photoLink?: string;\n };\n capabilities?: {\n canEdit?: boolean;\n canComment?: boolean;\n canShare?: boolean;\n canDelete?: boolean;\n canDownload?: boolean;\n };\n}\n\nexport interface DriveFileList {\n files: DriveFile[];\n nextPageToken?: string;\n incompleteSearch?: boolean;\n}\n\nexport interface CreateFolderOptions {\n name: string;\n parentId?: string;\n description?: string;\n}\n\nexport interface UploadFileOptions {\n name: string;\n content: string;\n mimeType: string;\n parentId?: string;\n description?: string;\n}\n\nexport interface ListFilesOptions {\n folderId?: string;\n pageSize?: number;\n pageToken?: string;\n orderBy?: string;\n query?: string;\n}\n\nexport interface SearchFilesOptions {\n query: string;\n pageSize?: number;\n pageToken?: string;\n orderBy?: string;\n}\n\nexport const driveOAuthProvider = {\n name: \"drive\",\n authorizationUrl: \"https://accounts.google.com/o/oauth2/v2/auth\",\n tokenUrl: \"https://oauth2.googleapis.com/token\",\n clientId: getEnv(\"GOOGLE_CLIENT_ID\") ?? \"\",\n clientSecret: getEnv(\"GOOGLE_CLIENT_SECRET\") ?? \"\",\n scopes: [\n \"https://www.googleapis.com/auth/drive\",\n ],\n callbackPath: \"/api/auth/drive/callback\",\n};\n\nexport function createDriveClient(userId: string): {\n listFiles(options?: ListFilesOptions): Promise<DriveFileList>;\n getFile(fileId: string): Promise<DriveFile>;\n searchFiles(options: SearchFilesOptions): Promise<DriveFileList>;\n createFolder(options: CreateFolderOptions): Promise<DriveFile>;\n uploadFile(options: UploadFileOptions): Promise<DriveFile>;\n downloadFile(fileId: string): Promise<string>;\n deleteFile(fileId: string): Promise<void>;\n copyFile(fileId: string, name: string, parentId?: string): Promise<DriveFile>;\n updateFile(\n fileId: string,\n updates: { name?: string; description?: string; starred?: boolean },\n ): Promise<DriveFile>;\n} {\n async function getAccessToken(): Promise<string> {\n const token = await getValidToken(driveOAuthProvider, userId, \"drive\");\n if (!token) {\n throw new Error(\"Google Drive not connected. Please connect your Google account first.\");\n }\n return token;\n }\n\n async function driveApiRequest<T>(endpoint: string, options: RequestInit = {}): Promise<T> {\n const accessToken = await getAccessToken();\n\n const response = await fetch(`${DRIVE_API_BASE}${endpoint}`, {\n ...options,\n headers: {\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n ...options.headers,\n },\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Drive API error: ${response.status} - ${error}`);\n }\n\n if (response.status === 204) return undefined as T;\n return response.json();\n }\n\n function buildMetadata(options: {\n name: string;\n mimeType: string;\n parentId?: string;\n description?: string;\n }): Record<string, unknown> {\n const metadata: Record<string, unknown> = {\n name: options.name,\n mimeType: options.mimeType,\n };\n\n if (options.parentId) metadata.parents = [options.parentId];\n if (options.description) metadata.description = options.description;\n\n return metadata;\n }\n\n const fileFields =\n \"id,name,mimeType,kind,createdTime,modifiedTime,size,webViewLink,webContentLink,iconLink,thumbnailLink,parents,starred,trashed,shared,owners,lastModifyingUser,capabilities\";\n\n return {\n async listFiles(options: ListFilesOptions = {}): Promise<DriveFileList> {\n const params = new URLSearchParams({\n fields: `nextPageToken,incompleteSearch,files(${fileFields})`,\n pageSize: String(options.pageSize ?? 100),\n orderBy: options.orderBy ?? \"modifiedTime desc\",\n });\n\n let query = \"trashed=false\";\n if (options.folderId) query += ` and '${options.folderId}' in parents`;\n if (options.query) query += ` and ${options.query}`;\n\n params.append(\"q\", query);\n if (options.pageToken) params.append(\"pageToken\", options.pageToken);\n\n return driveApiRequest<DriveFileList>(`/files?${params.toString()}`);\n },\n\n async getFile(fileId: string): Promise<DriveFile> {\n const params = new URLSearchParams({ fields: fileFields });\n return driveApiRequest<DriveFile>(`/files/${fileId}?${params.toString()}`);\n },\n\n async searchFiles(options: SearchFilesOptions): Promise<DriveFileList> {\n const params = new URLSearchParams({\n fields:\n \"nextPageToken,incompleteSearch,files(id,name,mimeType,kind,createdTime,modifiedTime,size,webViewLink,webContentLink,iconLink,thumbnailLink,parents,starred,trashed)\",\n pageSize: String(options.pageSize ?? 100),\n q: `${options.query} and trashed=false`,\n orderBy: options.orderBy ?? \"modifiedTime desc\",\n });\n\n if (options.pageToken) params.append(\"pageToken\", options.pageToken);\n\n return driveApiRequest<DriveFileList>(`/files?${params.toString()}`);\n },\n\n async createFolder(options: CreateFolderOptions): Promise<DriveFile> {\n const metadata = buildMetadata({\n name: options.name,\n mimeType: \"application/vnd.google-apps.folder\",\n parentId: options.parentId,\n description: options.description,\n });\n\n return driveApiRequest<DriveFile>(\"/files\", {\n method: \"POST\",\n body: JSON.stringify(metadata),\n });\n },\n\n async uploadFile(options: UploadFileOptions): Promise<DriveFile> {\n const accessToken = await getAccessToken();\n\n const boundary = \"-------314159265358979323846\";\n const delimiter = `\\r\\n--${boundary}\\r\\n`;\n const closeDelimiter = `\\r\\n--${boundary}--`;\n\n const metadata = buildMetadata({\n name: options.name,\n mimeType: options.mimeType,\n parentId: options.parentId,\n description: options.description,\n });\n\n const multipartRequestBody =\n delimiter +\n \"Content-Type: application/json\\r\\n\\r\\n\" +\n JSON.stringify(metadata) +\n delimiter +\n `Content-Type: ${options.mimeType}\\r\\n\\r\\n` +\n options.content +\n closeDelimiter;\n\n const response = await fetch(\n \"https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&fields=id,name,mimeType,kind,createdTime,modifiedTime,size,webViewLink,webContentLink\",\n {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": `multipart/related; boundary=${boundary}`,\n },\n body: multipartRequestBody,\n },\n );\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Drive upload error: ${response.status} - ${error}`);\n }\n\n return response.json();\n },\n\n async downloadFile(fileId: string): Promise<string> {\n const accessToken = await getAccessToken();\n\n const response = await fetch(`${DRIVE_API_BASE}/files/${fileId}?alt=media`, {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Drive download error: ${response.status} - ${error}`);\n }\n\n return response.text();\n },\n\n async deleteFile(fileId: string): Promise<void> {\n await driveApiRequest(`/files/${fileId}`, { method: \"DELETE\" });\n },\n\n async copyFile(fileId: string, name: string, parentId?: string): Promise<DriveFile> {\n const metadata: Record<string, unknown> = { name };\n if (parentId) metadata.parents = [parentId];\n\n return driveApiRequest<DriveFile>(`/files/${fileId}/copy`, {\n method: \"POST\",\n body: JSON.stringify(metadata),\n });\n },\n\n async updateFile(\n fileId: string,\n updates: { name?: string; description?: string; starred?: boolean },\n ): Promise<DriveFile> {\n return driveApiRequest<DriveFile>(`/files/${fileId}`, {\n method: \"PATCH\",\n body: JSON.stringify(updates),\n });\n },\n };\n}\n\nexport type DriveClient = ReturnType<typeof createDriveClient>;\n",
|
|
234
234
|
"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 buildTokenRequest(\n provider: OAuthProvider,\n body: Record<string, string>,\n): RequestInit {\n return {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n client_id: provider.clientId,\n client_secret: provider.clientSecret,\n ...body,\n }),\n };\n}\n\nasync function fetchToken(\n provider: OAuthProvider,\n body: Record<string, string>,\n errorPrefix: string,\n): Promise<any> {\n const response = await fetch(\n provider.tokenUrl,\n buildTokenRequest(provider, 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\nfunction toOAuthToken(data: any, fallbackRefreshToken?: string): OAuthToken {\n const expiresIn = data.expires_in;\n\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token ?? fallbackRefreshToken,\n expiresAt: expiresIn ? Date.now() + expiresIn * 1000 : undefined,\n tokenType: data.token_type ?? \"Bearer\",\n scope: data.scope,\n };\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 fetchToken(\n provider,\n {\n code,\n grant_type: \"authorization_code\",\n redirect_uri: redirectUri,\n },\n \"Token exchange failed\",\n );\n\n return toOAuthToken(data);\n}\n\nexport async function refreshAccessToken(\n provider: OAuthProvider,\n refreshToken: string,\n): Promise<OAuthToken> {\n const data = await fetchToken(\n provider,\n {\n refresh_token: refreshToken,\n grant_type: \"refresh_token\",\n },\n \"Token refresh failed\",\n );\n\n return toOAuthToken(data, refreshToken);\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) return token.accessToken;\n if (!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",
|
|
235
235
|
"tools/create-folder.ts": "import { tool } from \"veryfront/tool\";\nimport { defineSchema } from \"veryfront/schemas\";\nimport { createDriveClient } from \"../../lib/drive-client.ts\";\n\nconst DEFAULT_USER_ID = \"demo-user\";\n\nexport default tool({\n id: \"create-folder\",\n description:\n \"Create a new folder in Google Drive. Can optionally specify a parent folder. Returns the new folder ID and details.\",\n inputSchema: defineSchema((v) => v.object({\n name: v.string().describe(\"Name of the folder to create\"),\n parentId: v\n .string()\n .optional()\n .describe(\"ID of the parent folder. If not provided, creates in root.\"),\n description: v\n .string()\n .optional()\n .describe(\"Optional description for the folder\"),\n }))(),\n async execute({ name, parentId, description }) {\n const client = createDriveClient(DEFAULT_USER_ID);\n const folder = await client.createFolder({ name, parentId, description });\n\n return {\n id: folder.id,\n name: folder.name,\n mimeType: folder.mimeType,\n createdTime: folder.createdTime,\n modifiedTime: folder.modifiedTime,\n webViewLink: folder.webViewLink,\n parents: folder.parents,\n };\n },\n});\n",
|
|
236
236
|
"tools/get-file.ts": "import { tool } from \"veryfront/tool\";\nimport { defineSchema } from \"veryfront/schemas\";\nimport { createDriveClient } from \"../../lib/drive-client.ts\";\n\nconst DEFAULT_USER_ID = \"demo-user\";\nconst FOLDER_MIME_TYPE = \"application/vnd.google-apps.folder\";\n\nexport default tool({\n id: \"get-file\",\n description:\n \"Get detailed metadata about a specific file or folder in Google Drive. Returns detailed information including sharing settings, owners, and capabilities.\",\n inputSchema: defineSchema((v) => v.object({\n fileId: v.string().describe(\"The ID of the file or folder to retrieve\"),\n }))(),\n async execute({ fileId }) {\n const client = createDriveClient(DEFAULT_USER_ID);\n const file = await client.getFile(fileId);\n\n const lastModifyingUser = file.lastModifyingUser\n ? {\n name: file.lastModifyingUser.displayName,\n email: file.lastModifyingUser.emailAddress,\n photoLink: file.lastModifyingUser.photoLink,\n }\n : undefined;\n\n return {\n id: file.id,\n name: file.name,\n mimeType: file.mimeType,\n isFolder: file.mimeType === FOLDER_MIME_TYPE,\n size: file.size,\n createdTime: file.createdTime,\n modifiedTime: file.modifiedTime,\n webViewLink: file.webViewLink,\n webContentLink: file.webContentLink,\n iconLink: file.iconLink,\n thumbnailLink: file.thumbnailLink,\n parents: file.parents,\n starred: file.starred,\n trashed: file.trashed,\n shared: file.shared,\n owners: file.owners?.map((owner) => ({\n name: owner.displayName,\n email: owner.emailAddress,\n photoLink: owner.photoLink,\n })),\n lastModifyingUser,\n capabilities: file.capabilities,\n };\n },\n});\n",
|
package/esm/deno.js
CHANGED
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
* @module agent/memory
|
|
5
5
|
*/
|
|
6
6
|
export { estimateTokens, type Memory, type MemoryConfigBase, type MemoryPersistence, type MemoryStats, type MinimalMessage, } from "./memory-interface.js";
|
|
7
|
-
export { BufferMemory, ConversationMemory, createMemory, SummaryMemory } from "./memory.js";
|
|
7
|
+
export { BufferMemory, ConversationMemory, createAgentMemory, createMemory, NoMemory, SummaryMemory, } from "./memory.js";
|
|
8
8
|
export { createRedisMemory, type RedisClient, RedisMemory, type RedisMemoryConfig, } from "./redis.js";
|
|
9
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/memory/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,cAAc,EACd,KAAK,MAAM,EACX,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,cAAc,GACpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/memory/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,cAAc,EACd,KAAK,MAAM,EACX,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,cAAc,GACpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,EACZ,QAAQ,EACR,aAAa,GACd,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,iBAAiB,EACjB,KAAK,WAAW,EAChB,WAAW,EACX,KAAK,iBAAiB,GACvB,MAAM,YAAY,CAAC"}
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
* @module agent/memory
|
|
5
5
|
*/
|
|
6
6
|
export { estimateTokens, } from "./memory-interface.js";
|
|
7
|
-
export { BufferMemory, ConversationMemory, createMemory, SummaryMemory } from "./memory.js";
|
|
7
|
+
export { BufferMemory, ConversationMemory, createAgentMemory, createMemory, NoMemory, SummaryMemory, } from "./memory.js";
|
|
8
8
|
export { createRedisMemory, RedisMemory, } from "./redis.js";
|
|
@@ -12,6 +12,13 @@ export interface MemoryConfigBase {
|
|
|
12
12
|
type: string;
|
|
13
13
|
maxTokens?: number;
|
|
14
14
|
maxMessages?: number;
|
|
15
|
+
/**
|
|
16
|
+
* Persist conversation history across `stream()` / `generate()` calls on the
|
|
17
|
+
* agent instance. Defaults to `true` when a memory config is provided. Set to
|
|
18
|
+
* `false` to run every call in isolation (no shared history), the same
|
|
19
|
+
* effect as omitting `memory` entirely.
|
|
20
|
+
*/
|
|
21
|
+
enabled?: boolean;
|
|
15
22
|
}
|
|
16
23
|
/** Public API contract for memory stats. */
|
|
17
24
|
export interface MemoryStats {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-interface.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/memory/memory-interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;4BAS4B;AAE5B,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"memory-interface.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/memory/memory-interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;4BAS4B;AAE5B,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,4CAA4C;AAC5C,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC/C,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,sCAAsC;AACtC,MAAM,WAAW,MAAM,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc;IAC/D,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,WAAW,IAAI,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAC5B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,QAAQ,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;CAClC;AAED,kDAAkD;AAClD,MAAM,WAAW,iBAAiB,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc;IAC1E,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IACpC,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAC5C,MAAM,CAOR;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,MAAM,CASjE"}
|
|
@@ -39,7 +39,32 @@ export declare class SummaryMemory<M extends MinimalMessage = MinimalMessage> im
|
|
|
39
39
|
getStats(): Promise<MemoryStats>;
|
|
40
40
|
private summarizeOldMessages;
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* No-op memory.
|
|
44
|
+
*
|
|
45
|
+
* Holds nothing and never persists. Used when an agent has no `memory` config
|
|
46
|
+
* (the documented stateless default) or when `memory.enabled === false`. Every
|
|
47
|
+
* `stream()` / `generate()` call then runs in isolation on just its own input,
|
|
48
|
+
* which is what makes concurrent fan-out on a shared agent instance safe: runs
|
|
49
|
+
* cannot interleave into a shared conversation. Multi-step tool loops are
|
|
50
|
+
* unaffected: in-run continuity is driven by the loop's local message array,
|
|
51
|
+
* not by this store.
|
|
52
|
+
*/
|
|
53
|
+
export declare class NoMemory<M extends MinimalMessage = MinimalMessage> implements Memory<M> {
|
|
54
|
+
add(_message: M): Promise<void>;
|
|
55
|
+
getMessages(): Promise<M[]>;
|
|
56
|
+
clear(): Promise<void>;
|
|
57
|
+
getStats(): Promise<MemoryStats>;
|
|
58
|
+
}
|
|
42
59
|
/** Create memory. */
|
|
43
60
|
export declare function createMemory<M extends MinimalMessage = MinimalMessage>(config: MemoryConfigBase): Memory<M>;
|
|
61
|
+
/**
|
|
62
|
+
* Resolve the memory store for an agent runtime.
|
|
63
|
+
*
|
|
64
|
+
* Agents are stateless by default: with no `memory` config (or `enabled: false`)
|
|
65
|
+
* the runtime gets a {@link NoMemory} store so calls never share conversation
|
|
66
|
+
* history. A provided config opts in to cross-call persistence.
|
|
67
|
+
*/
|
|
68
|
+
export declare function createAgentMemory<M extends MinimalMessage = MinimalMessage>(config?: MemoryConfigBase): Memory<M>;
|
|
44
69
|
export {};
|
|
45
70
|
//# sourceMappingURL=memory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/memory/memory.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,MAAM,EACX,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,cAAc,EACpB,MAAM,uBAAuB,CAAC;AAG/B,KAAK,eAAe,GAAG,cAAc,GAAG,QAAQ,CAAC;AAgDjD,uBAAe,gBAAgB,CAAC,CAAC,SAAS,cAAc,CAAE,YAAW,MAAM,CAAC,CAAC,CAAC;IAC5E,SAAS,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAM;IAC7B,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;IACxD,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE/C,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAEvC,WAAW,IAAI,OAAO,CAAC,CAAC,EAAE,CAAC;IAI3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQtB,QAAQ,IAAI,OAAO,CAAC,WAAW,CAAC;CAGjC;AAED,qCAAqC;AACrC,qBAAa,kBAAkB,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,CACvE,SAAQ,gBAAgB,CAAC,CAAC,CAAC;IAIf,OAAO,CAAC,MAAM;IAH1B,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAG,cAAc,CAAU;IACxD,SAAS,CAAC,QAAQ,CAAC,UAAU,+BAA+B;gBAExC,MAAM,EAAE,gBAAgB;IAI5C,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB9B,OAAO,CAAC,gBAAgB;CAazB;AAED,+BAA+B;AAC/B,qBAAa,YAAY,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,CAAE,SAAQ,gBAAgB,CAAC,CAAC,CAAC;IAC9F,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAG,QAAQ,CAAU;IAClD,SAAS,CAAC,QAAQ,CAAC,UAAU,yBAAyB;IACtD,OAAO,CAAC,UAAU,CAAS;gBAEf,MAAM,EAAE,gBAAgB;IAKpC,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CAe/B;AAED,gCAAgC;AAChC,qBAAa,aAAa,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,CAAE,YAAW,MAAM,CAAC,CAAC,CAAC;IAK5E,OAAO,CAAC,MAAM;IAJ1B,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,OAAO,CAAM;IACrB,OAAO,CAAC,gBAAgB,CAAS;gBAEb,MAAM,EAAE,gBAAgB;IAI5C,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAc9B,WAAW,IAAI,OAAO,CAAC,CAAC,EAAE,CAAC;IA0B3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAatB,QAAQ,IAAI,OAAO,CAAC,WAAW,CAAC;IAkBhC,OAAO,CAAC,oBAAoB;CAgB7B;AAED,qBAAqB;AACrB,wBAAgB,YAAY,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,EACpE,MAAM,EAAE,gBAAgB,GACvB,MAAM,CAAC,CAAC,CAAC,CAUX"}
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/memory/memory.ts"],"names":[],"mappings":"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"}
|
|
@@ -144,6 +144,31 @@ export class SummaryMemory {
|
|
|
144
144
|
return Promise.resolve();
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* No-op memory.
|
|
149
|
+
*
|
|
150
|
+
* Holds nothing and never persists. Used when an agent has no `memory` config
|
|
151
|
+
* (the documented stateless default) or when `memory.enabled === false`. Every
|
|
152
|
+
* `stream()` / `generate()` call then runs in isolation on just its own input,
|
|
153
|
+
* which is what makes concurrent fan-out on a shared agent instance safe: runs
|
|
154
|
+
* cannot interleave into a shared conversation. Multi-step tool loops are
|
|
155
|
+
* unaffected: in-run continuity is driven by the loop's local message array,
|
|
156
|
+
* not by this store.
|
|
157
|
+
*/
|
|
158
|
+
export class NoMemory {
|
|
159
|
+
add(_message) {
|
|
160
|
+
return Promise.resolve();
|
|
161
|
+
}
|
|
162
|
+
getMessages() {
|
|
163
|
+
return Promise.resolve([]);
|
|
164
|
+
}
|
|
165
|
+
clear() {
|
|
166
|
+
return Promise.resolve();
|
|
167
|
+
}
|
|
168
|
+
getStats() {
|
|
169
|
+
return Promise.resolve({ totalMessages: 0, estimatedTokens: 0, type: "none" });
|
|
170
|
+
}
|
|
171
|
+
}
|
|
147
172
|
/** Create memory. */
|
|
148
173
|
export function createMemory(config) {
|
|
149
174
|
switch (config.type) {
|
|
@@ -156,3 +181,16 @@ export function createMemory(config) {
|
|
|
156
181
|
return new ConversationMemory(config);
|
|
157
182
|
}
|
|
158
183
|
}
|
|
184
|
+
/**
|
|
185
|
+
* Resolve the memory store for an agent runtime.
|
|
186
|
+
*
|
|
187
|
+
* Agents are stateless by default: with no `memory` config (or `enabled: false`)
|
|
188
|
+
* the runtime gets a {@link NoMemory} store so calls never share conversation
|
|
189
|
+
* history. A provided config opts in to cross-call persistence.
|
|
190
|
+
*/
|
|
191
|
+
export function createAgentMemory(config) {
|
|
192
|
+
if (!config || config.enabled === false) {
|
|
193
|
+
return new NoMemory();
|
|
194
|
+
}
|
|
195
|
+
return createMemory(config);
|
|
196
|
+
}
|
|
@@ -2,8 +2,6 @@ export declare const AGENT_DEFAULTS: {
|
|
|
2
2
|
readonly maxTokens: 4096;
|
|
3
3
|
readonly temperature: 0;
|
|
4
4
|
readonly maxSteps: 20;
|
|
5
|
-
readonly memoryType: "conversation";
|
|
6
|
-
readonly memoryMaxTokens: 4000;
|
|
7
5
|
};
|
|
8
6
|
export declare const STREAMING_DEFAULTS: {
|
|
9
7
|
readonly maxBufferSize: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/defaults.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/defaults.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc;;;;CAIjB,CAAC;AAEX,eAAO,MAAM,kBAAkB;;;CAGrB,CAAC"}
|
|
@@ -31,6 +31,15 @@ export declare class AgentRuntime {
|
|
|
31
31
|
private memory;
|
|
32
32
|
private status;
|
|
33
33
|
constructor(id: string, config: AgentConfig);
|
|
34
|
+
/**
|
|
35
|
+
* Persist this turn's input, then resolve the messages to run on. Configured
|
|
36
|
+
* memory returns the full persisted conversation (this turn + history); the
|
|
37
|
+
* stateless default persists nothing and returns empty, so we fall back to
|
|
38
|
+
* this turn's input. That fallback is what keeps concurrent stream()/
|
|
39
|
+
* generate() calls on a shared instance isolated instead of interleaving into
|
|
40
|
+
* one conversation.
|
|
41
|
+
*/
|
|
42
|
+
private prepareTurnMessages;
|
|
34
43
|
private resolveModelTransport;
|
|
35
44
|
private resolveRuntimeState;
|
|
36
45
|
private notifyToolResult;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,KAAK,WAAW,EAEhB,KAAK,aAAa,EAGlB,KAAK,OAAO,EAGZ,KAAK,QAAQ,EAGd,MAAM,aAAa,CAAC;AAIrB,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,7 +14,7 @@ import { getTextFromParts, } from "../types.js";
|
|
|
14
14
|
import { ensureModelReady, resolveModel } from "../../provider/index.js";
|
|
15
15
|
import { generateId } from "../../utils/id.js";
|
|
16
16
|
import { detectPlatform, getPlatformCapabilities } from "../../platform/core-platform.js";
|
|
17
|
-
import {
|
|
17
|
+
import { createAgentMemory } from "../memory/index.js";
|
|
18
18
|
import { serverLogger } from "../../utils/index.js";
|
|
19
19
|
import { addSpanEvent, setSpanAttributes, withSpan, } from "../../observability/tracing/index.js";
|
|
20
20
|
import { convertToTextGenerationRuntimeMessages } from "./text-generation-runtime-message-converter.js";
|
|
@@ -24,7 +24,6 @@ import { getRuntimeRemoteToolSources } from "./mcp-server-tool-sources.js";
|
|
|
24
24
|
import { createStreamState, processStream, } from "./chat-stream-handler.js";
|
|
25
25
|
import { repairToolCall } from "./repair-tool-call.js";
|
|
26
26
|
import { MiddlewareChain } from "../middleware/chain.js";
|
|
27
|
-
import { AGENT_DEFAULTS } from "./defaults.js";
|
|
28
27
|
import { tryGetCacheKeyContext } from "../../cache/cache-key-builder.js";
|
|
29
28
|
import { isLocalModelRuntime } from "../../provider/runtime-inspection.js";
|
|
30
29
|
import { generateText, streamText } from "../../runtime/runtime-bridge.js";
|
|
@@ -59,7 +58,7 @@ function isAbortError(error, abortSignal) {
|
|
|
59
58
|
}
|
|
60
59
|
function warnLocalToolSkipping(agentId, modelId) {
|
|
61
60
|
logger.warn(`Agent "${agentId}" has tools configured but is using local model "${modelId}". ` +
|
|
62
|
-
"Local models don't support tool calling
|
|
61
|
+
"Local models don't support tool calling. Tools will be skipped. " +
|
|
63
62
|
"Set VERYFRONT_API_TOKEN and VERYFRONT_PROJECT_SLUG, or configure " +
|
|
64
63
|
"OPENAI_API_KEY, ANTHROPIC_API_KEY, or GOOGLE_API_KEY for full tool support.");
|
|
65
64
|
}
|
|
@@ -72,9 +71,25 @@ export class AgentRuntime {
|
|
|
72
71
|
constructor(id, config) {
|
|
73
72
|
this.id = id;
|
|
74
73
|
this.config = config;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
// Agents are stateless by default (see docs/guides/memory-and-streaming.md):
|
|
75
|
+
// with no `memory` config, calls never share conversation history, so
|
|
76
|
+
// concurrent stream()/generate() on a shared instance stay isolated.
|
|
77
|
+
// Providing `memory` opts in to cross-call persistence.
|
|
78
|
+
this.memory = createAgentMemory(config.memory);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Persist this turn's input, then resolve the messages to run on. Configured
|
|
82
|
+
* memory returns the full persisted conversation (this turn + history); the
|
|
83
|
+
* stateless default persists nothing and returns empty, so we fall back to
|
|
84
|
+
* this turn's input. That fallback is what keeps concurrent stream()/
|
|
85
|
+
* generate() calls on a shared instance isolated instead of interleaving into
|
|
86
|
+
* one conversation.
|
|
87
|
+
*/
|
|
88
|
+
async prepareTurnMessages(inputMessages) {
|
|
89
|
+
for (const msg of inputMessages)
|
|
90
|
+
await this.memory.add(msg);
|
|
91
|
+
const persisted = await this.memory.getMessages();
|
|
92
|
+
return persisted.length > 0 ? persisted : inputMessages;
|
|
78
93
|
}
|
|
79
94
|
async resolveModelTransport(context, modelOverride, mode) {
|
|
80
95
|
const requestedModel = resolveConfiguredAgentModel(modelOverride || this.config.model);
|
|
@@ -130,9 +145,7 @@ export class AgentRuntime {
|
|
|
130
145
|
"agent.model": resolvedModelString,
|
|
131
146
|
});
|
|
132
147
|
const inputMessages = normalizeInput(input);
|
|
133
|
-
|
|
134
|
-
await this.memory.add(msg);
|
|
135
|
-
const messages = await this.memory.getMessages();
|
|
148
|
+
const messages = await this.prepareTurnMessages(inputMessages);
|
|
136
149
|
const systemPrompt = await this.resolveSystemPrompt();
|
|
137
150
|
const agentContext = {
|
|
138
151
|
agentId: this.id,
|
|
@@ -159,9 +172,7 @@ export class AgentRuntime {
|
|
|
159
172
|
if (resolvedModelString !== requestedModel) {
|
|
160
173
|
logger.info(`⚡ Using runtime model "${resolvedModelString}" instead of "${requestedModel}".`);
|
|
161
174
|
}
|
|
162
|
-
|
|
163
|
-
await this.memory.add(msg);
|
|
164
|
-
const memoryMessages = await this.memory.getMessages();
|
|
175
|
+
const memoryMessages = await this.prepareTurnMessages(messages);
|
|
165
176
|
const systemPrompt = await this.resolveSystemPrompt();
|
|
166
177
|
const encoder = new TextEncoder();
|
|
167
178
|
const streamAbortController = new AbortController();
|
|
@@ -185,7 +196,7 @@ export class AgentRuntime {
|
|
|
185
196
|
...context,
|
|
186
197
|
};
|
|
187
198
|
const textPartId = generateId("text");
|
|
188
|
-
// Resolve model BEFORE creating the ReadableStream
|
|
199
|
+
// Resolve model BEFORE creating the ReadableStream. If this throws
|
|
189
200
|
// (e.g., no_ai_available), the error propagates to the caller who can
|
|
190
201
|
// return a proper error response (503) instead of a 200 with an error event.
|
|
191
202
|
const languageModel = transport.languageModel;
|
|
@@ -206,6 +217,13 @@ export class AgentRuntime {
|
|
|
206
217
|
platform: detectPlatform(),
|
|
207
218
|
};
|
|
208
219
|
const chain = new MiddlewareChain(this.config.middleware);
|
|
220
|
+
// Hold the in-flight agent-loop promise so stream cancellation can detach a
|
|
221
|
+
// no-op rejection handler. When the client cancels, we abort the shared
|
|
222
|
+
// signal; the loop (model fetch / tool execution) then rejects with an
|
|
223
|
+
// AbortError. The `start` body awaits it, but cancellation can land after
|
|
224
|
+
// that await settles, leaving the rejection without a consumer, fatal as
|
|
225
|
+
// an unhandled rejection under Deno (#2334).
|
|
226
|
+
let inFlight;
|
|
209
227
|
return new ReadableStream({
|
|
210
228
|
start: async (controller) => {
|
|
211
229
|
try {
|
|
@@ -213,7 +231,7 @@ export class AgentRuntime {
|
|
|
213
231
|
this.status = "streaming";
|
|
214
232
|
const messageId = generateMessageId();
|
|
215
233
|
sendSSE(controller, encoder, { type: "message-start", messageId });
|
|
216
|
-
// Report the effective model
|
|
234
|
+
// Report the effective model. When resolveModel falls back from
|
|
217
235
|
// cloud to local (e.g. missing API key), use the resolved object's
|
|
218
236
|
// modelId so the client avatar matches the actual provider.
|
|
219
237
|
const effectiveModel = isLocal && !resolvedModelString.startsWith("local/")
|
|
@@ -226,7 +244,8 @@ export class AgentRuntime {
|
|
|
226
244
|
model: effectiveModel,
|
|
227
245
|
},
|
|
228
246
|
});
|
|
229
|
-
|
|
247
|
+
inFlight = chain.execute(agentContext, () => this.executeAgentLoopStreaming(systemPrompt, memoryMessages, controller, encoder, callbacks, textPartId, toolContext, context, resolvedModelString, languageModel, transport.headers, transport.providerOptions, maxOutputTokensOverride, streamAbortSignal, requestedModel));
|
|
248
|
+
const response = await inFlight;
|
|
230
249
|
throwIfAborted(streamAbortSignal);
|
|
231
250
|
callbacks?.onFinish?.(response);
|
|
232
251
|
throwIfAborted(streamAbortSignal);
|
|
@@ -251,7 +270,19 @@ export class AgentRuntime {
|
|
|
251
270
|
}
|
|
252
271
|
},
|
|
253
272
|
cancel(reason) {
|
|
254
|
-
|
|
273
|
+
// The client disconnected (e.g. the Chat Stop button). Treat this as a
|
|
274
|
+
// clean stop: detach a no-op handler from the in-flight loop so the
|
|
275
|
+
// AbortError it throws when we abort the shared signal cannot surface as
|
|
276
|
+
// an unhandled rejection, then abort. Guard the abort itself so a
|
|
277
|
+
// synchronous signal-abort rejection can never escape here (#2334).
|
|
278
|
+
inFlight?.catch(() => { });
|
|
279
|
+
try {
|
|
280
|
+
streamAbortController.abort(reason);
|
|
281
|
+
}
|
|
282
|
+
catch {
|
|
283
|
+
// Aborting an already-aborted controller, or a synchronous reject
|
|
284
|
+
// from a signal consumer, is a no-op for cancellation purposes.
|
|
285
|
+
}
|
|
255
286
|
},
|
|
256
287
|
});
|
|
257
288
|
}
|
|
@@ -267,7 +298,7 @@ export class AgentRuntime {
|
|
|
267
298
|
const toolCalls = [];
|
|
268
299
|
const currentMessages = [...messages];
|
|
269
300
|
const totalUsage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
|
|
270
|
-
// Local models can't reliably do function calling
|
|
301
|
+
// Local models can't reliably do function calling, so skip tools gracefully.
|
|
271
302
|
const isLocal = isLocalModelRuntime(languageModel);
|
|
272
303
|
if (isLocal && this.config.tools) {
|
|
273
304
|
warnLocalToolSkipping(this.id, effectiveModel);
|
|
@@ -487,7 +518,7 @@ export class AgentRuntime {
|
|
|
487
518
|
const toolCalls = [];
|
|
488
519
|
const currentMessages = [...messages];
|
|
489
520
|
const totalUsage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
|
|
490
|
-
// Local models can't reliably do function calling
|
|
521
|
+
// Local models can't reliably do function calling, so skip tools gracefully.
|
|
491
522
|
const isLocalStreaming = isLocalModelRuntime(languageModel);
|
|
492
523
|
if (isLocalStreaming && this.config.tools) {
|
|
493
524
|
warnLocalToolSkipping(this.id, effectiveModel);
|
|
@@ -642,13 +673,13 @@ export class AgentRuntime {
|
|
|
642
673
|
if (isRecoverablePlaceholderToolCall(tc)) {
|
|
643
674
|
// Provisional empty-object placeholder that never finalized. The
|
|
644
675
|
// model never committed arguments, so we neither execute it nor
|
|
645
|
-
// surface a stream-termination error
|
|
676
|
+
// surface a stream-termination error, so the loop continues and the
|
|
646
677
|
// next model call recovers the real tool call.
|
|
647
678
|
continue;
|
|
648
679
|
}
|
|
649
680
|
if (isStreamedToolCallIncomplete(tc)) {
|
|
650
681
|
// Stream ended before the provider finalized this tool call. We
|
|
651
|
-
// cannot execute it
|
|
682
|
+
// cannot execute it, so record a distinct stream-termination error
|
|
652
683
|
// (not a tool-argument parse error) so the parent step and any
|
|
653
684
|
// upstream orchestrator (e.g. the child-fork watchdog) see a
|
|
654
685
|
// completed step with a clearly-labelled failure and can recover.
|
|
@@ -830,7 +861,13 @@ export class AgentRuntime {
|
|
|
830
861
|
maxOutputTokensOverride > 0) {
|
|
831
862
|
return Math.floor(maxOutputTokensOverride);
|
|
832
863
|
}
|
|
833
|
-
|
|
864
|
+
// A disabled memory config contributes nothing, exactly like omitting
|
|
865
|
+
// `memory`, so its maxTokens (a conversation-window size) must not cap
|
|
866
|
+
// model output.
|
|
867
|
+
const memoryMaxTokens = this.config.memory?.enabled === false
|
|
868
|
+
? undefined
|
|
869
|
+
: this.config.memory?.maxTokens;
|
|
870
|
+
return memoryMaxTokens ??
|
|
834
871
|
(modelString ? getModelMaxOutputTokens(modelString) : undefined) ??
|
|
835
872
|
DEFAULT_MAX_TOKENS;
|
|
836
873
|
}
|
|
@@ -5,6 +5,7 @@ export declare const getMemoryConfigSchema: () => import("../../internal-agents/
|
|
|
5
5
|
type: import("../../internal-agents/schema.js").Schema<"redis" | "buffer" | "conversation" | "summary">;
|
|
6
6
|
maxTokens: import("../../internal-agents/schema.js").Schema<number | undefined>;
|
|
7
7
|
maxMessages: import("../../internal-agents/schema.js").Schema<number | undefined>;
|
|
8
|
+
enabled: import("../../internal-agents/schema.js").Schema<boolean | undefined>;
|
|
8
9
|
}>>;
|
|
9
10
|
export declare const getEdgeConfigSchema: () => import("../../internal-agents/schema.js").Schema<import("../../extensions/schema/schema-validator.js").InferShape<{
|
|
10
11
|
enabled: import("../../internal-agents/schema.js").Schema<boolean>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.schema.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/schemas/agent.schema.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAmB,MAAM,kCAAkC,CAAC;AAErF,eAAO,MAAM,sBAAsB,qGAElC,CAAC;AAEF,eAAO,MAAM,oBAAoB,sIAWhC,CAAC;AAEF,eAAO,MAAM,qBAAqB
|
|
1
|
+
{"version":3,"file":"agent.schema.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/schemas/agent.schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,6 +12,9 @@ export const getMemoryConfigSchema = defineSchema((v) => v.object({
|
|
|
12
12
|
type: v.enum(["conversation", "buffer", "summary", "redis"]),
|
|
13
13
|
maxTokens: v.number().int().positive().optional(),
|
|
14
14
|
maxMessages: v.number().int().positive().optional(),
|
|
15
|
+
// Persist history across calls on the agent instance. Defaults to true when
|
|
16
|
+
// a memory config is provided; set false to keep every call isolated.
|
|
17
|
+
enabled: v.boolean().optional(),
|
|
15
18
|
}));
|
|
16
19
|
export const getEdgeConfigSchema = defineSchema((v) => v.object({
|
|
17
20
|
enabled: v.boolean(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-execution-data-event-bridge.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/streaming/tool-execution-data-event-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAElE,mEAAmE;AACnE,MAAM,MAAM,+BAA+B,GAAG,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;AAEtF,iEAAiE;AACjE,MAAM,MAAM,uCAAuC,GAAG;IACpD,UAAU,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACvC,gBAAgB,EAAE,CAAC,OAAO,EAAE,+BAA+B,KAAK,IAAI,CAAC;CACtE,CAAC;AA6BF,sDAAsD;AACtD,wBAAgB,wCAAwC,CACtD,KAAK,EAAE,uCAAuC,GAC7C,cAAc,CAAC,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"tool-execution-data-event-bridge.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/streaming/tool-execution-data-event-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAElE,mEAAmE;AACnE,MAAM,MAAM,+BAA+B,GAAG,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;AAEtF,iEAAiE;AACjE,MAAM,MAAM,uCAAuC,GAAG;IACpD,UAAU,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACvC,gBAAgB,EAAE,CAAC,OAAO,EAAE,+BAA+B,KAAK,IAAI,CAAC;CACtE,CAAC;AA6BF,sDAAsD;AACtD,wBAAgB,wCAAwC,CACtD,KAAK,EAAE,uCAAuC,GAC7C,cAAc,CAAC,UAAU,CAAC,CAwD5B"}
|
|
@@ -57,7 +57,17 @@ export function createToolExecutionDataEventBridgeStream(input) {
|
|
|
57
57
|
})();
|
|
58
58
|
},
|
|
59
59
|
async cancel(reason) {
|
|
60
|
-
|
|
60
|
+
// Cancellation is best-effort teardown (the client disconnected / hit
|
|
61
|
+
// Stop). Forwarding the cancel to the base reader can reject — e.g. the
|
|
62
|
+
// upstream agent runtime aborts an in-flight signal whose rejection
|
|
63
|
+
// surfaces through the cancel chain. Swallow it so it does not escape as
|
|
64
|
+
// an unhandled rejection, which is fatal under Deno (#2334).
|
|
65
|
+
try {
|
|
66
|
+
await baseReader?.cancel(reason);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Stream is being torn down; a failed cancel is a clean stop here.
|
|
70
|
+
}
|
|
61
71
|
},
|
|
62
72
|
});
|
|
63
73
|
}
|
package/esm/src/agent/types.d.ts
CHANGED
|
@@ -117,6 +117,14 @@ export interface AgentConfig {
|
|
|
117
117
|
/** Sampling temperature for model generation. Defaults to 0. */
|
|
118
118
|
temperature?: number;
|
|
119
119
|
streaming?: boolean;
|
|
120
|
+
/**
|
|
121
|
+
* Conversation memory persisted across `stream()` / `generate()` calls on this
|
|
122
|
+
* instance. Omit for the stateless default: every call runs in isolation,
|
|
123
|
+
* which keeps concurrent fan-out on a shared instance correct. When set, the
|
|
124
|
+
* instance accumulates one shared conversation, so reuse it sequentially, not
|
|
125
|
+
* across concurrent independent runs (use a separate instance per run for
|
|
126
|
+
* that). Set `enabled: false` to force the stateless behavior explicitly.
|
|
127
|
+
*/
|
|
120
128
|
memory?: MemoryConfig;
|
|
121
129
|
middleware?: AgentMiddleware[];
|
|
122
130
|
edge?: EdgeConfig;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/src/agent/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/src/agent/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_data.d.ts","sourceRoot":"","sources":["../../../src/src/integrations/_data.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,eAAO,MAAM,UAAU,EAAE,iBAAiB,
|
|
1
|
+
{"version":3,"file":"_data.d.ts","sourceRoot":"","sources":["../../../src/src/integrations/_data.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,eAAO,MAAM,UAAU,EAAE,iBAAiB,EA26XzC,CAAC;AAEF,eAAO,MAAM,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA+ExC,CAAC"}
|
|
@@ -1644,6 +1644,7 @@ export const connectors = [
|
|
|
1644
1644
|
"scopes": [
|
|
1645
1645
|
"https://www.googleapis.com/auth/documents.readonly",
|
|
1646
1646
|
"https://www.googleapis.com/auth/documents",
|
|
1647
|
+
"https://www.googleapis.com/auth/docs",
|
|
1647
1648
|
"https://www.googleapis.com/auth/drive.readonly",
|
|
1648
1649
|
],
|
|
1649
1650
|
"requiredApis": [{
|
|
@@ -1820,10 +1821,7 @@ export const connectors = [
|
|
|
1820
1821
|
"provider": "google",
|
|
1821
1822
|
"authorizationUrl": "https://accounts.google.com/o/oauth2/v2/auth",
|
|
1822
1823
|
"tokenUrl": "https://oauth2.googleapis.com/token",
|
|
1823
|
-
"scopes": [
|
|
1824
|
-
"https://www.googleapis.com/auth/drive.readonly",
|
|
1825
|
-
"https://www.googleapis.com/auth/drive.file",
|
|
1826
|
-
],
|
|
1824
|
+
"scopes": ["https://www.googleapis.com/auth/drive"],
|
|
1827
1825
|
"requiredApis": [{
|
|
1828
1826
|
"name": "Google Drive API",
|
|
1829
1827
|
"enableUrl": "https://console.cloud.google.com/apis/library/drive.googleapis.com",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../../../src/src/platform/compat/process/env.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,MAAM,OAAO,CAAC;IACxB,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5C,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACtC,CAAC;AAoBF,oDAAoD;AACpD,wBAAgB,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmB5C;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../../../src/src/platform/compat/process/env.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,MAAM,OAAO,CAAC;IACxB,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5C,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACtC,CAAC;AAoBF,oDAAoD;AACpD,wBAAgB,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmB5C;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAoB1D;AAqCD,kEAAkE;AAClE,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAWtD;AAKD,MAAM,WAAW,iBAAiB;IAChC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAUD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAC9D,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;AAOpE,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAC9D,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;AAUpE,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,EACX,QAAQ,UAAQ,EAChB,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAmBT;AAED,gBAAgB;AAChB,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAgBvD;AAED,6CAA6C;AAC7C,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAgB3C;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,iBAAiB,GAAG,IAAI,CAS/D"}
|
|
@@ -41,8 +41,19 @@ export function getHostEnv(key) {
|
|
|
41
41
|
if (overlayResult.hasValue) {
|
|
42
42
|
return overlayResult.value;
|
|
43
43
|
}
|
|
44
|
-
if (IS_DENO)
|
|
45
|
-
|
|
44
|
+
if (IS_DENO) {
|
|
45
|
+
try {
|
|
46
|
+
return dntShim.Deno.env.get(key);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// Under a tightened env permission allowlist (project isolation workers),
|
|
50
|
+
// reading a non-allowlisted variable throws NotCapable. Treat it as absent
|
|
51
|
+
// to match the prior `env: true` behavior where reads never threw, so
|
|
52
|
+
// optional-variable lookups degrade to undefined instead of crashing the
|
|
53
|
+
// request.
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
46
57
|
if (runtimeProcess)
|
|
47
58
|
return runtimeProcess.env[key];
|
|
48
59
|
return undefined;
|
|
@@ -11,5 +11,25 @@ export declare function isInternalEgressOverrideEnabled(value: string | undefine
|
|
|
11
11
|
export declare function isInternalEgressIp(address: string): boolean;
|
|
12
12
|
export declare function assertWorkerEgressAllowed(target: string | URL | Request, options?: WorkerEgressGuardOptions): Promise<void>;
|
|
13
13
|
export declare function assertWorkerHostEgressAllowed(hostname: string, options?: WorkerEgressGuardOptions): Promise<void>;
|
|
14
|
+
/** Dependencies for {@link guardedEgressFetch} (injectable for tests). */
|
|
15
|
+
export interface GuardedEgressFetchDeps {
|
|
16
|
+
/** Underlying fetch implementation (defaults to the global `fetch`). */
|
|
17
|
+
fetchImpl?: typeof fetch;
|
|
18
|
+
/** Egress options applied to the initial URL and every redirect hop. */
|
|
19
|
+
options?: WorkerEgressGuardOptions;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Egress-checked fetch that re-validates EVERY redirect hop.
|
|
23
|
+
*
|
|
24
|
+
* The platform `fetch` follows 3xx redirects transparently, so checking only the
|
|
25
|
+
* initial URL lets a public host redirect to an internal address (loopback,
|
|
26
|
+
* RFC1918, link-local, cloud metadata) that the guard never sees. This forces
|
|
27
|
+
* `redirect: "manual"` on the underlying fetch and re-runs the egress check on
|
|
28
|
+
* each `Location` before following it. The caller's redirect intent is honored:
|
|
29
|
+
* `manual` returns the redirect unfollowed, `error` throws, `follow` (default)
|
|
30
|
+
* follows manually after re-checking. Credential headers are stripped on a
|
|
31
|
+
* cross-origin hop, matching the platform fetch the guard wraps.
|
|
32
|
+
*/
|
|
33
|
+
export declare function guardedEgressFetch(input: Parameters<typeof fetch>[0], init?: Parameters<typeof fetch>[1], deps?: GuardedEgressFetchDeps): Promise<Response>;
|
|
14
34
|
export declare function installWorkerEgressGuard(options?: WorkerEgressGuardOptions): void;
|
|
15
35
|
//# sourceMappingURL=worker-egress-guard.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-egress-guard.d.ts","sourceRoot":"","sources":["../../../../src/src/security/sandbox/worker-egress-guard.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,mCAAmC,2CAA2C,CAAC;AAE5F,qBAAa,wBAAyB,SAAQ,KAAK;IACxC,IAAI,SAA8B;CAC5C;AAED,MAAM,MAAM,iBAAiB,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;AAExE,MAAM,WAAW,wBAAwB;IACvC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,WAAW,CAAC,EAAE,iBAAiB,CAAC;CACjC;AAWD,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAWlF;AAuDD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAK3D;AA4CD,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,EAC9B,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,wBAAsB,6BAA6B,CACjD,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,IAAI,CAAC,CA0Bf;
|
|
1
|
+
{"version":3,"file":"worker-egress-guard.d.ts","sourceRoot":"","sources":["../../../../src/src/security/sandbox/worker-egress-guard.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,mCAAmC,2CAA2C,CAAC;AAE5F,qBAAa,wBAAyB,SAAQ,KAAK;IACxC,IAAI,SAA8B;CAC5C;AAED,MAAM,MAAM,iBAAiB,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;AAExE,MAAM,WAAW,wBAAwB;IACvC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,WAAW,CAAC,EAAE,iBAAiB,CAAC;CACjC;AAWD,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAWlF;AAuDD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAK3D;AA4CD,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,EAC9B,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,wBAAsB,6BAA6B,CACjD,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,IAAI,CAAC,CA0Bf;AAmBD,0EAA0E;AAC1E,MAAM,WAAW,sBAAsB;IACrC,wEAAwE;IACxE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,wEAAwE;IACxE,OAAO,CAAC,EAAE,wBAAwB,CAAC;CACpC;AASD;;;;;;;;;;;GAWG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,EAClC,IAAI,CAAC,EAAE,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,EAClC,IAAI,GAAE,sBAA2B,GAChC,OAAO,CAAC,QAAQ,CAAC,CAqGnB;AAED,wBAAgB,wBAAwB,CAAC,OAAO,GAAE,wBAA6B,GAAG,IAAI,CAmDrF"}
|
|
@@ -160,6 +160,115 @@ function getAllowInternalEgress() {
|
|
|
160
160
|
return false;
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
|
+
const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
|
|
164
|
+
const MAX_EGRESS_REDIRECTS = 20;
|
|
165
|
+
/** A request body that can be safely replayed across a body-preserving redirect. */
|
|
166
|
+
function isReplayableBody(body) {
|
|
167
|
+
return body == null || typeof body === "string" ||
|
|
168
|
+
body instanceof Uint8Array || body instanceof ArrayBuffer ||
|
|
169
|
+
body instanceof URLSearchParams;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Egress-checked fetch that re-validates EVERY redirect hop.
|
|
173
|
+
*
|
|
174
|
+
* The platform `fetch` follows 3xx redirects transparently, so checking only the
|
|
175
|
+
* initial URL lets a public host redirect to an internal address (loopback,
|
|
176
|
+
* RFC1918, link-local, cloud metadata) that the guard never sees. This forces
|
|
177
|
+
* `redirect: "manual"` on the underlying fetch and re-runs the egress check on
|
|
178
|
+
* each `Location` before following it. The caller's redirect intent is honored:
|
|
179
|
+
* `manual` returns the redirect unfollowed, `error` throws, `follow` (default)
|
|
180
|
+
* follows manually after re-checking. Credential headers are stripped on a
|
|
181
|
+
* cross-origin hop, matching the platform fetch the guard wraps.
|
|
182
|
+
*/
|
|
183
|
+
export async function guardedEgressFetch(input, init, deps = {}) {
|
|
184
|
+
const doFetch = deps.fetchImpl ?? fetch;
|
|
185
|
+
const options = deps.options ?? {};
|
|
186
|
+
const requestedRedirect = init?.redirect ??
|
|
187
|
+
(input instanceof Request ? input.redirect : "follow");
|
|
188
|
+
let url = input instanceof Request
|
|
189
|
+
? input.url
|
|
190
|
+
: input instanceof URL
|
|
191
|
+
? input.href
|
|
192
|
+
: String(input);
|
|
193
|
+
let method = (init?.method ?? (input instanceof Request ? input.method : "GET")).toUpperCase();
|
|
194
|
+
const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : undefined));
|
|
195
|
+
let body;
|
|
196
|
+
if (init?.body != null) {
|
|
197
|
+
body = init.body;
|
|
198
|
+
}
|
|
199
|
+
else if (input instanceof Request && input.body) {
|
|
200
|
+
body = new Uint8Array(await input.arrayBuffer());
|
|
201
|
+
}
|
|
202
|
+
// Preserve request-level options (notably `signal`, so aborts keep working)
|
|
203
|
+
// that would otherwise be dropped when the caller passes a Request object
|
|
204
|
+
// rather than an init bag, and that must persist across every redirect hop.
|
|
205
|
+
const reqInput = input instanceof Request ? input : undefined;
|
|
206
|
+
const carryInit = {
|
|
207
|
+
signal: init?.signal ?? reqInput?.signal,
|
|
208
|
+
credentials: init?.credentials ?? reqInput?.credentials,
|
|
209
|
+
cache: init?.cache ?? reqInput?.cache,
|
|
210
|
+
mode: init?.mode ?? reqInput?.mode,
|
|
211
|
+
referrer: init?.referrer ?? reqInput?.referrer,
|
|
212
|
+
referrerPolicy: init?.referrerPolicy ?? reqInput?.referrerPolicy,
|
|
213
|
+
keepalive: init?.keepalive ?? reqInput?.keepalive,
|
|
214
|
+
};
|
|
215
|
+
for (let hop = 0;; hop++) {
|
|
216
|
+
await assertWorkerEgressAllowed(url, options);
|
|
217
|
+
const response = await doFetch(url, {
|
|
218
|
+
...init,
|
|
219
|
+
...carryInit,
|
|
220
|
+
method,
|
|
221
|
+
headers,
|
|
222
|
+
body,
|
|
223
|
+
redirect: "manual",
|
|
224
|
+
});
|
|
225
|
+
if (!REDIRECT_STATUSES.has(response.status))
|
|
226
|
+
return response;
|
|
227
|
+
const location = response.headers.get("location");
|
|
228
|
+
if (!location)
|
|
229
|
+
return response;
|
|
230
|
+
if (requestedRedirect === "manual")
|
|
231
|
+
return response;
|
|
232
|
+
if (requestedRedirect === "error") {
|
|
233
|
+
throw new WorkerEgressBlockedError("Worker egress: unexpected redirect with redirect mode 'error'");
|
|
234
|
+
}
|
|
235
|
+
if (hop >= MAX_EGRESS_REDIRECTS) {
|
|
236
|
+
throw new WorkerEgressBlockedError("Worker network egress blocked: exceeded maximum redirect count");
|
|
237
|
+
}
|
|
238
|
+
const nextUrl = new URL(location, url);
|
|
239
|
+
// Only follow redirects to http(s). The platform fetch treats a redirect to
|
|
240
|
+
// any other scheme as a network error; following e.g. file:// here would let
|
|
241
|
+
// an attacker-controlled redirect turn a network fetch into a local file
|
|
242
|
+
// read, since assertWorkerEgressAllowed no-ops for hostless (non-network)
|
|
243
|
+
// URLs.
|
|
244
|
+
if (nextUrl.protocol !== "http:" && nextUrl.protocol !== "https:") {
|
|
245
|
+
throw new WorkerEgressBlockedError(`Worker network egress blocked: redirect to non-http(s) scheme ${nextUrl.protocol}`);
|
|
246
|
+
}
|
|
247
|
+
// Cross-origin redirect: strip credential-bearing headers, matching the
|
|
248
|
+
// platform fetch this guard replaces, so a redirect target cannot receive
|
|
249
|
+
// the caller's Authorization/Cookie.
|
|
250
|
+
if (nextUrl.origin !== new URL(url).origin) {
|
|
251
|
+
headers.delete("authorization");
|
|
252
|
+
headers.delete("cookie");
|
|
253
|
+
headers.delete("proxy-authorization");
|
|
254
|
+
}
|
|
255
|
+
url = nextUrl.href;
|
|
256
|
+
// Standard fetch redirect method/body rules: 303, and 301/302 for a
|
|
257
|
+
// non-GET/HEAD method, downgrade to GET and drop the body; 307/308 preserve.
|
|
258
|
+
const downgrades = response.status === 303 ||
|
|
259
|
+
((response.status === 301 || response.status === 302) &&
|
|
260
|
+
method !== "GET" && method !== "HEAD");
|
|
261
|
+
if (downgrades) {
|
|
262
|
+
method = "GET";
|
|
263
|
+
body = undefined;
|
|
264
|
+
headers.delete("content-length");
|
|
265
|
+
headers.delete("content-type");
|
|
266
|
+
}
|
|
267
|
+
else if (!isReplayableBody(body)) {
|
|
268
|
+
throw new WorkerEgressBlockedError("Worker network egress blocked: cannot safely follow a body-preserving redirect");
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
163
272
|
export function installWorkerEgressGuard(options = {}) {
|
|
164
273
|
const globalRecord = dntShim.dntGlobalThis;
|
|
165
274
|
if (globalRecord[guardInstalled])
|
|
@@ -170,8 +279,12 @@ export function installWorkerEgressGuard(options = {}) {
|
|
|
170
279
|
};
|
|
171
280
|
const originalFetch = globalThis.fetch.bind(dntShim.dntGlobalThis);
|
|
172
281
|
const fetchWrapper = async (input, init) => {
|
|
173
|
-
|
|
174
|
-
|
|
282
|
+
// guardedEgressFetch checks the initial URL and re-checks every redirect hop,
|
|
283
|
+
// so a public host cannot redirect into an internal address.
|
|
284
|
+
return await guardedEgressFetch(input, init, {
|
|
285
|
+
fetchImpl: originalFetch,
|
|
286
|
+
options: baseOptions,
|
|
287
|
+
});
|
|
175
288
|
};
|
|
176
289
|
Object.defineProperty(fetchWrapper, guardedFetch, { value: true });
|
|
177
290
|
globalThis.fetch = fetchWrapper;
|
|
@@ -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;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;
|
|
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;AAK9D,eAAO,MAAM,kBAAkB,wBAE7B,CAAC;AA6IH,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;AAuBD,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,CA0ElE;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,EACnB,YAAY,SAAwB,GACnC,IAAI,CAgBN;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,CA+J5B"}
|
|
@@ -18,9 +18,26 @@ import { ensureMdxModuleDependencies } from "../module-fetcher/dependency-recove
|
|
|
18
18
|
export { getLocalFs } from "./local-fs.js";
|
|
19
19
|
import { getLocalFs } from "./local-fs.js";
|
|
20
20
|
const MAX_VERIFIED_MODULE_DEPS = 2_000;
|
|
21
|
+
const MAX_MODULE_PATH_CACHE_ENTRIES = 500;
|
|
21
22
|
export const verifiedModuleDeps = new LRUCache({
|
|
22
23
|
maxEntries: MAX_VERIFIED_MODULE_DEPS,
|
|
23
24
|
});
|
|
25
|
+
class BoundedModulePathCache extends Map {
|
|
26
|
+
maxEntries;
|
|
27
|
+
constructor(maxEntries) {
|
|
28
|
+
super();
|
|
29
|
+
this.maxEntries = maxEntries;
|
|
30
|
+
}
|
|
31
|
+
set(key, value) {
|
|
32
|
+
if (!this.has(key) && this.size >= this.maxEntries) {
|
|
33
|
+
const oldestKey = this.keys().next().value;
|
|
34
|
+
if (oldestKey !== undefined) {
|
|
35
|
+
this.delete(oldestKey);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return super.set(key, value);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
24
41
|
/**
|
|
25
42
|
* Check if cached code has file:// paths from a different environment.
|
|
26
43
|
* Checks both HTTP bundle paths and MDX ESM cache paths.
|
|
@@ -125,6 +142,7 @@ function getModulePathCacheEntryCount() {
|
|
|
125
142
|
registerCache("mdx-esm-path-caches", () => ({
|
|
126
143
|
name: "mdx-esm-path-caches",
|
|
127
144
|
entries: getModulePathCacheEntryCount(),
|
|
145
|
+
maxEntries: MAX_MODULE_PATH_CACHE_ENTRIES * Math.max(1, modulePathCaches.size),
|
|
128
146
|
cacheDirs: modulePathCaches.size,
|
|
129
147
|
}));
|
|
130
148
|
registerCache("mdx-esm-verified-deps", () => ({
|
|
@@ -136,7 +154,7 @@ export async function getModulePathCache(cacheDir) {
|
|
|
136
154
|
const existing = modulePathCaches.get(cacheDir);
|
|
137
155
|
if (existing && modulePathCacheLoaded.has(cacheDir))
|
|
138
156
|
return existing;
|
|
139
|
-
const cache = existing ?? new
|
|
157
|
+
const cache = existing ?? new BoundedModulePathCache(MAX_MODULE_PATH_CACHE_ENTRIES);
|
|
140
158
|
modulePathCaches.set(cacheDir, cache);
|
|
141
159
|
const indexPath = join(cacheDir, "_index.json");
|
|
142
160
|
try {
|