veryfront 0.1.217 → 0.1.219

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/esm/cli/commands/init/config-generator.d.ts +13 -1
  2. package/esm/cli/commands/init/config-generator.d.ts.map +1 -1
  3. package/esm/cli/commands/init/config-generator.js +15 -1
  4. package/esm/cli/commands/init/init-command.d.ts.map +1 -1
  5. package/esm/cli/commands/init/init-command.js +9 -2
  6. package/esm/deno.d.ts +1 -3
  7. package/esm/deno.js +6 -5
  8. package/esm/src/agent/ag-ui-detached-start.d.ts +84 -0
  9. package/esm/src/agent/ag-ui-detached-start.d.ts.map +1 -0
  10. package/esm/src/agent/ag-ui-detached-start.js +273 -0
  11. package/esm/src/agent/index.d.ts +1 -0
  12. package/esm/src/agent/index.d.ts.map +1 -1
  13. package/esm/src/agent/index.js +1 -0
  14. package/esm/src/extensions/interfaces/auth-provider.d.ts +30 -3
  15. package/esm/src/extensions/interfaces/auth-provider.d.ts.map +1 -1
  16. package/esm/src/extensions/interfaces/index.d.ts +2 -1
  17. package/esm/src/extensions/interfaces/index.d.ts.map +1 -1
  18. package/esm/src/extensions/interfaces/token-cache-store.d.ts +56 -0
  19. package/esm/src/extensions/interfaces/token-cache-store.d.ts.map +1 -0
  20. package/esm/src/extensions/interfaces/token-cache-store.js +12 -0
  21. package/esm/src/extensions/recommendations.d.ts.map +1 -1
  22. package/esm/src/extensions/recommendations.js +1 -0
  23. package/esm/src/integrations/_data.js +1 -1
  24. package/esm/src/integrations/schema.d.ts +1 -0
  25. package/esm/src/integrations/schema.d.ts.map +1 -1
  26. package/esm/src/integrations/schema.js +8 -0
  27. package/esm/src/proxy/cache/index.d.ts +1 -1
  28. package/esm/src/proxy/cache/index.d.ts.map +1 -1
  29. package/esm/src/proxy/cache/index.js +25 -15
  30. package/esm/src/proxy/cache/tracing-cache.d.ts +31 -0
  31. package/esm/src/proxy/cache/tracing-cache.d.ts.map +1 -0
  32. package/esm/src/proxy/cache/tracing-cache.js +44 -0
  33. package/esm/src/proxy/cache/types.d.ts +1 -1
  34. package/esm/src/proxy/cache/types.js +1 -1
  35. package/esm/src/proxy/handler.d.ts +7 -0
  36. package/esm/src/proxy/handler.d.ts.map +1 -1
  37. package/esm/src/proxy/handler.js +50 -29
  38. package/esm/src/server/runtime-handler/request-tracker.d.ts.map +1 -1
  39. package/esm/src/server/runtime-handler/request-tracker.js +5 -6
  40. package/esm/src/server/runtime-handler/request-utils.d.ts.map +1 -1
  41. package/esm/src/server/runtime-handler/request-utils.js +1 -0
  42. package/esm/src/utils/version-constant.d.ts +1 -1
  43. package/esm/src/utils/version-constant.js +1 -1
  44. package/package.json +66 -35
  45. package/src/cli/commands/init/config-generator.ts +33 -0
  46. package/src/cli/commands/init/init-command.ts +9 -2
  47. package/src/deno.js +6 -5
  48. package/src/src/agent/ag-ui-detached-start.ts +397 -0
  49. package/src/src/agent/index.ts +8 -0
  50. package/src/src/extensions/interfaces/auth-provider.ts +35 -3
  51. package/src/src/extensions/interfaces/index.ts +10 -1
  52. package/src/src/extensions/interfaces/token-cache-store.ts +58 -0
  53. package/src/src/extensions/recommendations.ts +1 -0
  54. package/src/src/integrations/_data.ts +1 -1
  55. package/src/src/integrations/schema.ts +8 -0
  56. package/src/src/proxy/cache/index.ts +27 -15
  57. package/src/src/proxy/cache/tracing-cache.ts +77 -0
  58. package/src/src/proxy/cache/types.ts +1 -1
  59. package/src/src/proxy/handler.ts +57 -31
  60. package/src/src/server/runtime-handler/request-tracker.ts +5 -7
  61. package/src/src/server/runtime-handler/request-utils.ts +1 -0
  62. package/src/src/utils/version-constant.ts +1 -1
  63. package/esm/src/proxy/cache/redis-cache.d.ts +0 -25
  64. package/esm/src/proxy/cache/redis-cache.d.ts.map +0 -1
  65. package/esm/src/proxy/cache/redis-cache.js +0 -219
  66. package/src/src/proxy/cache/redis-cache.ts +0 -255
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Contract interface for OAuth-token-style cache stores used by the proxy.
3
+ *
4
+ * This contract is richer than the generic `CacheStore` — it adds scan-by-prefix,
5
+ * bulk read, and usage statistics primitives that the proxy's token cache needs.
6
+ * Simpler key-value consumers should use `CacheStore` instead.
7
+ *
8
+ * Default implementation: `@veryfront/ext-redis`.
9
+ *
10
+ * @module extensions/interfaces/token-cache-store
11
+ */
12
+ /**
13
+ * A cache entry stored by `TokenCacheStore`.
14
+ *
15
+ * The proxy persists OAuth tokens keyed by request metadata; this entry shape
16
+ * mirrors what the proxy has historically stored.
17
+ */
18
+ export interface TokenCacheEntry {
19
+ token: string;
20
+ /** Unix timestamp in milliseconds. */
21
+ expiresAt: number;
22
+ scope: "preview" | "production";
23
+ projectSlug?: string;
24
+ }
25
+ /**
26
+ * Aggregate usage statistics for a `TokenCacheStore`.
27
+ */
28
+ export interface TokenCacheStats {
29
+ hits: number;
30
+ misses: number;
31
+ size: number;
32
+ type: "memory" | "redis";
33
+ }
34
+ /**
35
+ * TokenCacheStore contract interface.
36
+ *
37
+ * Implementations provide TTL-aware token caching, plus scan and stats
38
+ * primitives that generic key-value caches do not require.
39
+ */
40
+ export interface TokenCacheStore {
41
+ /** Retrieve a cached entry by key. Returns `null` on miss or expiry. */
42
+ get(key: string): Promise<TokenCacheEntry | null>;
43
+ /** Store an entry. TTL is derived from `entry.expiresAt`. */
44
+ set(key: string, entry: TokenCacheEntry): Promise<void>;
45
+ /** Delete a cached entry. No-op if the key does not exist. */
46
+ delete(key: string): Promise<void>;
47
+ /** Remove every entry owned by this store. */
48
+ clear(): Promise<void>;
49
+ /** Check whether a non-expired entry exists for the given key. */
50
+ has(key: string): Promise<boolean>;
51
+ /** Return current hit/miss/size statistics. */
52
+ stats(): Promise<TokenCacheStats>;
53
+ /** Close connections and release resources. */
54
+ close(): Promise<void>;
55
+ }
56
+ //# sourceMappingURL=token-cache-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-cache-store.d.ts","sourceRoot":"","sources":["../../../../src/src/extensions/interfaces/token-cache-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,SAAS,GAAG,YAAY,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;CAC1B;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IAClD,6DAA6D;IAC7D,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,8DAA8D;IAC9D,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,8CAA8C;IAC9C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,kEAAkE;IAClE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnC,+CAA+C;IAC/C,KAAK,IAAI,OAAO,CAAC,eAAe,CAAC,CAAC;IAClC,+CAA+C;IAC/C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Contract interface for OAuth-token-style cache stores used by the proxy.
3
+ *
4
+ * This contract is richer than the generic `CacheStore` — it adds scan-by-prefix,
5
+ * bulk read, and usage statistics primitives that the proxy's token cache needs.
6
+ * Simpler key-value consumers should use `CacheStore` instead.
7
+ *
8
+ * Default implementation: `@veryfront/ext-redis`.
9
+ *
10
+ * @module extensions/interfaces/token-cache-store
11
+ */
12
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"recommendations.d.ts","sourceRoot":"","sources":["../../../src/src/extensions/recommendations.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAiBH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE1E"}
1
+ {"version":3,"file":"recommendations.d.ts","sourceRoot":"","sources":["../../../src/src/extensions/recommendations.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkBH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE1E"}
@@ -6,6 +6,7 @@
6
6
  const recommendations = new Map([
7
7
  ["Bundler", "@veryfront/ext-esbuild"],
8
8
  ["CacheStore", "@veryfront/ext-redis"],
9
+ ["TokenCacheStore", "@veryfront/ext-redis"],
9
10
  ["CSSProcessor", "@veryfront/ext-tailwind"],
10
11
  ["ContentTransformer", "@veryfront/ext-mdx"],
11
12
  ["DatabaseClient", "@veryfront/ext-postgres"],
@@ -24,7 +24,7 @@ export const connectors = [
24
24
  { "name": "mailchimp", "displayName": "Mailchimp", "icon": "mailchimp.svg", "description": "Manage email campaigns, lists, and subscribers in Mailchimp", "auth": { "type": "oauth2", "provider": "mailchimp", "authorizationUrl": "https://login.mailchimp.com/oauth2/authorize", "tokenUrl": "https://login.mailchimp.com/oauth2/token", "scopes": [], "requiredApis": [{ "name": "Mailchimp API", "enableUrl": "https://admin.mailchimp.com/account/oauth2/" }] }, "envVars": [{ "name": "MAILCHIMP_CLIENT_ID", "description": "Mailchimp OAuth Client ID", "required": true, "sensitive": false, "docsUrl": "https://mailchimp.com/developer/marketing/guides/access-user-data-oauth-2/" }, { "name": "MAILCHIMP_CLIENT_SECRET", "description": "Mailchimp OAuth Client Secret", "required": true, "sensitive": true, "docsUrl": "https://mailchimp.com/developer/marketing/guides/access-user-data-oauth-2/" }], "tools": [{ "id": "list-campaigns", "name": "List Campaigns", "description": "List all email campaigns in Mailchimp", "requiresWrite": false }, { "id": "get-campaign", "name": "Get Campaign", "description": "Get details of a specific campaign", "requiresWrite": false }, { "id": "list-lists", "name": "List Audience Lists", "description": "List all audience lists (mailing lists) in Mailchimp", "requiresWrite": false }, { "id": "get-list", "name": "Get Audience List", "description": "Get details of a specific audience list", "requiresWrite": false }, { "id": "list-members", "name": "List Members", "description": "List subscribers/members in an audience list", "requiresWrite": false }], "prompts": [{ "id": "campaign-stats", "title": "Show campaign stats", "prompt": "Show me the performance statistics for my recent email campaigns in Mailchimp.", "category": "marketing", "icon": "chart" }, { "id": "list-subscribers", "title": "List subscribers", "prompt": "Show me the subscribers in my main email list with their subscription status.", "category": "marketing", "icon": "users" }], "suggestedWith": ["slack", "notion", "hubspot"] },
25
25
  { "name": "mixpanel", "displayName": "Mixpanel", "icon": "mixpanel.svg", "description": "Track events, analyze funnels, and understand user behavior with Mixpanel analytics", "auth": { "type": "api-key", "requiredApis": [{ "name": "Mixpanel API", "enableUrl": "https://mixpanel.com/settings/project" }], "keyName": "MIXPANEL_PROJECT_TOKEN" }, "envVars": [{ "name": "MIXPANEL_PROJECT_TOKEN", "description": "Mixpanel Project Token for event tracking", "required": true, "sensitive": true, "docsUrl": "https://docs.mixpanel.com/docs/tracking-methods/id-management/authentication" }, { "name": "MIXPANEL_API_SECRET", "description": "Mixpanel API Secret for data export and query operations", "required": true, "sensitive": true, "docsUrl": "https://developer.mixpanel.com/reference/authentication" }, { "name": "MIXPANEL_PROJECT_ID", "description": "Mixpanel Project ID (found in project settings)", "required": true, "sensitive": false, "docsUrl": "https://docs.mixpanel.com/docs/admin/organizations-projects/manage-projects" }], "tools": [{ "id": "track-event", "name": "Track Event", "description": "Track a custom event in Mixpanel with properties", "requiresWrite": true }, { "id": "query-events", "name": "Query Events", "description": "Query and export event data from Mixpanel", "requiresWrite": false }, { "id": "get-funnel", "name": "Get Funnel", "description": "Retrieve funnel analysis data to understand conversion rates", "requiresWrite": false }, { "id": "get-retention", "name": "Get Retention", "description": "Analyze user retention cohorts over time", "requiresWrite": false }, { "id": "list-cohorts", "name": "List Cohorts", "description": "List all user cohorts defined in your Mixpanel project", "requiresWrite": false }], "prompts": [{ "id": "event-analysis", "title": "Event analysis", "prompt": "Show me the most important events tracked in my Mixpanel project over the last 7 days and their trends.", "category": "analytics", "icon": "chart" }, { "id": "funnel-performance", "title": "Funnel performance", "prompt": "Analyze my key conversion funnels and identify where users are dropping off.", "category": "analytics", "icon": "funnel" }, { "id": "retention-insights", "title": "Retention insights", "prompt": "Give me insights about user retention and cohort behavior over the past month.", "category": "analytics", "icon": "users" }], "suggestedWith": ["slack", "analytics", "monitoring"] },
26
26
  { "name": "monday", "displayName": "Monday.com", "icon": "monday.svg", "description": "Manage projects, tasks, and workflows in Monday.com", "auth": { "type": "oauth2", "provider": "monday", "authorizationUrl": "https://auth.monday.com/oauth2/authorize", "tokenUrl": "https://auth.monday.com/oauth2/token", "scopes": ["me:read", "boards:read", "boards:write"], "requiredApis": [{ "name": "Monday.com Developers", "enableUrl": "https://monday.com/developers/apps" }] }, "envVars": [{ "name": "MONDAY_CLIENT_ID", "description": "Monday.com OAuth Client ID", "required": true, "sensitive": false, "docsUrl": "https://developer.monday.com/apps/docs/oauth" }, { "name": "MONDAY_CLIENT_SECRET", "description": "Monday.com OAuth Client Secret", "required": true, "sensitive": true, "docsUrl": "https://developer.monday.com/apps/docs/oauth" }], "tools": [{ "id": "list-boards", "name": "List Boards", "description": "List all boards in the workspace", "requiresWrite": false }, { "id": "list-items", "name": "List Items", "description": "List items in a board", "requiresWrite": false }, { "id": "get-item", "name": "Get Item", "description": "Get details of a specific item", "requiresWrite": false }, { "id": "create-item", "name": "Create Item", "description": "Create a new item in a board", "requiresWrite": true }, { "id": "update-item", "name": "Update Item", "description": "Update an existing item", "requiresWrite": true }], "prompts": [{ "id": "my-items", "title": "Show my items", "prompt": "List all items assigned to me in Monday.com with their status and due dates.", "category": "productivity", "icon": "list" }, { "id": "create-item", "title": "Create an item", "prompt": "Create a new item with a name, status, and assign it to someone.", "category": "productivity", "icon": "plus" }], "suggestedWith": ["slack", "notion", "asana"] },
27
- { "name": "neon", "displayName": "Neon", "icon": "neon.svg", "description": "Manage Neon Postgres projects, branches, and execute database queries", "auth": { "type": "api-key", "requiredApis": [{ "name": "Neon Management API", "enableUrl": "https://console.neon.tech/app/settings/api-keys" }], "tokenName": "API Key", "docsUrl": "https://neon.tech/docs/manage/api-keys" }, "envVars": [{ "name": "NEON_API_KEY", "description": "Neon API Key for Management API access", "required": true, "sensitive": true, "docsUrl": "https://neon.tech/docs/manage/api-keys" }, { "name": "DATABASE_URL", "description": "PostgreSQL connection string for database queries", "required": true, "sensitive": true, "docsUrl": "https://neon.tech/docs/connect/connect-from-any-app" }], "tools": [{ "id": "list-projects", "name": "List Projects", "description": "List all Neon projects in your account", "requiresWrite": false }, { "id": "list-branches", "name": "List Branches", "description": "List all branches for a specific project", "requiresWrite": false }, { "id": "query-database", "name": "Query Database", "description": "Execute SQL queries against the connected database", "requiresWrite": false }, { "id": "list-tables", "name": "List Tables", "description": "List all tables in the connected database", "requiresWrite": false }, { "id": "describe-table", "name": "Describe Table", "description": "Get detailed schema information for a specific table", "requiresWrite": false }], "prompts": [{ "id": "check-db-status", "title": "Check database status", "prompt": "Show me the status of my Neon projects and their branches.", "category": "database", "icon": "database" }, { "id": "explore-schema", "title": "Explore database schema", "prompt": "List all tables in my database and show me the schema for the main tables.", "category": "database", "icon": "table" }, { "id": "query-data", "title": "Query database", "prompt": "Help me query my database to find specific data.", "category": "database", "icon": "search" }], "suggestedWith": ["stripe", "clerk", "vercel"] },
27
+ { "name": "neon", "displayName": "Neon", "icon": "neon.svg", "description": "Manage Neon Postgres projects, branches, and execute database queries", "auth": { "type": "api-key", "requiredApis": [{ "name": "Neon Management API", "enableUrl": "https://console.neon.tech/app/settings/api-keys" }], "tokenName": "API Key", "docsUrl": "https://neon.tech/docs/manage/api-keys" }, "envVars": [{ "name": "NEON_API_KEY", "description": "Neon API Key for Management API access", "required": true, "sensitive": true, "docsUrl": "https://neon.tech/docs/manage/api-keys" }, { "name": "DATABASE_URL", "description": "PostgreSQL connection string for database queries", "required": true, "sensitive": true, "docsUrl": "https://neon.tech/docs/connect/connect-from-any-app" }], "npmDependencies": { "pg": "^8.13.1" }, "tools": [{ "id": "list-projects", "name": "List Projects", "description": "List all Neon projects in your account", "requiresWrite": false }, { "id": "list-branches", "name": "List Branches", "description": "List all branches for a specific project", "requiresWrite": false }, { "id": "query-database", "name": "Query Database", "description": "Execute SQL queries against the connected database", "requiresWrite": false }, { "id": "list-tables", "name": "List Tables", "description": "List all tables in the connected database", "requiresWrite": false }, { "id": "describe-table", "name": "Describe Table", "description": "Get detailed schema information for a specific table", "requiresWrite": false }], "prompts": [{ "id": "check-db-status", "title": "Check database status", "prompt": "Show me the status of my Neon projects and their branches.", "category": "database", "icon": "database" }, { "id": "explore-schema", "title": "Explore database schema", "prompt": "List all tables in my database and show me the schema for the main tables.", "category": "database", "icon": "table" }, { "id": "query-data", "title": "Query database", "prompt": "Help me query my database to find specific data.", "category": "database", "icon": "search" }], "suggestedWith": ["stripe", "clerk", "vercel"] },
28
28
  { "name": "notion", "displayName": "Notion", "icon": "notion.svg", "description": "Search, read, and create pages in Notion workspaces", "auth": { "type": "oauth2", "provider": "notion", "authorizationUrl": "https://api.notion.com/v1/oauth/authorize", "tokenUrl": "https://api.notion.com/v1/oauth/token", "scopes": [], "tokenAuthMethod": "basic", "requiredApis": [{ "name": "Notion Integration", "enableUrl": "https://www.notion.so/my-integrations" }] }, "envVars": [{ "name": "NOTION_CLIENT_ID", "description": "Notion OAuth Client ID (from your integration)", "required": true, "sensitive": false, "docsUrl": "https://www.notion.so/my-integrations" }, { "name": "NOTION_CLIENT_SECRET", "description": "Notion OAuth Client Secret", "required": true, "sensitive": true, "docsUrl": "https://www.notion.so/my-integrations" }], "tools": [{ "id": "search-notion", "name": "Search Notion", "description": "Search pages and databases in the workspace", "requiresWrite": false }, { "id": "read-page", "name": "Read Page", "description": "Read the content of a Notion page", "requiresWrite": false }, { "id": "create-page", "name": "Create Page", "description": "Create a new page in a database or as a subpage", "requiresWrite": true }, { "id": "query-database", "name": "Query Database", "description": "Query a Notion database with filters and sorts", "requiresWrite": false }], "prompts": [{ "id": "search-docs", "title": "Search my docs", "prompt": "Search my Notion workspace for relevant documentation or notes about a topic.", "category": "productivity", "icon": "search" }, { "id": "summarize-page", "title": "Summarize a page", "prompt": "Read and summarize a specific Notion page. Extract the key points and action items.", "category": "productivity", "icon": "document" }, { "id": "create-meeting-notes", "title": "Create meeting notes", "prompt": "Create a new meeting notes page with today's date, attendees, agenda, and action items sections.", "category": "productivity", "icon": "plus" }], "suggestedWith": ["gmail", "slack", "calendar"] },
29
29
  { "name": "onedrive", "displayName": "OneDrive", "icon": "onedrive.svg", "description": "Access and manage files in Microsoft OneDrive", "auth": { "type": "oauth2", "provider": "microsoft", "authorizationUrl": "https://login.microsoftonline.com/common/oauth2/v2.0/authorize", "tokenUrl": "https://login.microsoftonline.com/common/oauth2/v2.0/token", "scopes": ["Files.Read", "Files.ReadWrite", "Files.Read.All", "Files.ReadWrite.All", "offline_access"], "tokenAuthMethod": "body", "requiredApis": [{ "name": "Microsoft Graph API", "enableUrl": "https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade" }] }, "envVars": [{ "name": "MICROSOFT_CLIENT_ID", "description": "Microsoft Azure App Client ID (shared with Outlook/Teams/SharePoint)", "required": true, "sensitive": false, "docsUrl": "https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade" }, { "name": "MICROSOFT_CLIENT_SECRET", "description": "Microsoft Azure App Client Secret", "required": true, "sensitive": true, "docsUrl": "https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade" }], "tools": [{ "id": "list-files", "name": "List Files", "description": "List files and folders in a OneDrive folder", "requiresWrite": false }, { "id": "search-files", "name": "Search Files", "description": "Search for files and folders in OneDrive by name or content", "requiresWrite": false }, { "id": "upload-file", "name": "Upload File", "description": "Upload or update a file in OneDrive", "requiresWrite": true }, { "id": "download-file", "name": "Download File", "description": "Download file content from OneDrive", "requiresWrite": false }], "prompts": [{ "id": "search-documents", "title": "Search documents", "prompt": "Search for documents in OneDrive and summarize their content.", "category": "productivity", "icon": "search" }, { "id": "list-recent-files", "title": "List recent files", "prompt": "Show me the most recently modified files in my OneDrive.", "category": "productivity", "icon": "document" }, { "id": "organize-files", "title": "Organize files", "prompt": "Help me organize and manage files in my OneDrive storage.", "category": "productivity", "icon": "folder" }, { "id": "backup-file", "title": "Backup a file", "prompt": "Upload and backup a file to my OneDrive storage.", "category": "productivity", "icon": "upload" }], "suggestedWith": ["outlook", "teams", "sharepoint"] },
30
30
  { "name": "outlook", "displayName": "Microsoft Outlook", "icon": "outlook.svg", "description": "Read, send, and manage Outlook emails", "auth": { "type": "oauth2", "provider": "microsoft", "authorizationUrl": "https://login.microsoftonline.com/common/oauth2/v2.0/authorize", "tokenUrl": "https://login.microsoftonline.com/common/oauth2/v2.0/token", "scopes": ["Mail.Read", "Mail.Send", "Mail.ReadWrite", "offline_access"], "tokenAuthMethod": "body", "requiredApis": [{ "name": "Microsoft Graph API", "enableUrl": "https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade" }] }, "envVars": [{ "name": "MICROSOFT_CLIENT_ID", "description": "Microsoft Azure App Client ID (Application ID)", "required": true, "sensitive": false, "docsUrl": "https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade" }, { "name": "MICROSOFT_CLIENT_SECRET", "description": "Microsoft Azure App Client Secret", "required": true, "sensitive": true, "docsUrl": "https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade" }], "tools": [{ "id": "list-emails", "name": "List Emails", "description": "List recent emails from inbox or a specific folder", "requiresWrite": false }, { "id": "get-email", "name": "Get Email", "description": "Get detailed information about a specific email", "requiresWrite": false }, { "id": "send-email", "name": "Send Email", "description": "Send a new email message", "requiresWrite": true }, { "id": "search-emails", "name": "Search Emails", "description": "Search emails by query, subject, sender, or date", "requiresWrite": false }, { "id": "list-folders", "name": "List Folders", "description": "List all mail folders in the mailbox", "requiresWrite": false }], "prompts": [{ "id": "check-emails", "title": "Check my emails", "prompt": "List my recent unread emails and summarize the most important ones.", "category": "productivity", "icon": "mail" }, { "id": "search-emails", "title": "Search my emails", "prompt": "Search my emails for specific topics, senders, or date ranges.", "category": "productivity", "icon": "search" }, { "id": "draft-email", "title": "Draft an email", "prompt": "Help me draft a professional email with proper formatting and tone.", "category": "productivity", "icon": "compose" }], "suggestedWith": ["teams", "calendar", "gmail"] },
@@ -356,6 +356,7 @@ export declare const IntegrationConfigSchema: z.ZodObject<{
356
356
  docsUrl: z.ZodOptional<z.ZodString>;
357
357
  default: z.ZodOptional<z.ZodString>;
358
358
  }, z.core.$strip>>>;
359
+ npmDependencies: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
359
360
  tools: z.ZodArray<z.ZodObject<{
360
361
  id: z.ZodOptional<z.ZodString>;
361
362
  name: z.ZodString;
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/src/integrations/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAuDxB,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAA2B,CAAC;AAE9D,eAAO,MAAM,YAAY;;;;;;;;iBAQvB,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;;;;;iBAO3B,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAyB5B,CAAC;AAEH,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;iBAMzC,CAAC;AAEH,eAAO,MAAM,kCAAkC;;;;;;;;;;;iBAK7C,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBASpC,CAAC;AAEH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAOhC,CAAC;AAEH,eAAO,MAAM,uBAAuB;;;;;;iBAMlC,CAAC;AAEH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAYlC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACpE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AACxD,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC1D,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC5D,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACxE,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AACxE,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/src/integrations/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAuDxB,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAA2B,CAAC;AAE9D,eAAO,MAAM,YAAY;;;;;;;;iBAQvB,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;;;;;iBAO3B,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAyB5B,CAAC;AAEH,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;iBAMzC,CAAC;AAEH,eAAO,MAAM,kCAAkC;;;;;;;;;;;iBAK7C,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBASpC,CAAC;AAEH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAOhC,CAAC;AAEH,eAAO,MAAM,uBAAuB;;;;;;iBAMlC,CAAC;AAEH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoBlC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACpE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AACxD,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC1D,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC5D,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACxE,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AACxE,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC"}
@@ -140,6 +140,14 @@ export const IntegrationConfigSchema = z.object({
140
140
  description: z.string(),
141
141
  auth: OAuthConfigSchema,
142
142
  envVars: z.array(EnvVarSchema).optional(),
143
+ /**
144
+ * Optional map of npm packages to semver ranges. When this integration is
145
+ * selected during `veryfront init`, these deps are merged into the
146
+ * generated project's `package.json#dependencies`. Use this for templates
147
+ * that import packages beyond the init scaffold's defaults (react,
148
+ * react-dom, veryfront, zod).
149
+ */
150
+ npmDependencies: z.record(z.string(), z.string()).optional(),
143
151
  tools: z.array(IntegrationToolSchema),
144
152
  prompts: z.array(IntegrationPromptSchema).optional(),
145
153
  suggestedWith: z.array(z.string()).optional(),
@@ -5,8 +5,8 @@
5
5
  */
6
6
  export type { CacheOptions, CacheStats, MemoryCacheOptions, RedisCacheOptions, TokenCache, TokenCacheEntry, } from "./types.js";
7
7
  export { MemoryCache } from "./memory-cache.js";
8
- export { RedisCache } from "./redis-cache.js";
9
8
  export { ResilientCache } from "./resilient-cache.js";
9
+ export { TracingTokenCache } from "./tracing-cache.js";
10
10
  import type { CacheOptions, TokenCache } from "./types.js";
11
11
  export declare function createCache(options: CacheOptions): Promise<TokenCache>;
12
12
  export declare function createCacheFromEnv(): Promise<TokenCache>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/proxy/cache/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,YAAY,EACV,YAAY,EACZ,UAAU,EACV,kBAAkB,EAClB,iBAAiB,EACjB,UAAU,EACV,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAU3D,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,CAS5E;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,UAAU,CAAC,CA0B9D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/proxy/cache/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,YAAY,EACV,YAAY,EACZ,UAAU,EACV,kBAAkB,EAClB,iBAAiB,EACjB,UAAU,EACV,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAe3D,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,CAc5E;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,UAAU,CAAC,CA4B9D"}
@@ -4,19 +4,26 @@
4
4
  * @module proxy/cache
5
5
  */
6
6
  export { MemoryCache } from "./memory-cache.js";
7
- export { RedisCache } from "./redis-cache.js";
8
7
  export { ResilientCache } from "./resilient-cache.js";
8
+ export { TracingTokenCache } from "./tracing-cache.js";
9
9
  import { MemoryCache } from "./memory-cache.js";
10
- import { RedisCache } from "./redis-cache.js";
11
10
  import { ResilientCache } from "./resilient-cache.js";
11
+ import { TracingTokenCache } from "./tracing-cache.js";
12
+ import { tryResolve } from "../../extensions/contracts.js";
12
13
  import { getEnv } from "../../platform/compat/process.js";
13
14
  import { proxyLogger } from "../logger.js";
14
15
  import { withSpan } from "../tracing.js";
15
16
  const logger = proxyLogger.child({ module: "cache" });
17
+ const MISSING_EXTENSION_INFO = "TokenCacheStore contract not provided — install @veryfront/ext-redis or scaffold extensions/ext-redis/";
16
18
  export async function createCache(options) {
17
19
  return withSpan("cache.create", async () => {
18
- if (options.type === "redis")
19
- return new RedisCache(options.options);
20
+ if (options.type === "redis") {
21
+ const tokenCache = tryResolve("TokenCacheStore");
22
+ if (tokenCache)
23
+ return new TracingTokenCache(tokenCache);
24
+ logger.info(MISSING_EXTENSION_INFO);
25
+ return new MemoryCache(undefined);
26
+ }
20
27
  return new MemoryCache(options.options);
21
28
  }, { "cache.type": options.type });
22
29
  }
@@ -25,18 +32,21 @@ export async function createCacheFromEnv() {
25
32
  return withSpan("cache.createFromEnv", async () => {
26
33
  if (cacheType !== "redis")
27
34
  return new MemoryCache();
28
- const url = getEnv("REDIS_URL");
29
- if (!url) {
30
- logger.warn("[Cache] CACHE_TYPE=redis but REDIS_URL not set, falling back to memory");
35
+ const tokenCache = tryResolve("TokenCacheStore");
36
+ if (!tokenCache) {
37
+ // Redis was requested via config/env but no extension registered the
38
+ // TokenCacheStore contract. Log an info (misconfiguration, not error),
39
+ // then fall back to an in-memory cache so the proxy still boots.
40
+ logger.info(MISSING_EXTENSION_INFO);
31
41
  return new MemoryCache();
32
42
  }
33
- const redisCache = new RedisCache({
34
- url,
35
- prefix: getEnv("REDIS_PREFIX") || "vf:token:",
36
- });
37
- // Wrap Redis with resilient fallback to memory cache
38
- // This ensures the proxy continues to function when Redis is unavailable
39
- logger.debug("[Cache] Using Redis with memory fallback (ResilientCache)");
40
- return new ResilientCache(redisCache, new MemoryCache());
43
+ // Wrap the extension-provided cache with a memory fallback so a Redis
44
+ // outage does not take the proxy down. TracingTokenCache sits between
45
+ // ResilientCache and the extension impl so spans wrap the actual
46
+ // primary-cache attempt (mirrors the pre-extraction RedisCache which
47
+ // had inner withSpan calls).
48
+ logger.debug("[Cache] Using TokenCacheStore extension with memory fallback (ResilientCache)");
49
+ const traced = new TracingTokenCache(tokenCache);
50
+ return new ResilientCache(traced, new MemoryCache());
41
51
  }, { "cache.type": cacheType });
42
52
  }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * TracingTokenCache
3
+ *
4
+ * Wraps a {@link TokenCache} implementation and emits an OpenTelemetry span
5
+ * around each public method. This keeps extension-provided caches (such as
6
+ * `@veryfront/ext-redis`) tracer-agnostic: the extension implements the
7
+ * contract only, and the proxy applies observability at the factory boundary.
8
+ *
9
+ * Span names default to `cache.redis.<op>` to preserve the pre-extraction
10
+ * behavior of the in-tree RedisCache. Callers may override via
11
+ * {@link TracingTokenCacheOptions.spanPrefix} when wrapping a different
12
+ * backend.
13
+ */
14
+ import type { CacheStats, TokenCache, TokenCacheEntry } from "./types.js";
15
+ export interface TracingTokenCacheOptions {
16
+ /** Span name prefix, e.g. "cache.redis" produces "cache.redis.get". */
17
+ spanPrefix?: string;
18
+ }
19
+ export declare class TracingTokenCache implements TokenCache {
20
+ private readonly inner;
21
+ private readonly prefix;
22
+ constructor(inner: TokenCache, options?: TracingTokenCacheOptions);
23
+ get(key: string): Promise<TokenCacheEntry | null>;
24
+ set(key: string, entry: TokenCacheEntry): Promise<void>;
25
+ delete(key: string): Promise<void>;
26
+ clear(): Promise<void>;
27
+ has(key: string): Promise<boolean>;
28
+ stats(): Promise<CacheStats>;
29
+ close(): Promise<void>;
30
+ }
31
+ //# sourceMappingURL=tracing-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracing-cache.d.ts","sourceRoot":"","sources":["../../../../src/src/proxy/cache/tracing-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAG1E,MAAM,WAAW,wBAAwB;IACvC,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAID,qBAAa,iBAAkB,YAAW,UAAU;IAClD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEpB,KAAK,EAAE,UAAU,EAAE,OAAO,GAAE,wBAA6B;IAKrE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAQjD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAQvD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQlC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQlC,KAAK,IAAI,OAAO,CAAC,UAAU,CAAC;IAI5B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAGvB"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * TracingTokenCache
3
+ *
4
+ * Wraps a {@link TokenCache} implementation and emits an OpenTelemetry span
5
+ * around each public method. This keeps extension-provided caches (such as
6
+ * `@veryfront/ext-redis`) tracer-agnostic: the extension implements the
7
+ * contract only, and the proxy applies observability at the factory boundary.
8
+ *
9
+ * Span names default to `cache.redis.<op>` to preserve the pre-extraction
10
+ * behavior of the in-tree RedisCache. Callers may override via
11
+ * {@link TracingTokenCacheOptions.spanPrefix} when wrapping a different
12
+ * backend.
13
+ */
14
+ import { withSpan } from "../tracing.js";
15
+ const DEFAULT_SPAN_PREFIX = "cache.redis";
16
+ export class TracingTokenCache {
17
+ inner;
18
+ prefix;
19
+ constructor(inner, options = {}) {
20
+ this.inner = inner;
21
+ this.prefix = options.spanPrefix ?? DEFAULT_SPAN_PREFIX;
22
+ }
23
+ get(key) {
24
+ return withSpan(`${this.prefix}.get`, () => this.inner.get(key), { "cache.key": key });
25
+ }
26
+ set(key, entry) {
27
+ return withSpan(`${this.prefix}.set`, () => this.inner.set(key, entry), { "cache.key": key });
28
+ }
29
+ delete(key) {
30
+ return withSpan(`${this.prefix}.delete`, () => this.inner.delete(key), { "cache.key": key });
31
+ }
32
+ clear() {
33
+ return withSpan(`${this.prefix}.clear`, () => this.inner.clear());
34
+ }
35
+ has(key) {
36
+ return withSpan(`${this.prefix}.has`, () => this.inner.has(key), { "cache.key": key });
37
+ }
38
+ stats() {
39
+ return withSpan(`${this.prefix}.stats`, () => this.inner.stats());
40
+ }
41
+ close() {
42
+ return withSpan(`${this.prefix}.close`, () => this.inner.close());
43
+ }
44
+ }
@@ -2,7 +2,7 @@
2
2
  * Token Cache Interface
3
3
  *
4
4
  * Abstraction for storing OAuth tokens with TTL support.
5
- * Implementations: MemoryCache, RedisCache
5
+ * Implementations: MemoryCache (built-in), RedisCache (via @veryfront/ext-redis)
6
6
  */
7
7
  export interface TokenCacheEntry {
8
8
  token: string;
@@ -2,6 +2,6 @@
2
2
  * Token Cache Interface
3
3
  *
4
4
  * Abstraction for storing OAuth tokens with TTL support.
5
- * Implementations: MemoryCache, RedisCache
5
+ * Implementations: MemoryCache (built-in), RedisCache (via @veryfront/ext-redis)
6
6
  */
7
7
  export {};
@@ -1,5 +1,12 @@
1
1
  import { type ParsedDomain } from "../server/utils/domain-parser.js";
2
2
  import type { TokenCache } from "./cache/types.js";
3
+ /**
4
+ * Reset the cached AuthProvider. Intended for tests that `register()` a mock
5
+ * after the handler module has been imported.
6
+ *
7
+ * @internal
8
+ */
9
+ export declare function __resetCachedAuthProviderForTests(): void;
3
10
  export declare const INTERNAL_PROXY_HEADERS: readonly ["x-token", "x-project-slug", "x-environment", "x-environment-id", "x-content-source-id", "x-forwarded-host", "x-project-path", "x-project-id", "x-release-id", "x-branch-id", "x-branch-name"];
4
11
  export interface ProxyConfig {
5
12
  apiBaseUrl: string;
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/src/proxy/handler.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,YAAY,EAAsB,MAAM,kCAAkC,CAAC;AACzF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAQnD,eAAO,MAAM,sBAAsB,0MAYzB,CAAC;AAmIX,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,SAAS,GAAG,YAAY,CAAC;IACtC,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,YAAY,CAAC;IAC3B,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE;QACN,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC9D,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC7D,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC7D,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CAC9E;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAiGD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB;0BA4Q1B,OAAO,KAAG,OAAO,CAAC,YAAY,CAAC;0BAmQ/B,OAAO,KAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;;;;;;;;0BApd7C,MAAM,EAAE;;EAgfpC;AAED,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEjE,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,YAAY,GAAG,OAAO,CAwB7E"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/src/proxy/handler.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,YAAY,EAAsB,MAAM,kCAAkC,CAAC;AACzF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAuCnD;;;;;GAKG;AACH,wBAAgB,iCAAiC,IAAI,IAAI,CAExD;AAED,eAAO,MAAM,sBAAsB,0MAYzB,CAAC;AAqHX,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,SAAS,GAAG,YAAY,CAAC;IACtC,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,YAAY,CAAC;IAC3B,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE;QACN,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC9D,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC7D,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC7D,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CAC9E;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAgGD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB;0BA4Q1B,OAAO,KAAG,OAAO,CAAC,YAAY,CAAC;0BAmQ/B,OAAO,KAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;;;;;;;;0BApd7C,MAAM,EAAE;;EAgfpC;AAED,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEjE,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,YAAY,GAAG,OAAO,CAwB7E"}
@@ -5,7 +5,42 @@ import { cwd, getEnv } from "../platform/compat/process.js";
5
5
  import { join } from "../platform/compat/path/index.js";
6
6
  import { injectContext, ProxySpanNames, withSpan } from "./tracing.js";
7
7
  import { computeContentSourceId } from "../cache/keys.js";
8
- import { createRemoteJWKSet, decodeProtectedHeader, jwtVerify } from "jose";
8
+ import { resolve as resolveContract } from "../extensions/contracts.js";
9
+ /**
10
+ * Cache the resolved AuthProvider at module scope so the proxy does not pay
11
+ * the registry lookup on every request. The cache is cleared implicitly when
12
+ * `ExtensionLoader.teardownAll()` clears the registry — the next call
13
+ * re-resolves (or surfaces the "install ext-jwt" hint if the extension was
14
+ * removed).
15
+ */
16
+ let cachedAuthProvider;
17
+ function getAuthProvider() {
18
+ if (cachedAuthProvider)
19
+ return cachedAuthProvider;
20
+ try {
21
+ cachedAuthProvider = resolveContract("AuthProvider");
22
+ return cachedAuthProvider;
23
+ }
24
+ catch (err) {
25
+ // resolve() already throws with a helpful "Recommended: @veryfront/ext-jwt"
26
+ // message, but the proxy is a load-bearing code path — append a concrete
27
+ // remediation hint that names the project-root extension directory so
28
+ // the user knows exactly what's missing.
29
+ const base = err instanceof Error ? err.message : String(err);
30
+ throw new Error(`${base}\nTo enable JWT verification in the proxy, install ext-jwt ` +
31
+ `(scaffold with \`deno task cli extension init ext-jwt\` or add the ` +
32
+ `npm package @veryfront/ext-jwt).`, { cause: err });
33
+ }
34
+ }
35
+ /**
36
+ * Reset the cached AuthProvider. Intended for tests that `register()` a mock
37
+ * after the handler module has been imported.
38
+ *
39
+ * @internal
40
+ */
41
+ export function __resetCachedAuthProviderForTests() {
42
+ cachedAuthProvider = undefined;
43
+ }
9
44
  export const INTERNAL_PROXY_HEADERS = [
10
45
  "x-token",
11
46
  "x-project-slug",
@@ -40,21 +75,10 @@ function isSignedInternalControlPlaneRequest(req) {
40
75
  }
41
76
  return !!req.headers.get("x-token");
42
77
  }
43
- const remoteJwksByUrl = new Map();
44
- function getApiJwks(apiBaseUrl, logger) {
78
+ function resolveApiJwksUrl(apiBaseUrl, logger) {
45
79
  try {
46
80
  const normalizedBaseUrl = apiBaseUrl.endsWith("/") ? apiBaseUrl : `${apiBaseUrl}/`;
47
- const jwksUrl = new URL(".well-known/jwks.json", normalizedBaseUrl);
48
- const cacheKey = jwksUrl.toString();
49
- // Lazily initialize and cache JWKS in a single, idempotent step to avoid
50
- // unsynchronized read/then-write on the shared Map across concurrent calls.
51
- let jwks = remoteJwksByUrl.get(cacheKey);
52
- if (!jwks) {
53
- const created = createRemoteJWKSet(jwksUrl);
54
- remoteJwksByUrl.set(cacheKey, created);
55
- jwks = created;
56
- }
57
- return jwks;
81
+ return new URL(".well-known/jwks.json", normalizedBaseUrl).toString();
58
82
  }
59
83
  catch (error) {
60
84
  logger?.error("Invalid API base URL for JWKS lookup", error, {
@@ -130,22 +154,19 @@ function isMissingCustomDomainProjectError(error) {
130
154
  return /project not found for domain/i.test(message);
131
155
  }
132
156
  async function extractUserIdFromToken(token, apiBaseUrl, log) {
133
- let algorithm;
134
- try {
135
- algorithm = decodeProtectedHeader(token).alg;
136
- }
137
- catch (error) {
138
- log?.debug("Failed to decode JWT header", {
139
- error: error instanceof Error ? error.message : String(error),
140
- });
157
+ const auth = getAuthProvider();
158
+ const header = auth.decode(token);
159
+ if (!header) {
160
+ log?.debug("Failed to decode JWT header");
141
161
  return undefined;
142
162
  }
163
+ const algorithm = header.alg;
143
164
  if (algorithm === "RS256") {
144
- const jwks = getApiJwks(apiBaseUrl, log);
145
- if (!jwks)
165
+ const jwksUrl = resolveApiJwksUrl(apiBaseUrl, log);
166
+ if (!jwksUrl)
146
167
  return undefined;
147
168
  try {
148
- const { payload } = await jwtVerify(token, jwks, {
169
+ const payload = await auth.verifyWithJwks(token, jwksUrl, {
149
170
  algorithms: ["RS256"],
150
171
  });
151
172
  return payload.userId;
@@ -167,10 +188,10 @@ async function extractUserIdFromToken(token, apiBaseUrl, log) {
167
188
  return undefined;
168
189
  }
169
190
  try {
170
- const secret = new TextEncoder().encode(jwtSecret);
171
- const { payload } = await jwtVerify(token, secret, {
172
- algorithms: ["HS256"],
173
- });
191
+ // ext-jwt reads JWT_SECRET from the environment when no `secret` was
192
+ // passed to the extension factory; the explicit env check above is kept
193
+ // so callers can warn once before we attempt verification.
194
+ const payload = await auth.verify(token, { algorithms: ["HS256"] });
174
195
  return payload.userId;
175
196
  }
176
197
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"request-tracker.d.ts","sourceRoot":"","sources":["../../../../src/src/server/runtime-handler/request-tracker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AASlD,UAAU,cAAc;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,UAAU,CAAC,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC;IAClD,aAAa,CAAC,EAAE,UAAU,CAAC,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC;CACvD;AAiBD,cAAM,cAAc;IAClB,OAAO,CAAC,QAAQ,CAAqC;IACrD,OAAO,CAAC,cAAc,CAAqD;IAC3E,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,aAAa,CAAK;;IAM1B,OAAO,CAAC,kBAAkB;IA4B1B,KAAK,CACH,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,GAAG,CAAC,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,MAAM,GACjB,IAAI;IAsDP,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,UAAQ,GAAG,IAAI;IAmCvE,gBAAgB,IAAI,MAAM;IAI1B,mBAAmB,IAAI,cAAc,EAAE;IAIvC,QAAQ,IAAI;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;IAS9E,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,SAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAsD7E,QAAQ,IAAI,IAAI;CAUjB;AAED,eAAO,MAAM,cAAc,gBAAuB,CAAC"}
1
+ {"version":3,"file":"request-tracker.d.ts","sourceRoot":"","sources":["../../../../src/src/server/runtime-handler/request-tracker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AASlD,UAAU,cAAc;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,UAAU,CAAC,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC;IAClD,aAAa,CAAC,EAAE,UAAU,CAAC,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC;CACvD;AAiBD,cAAM,cAAc;IAClB,OAAO,CAAC,QAAQ,CAAqC;IACrD,OAAO,CAAC,cAAc,CAAqD;IAC3E,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,aAAa,CAAK;;IAM1B,OAAO,CAAC,kBAAkB;IA4B1B,KAAK,CACH,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,GAAG,CAAC,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,MAAM,GACjB,IAAI;IAuDP,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,UAAQ,GAAG,IAAI;IAgCvE,gBAAgB,IAAI,MAAM;IAI1B,mBAAmB,IAAI,cAAc,EAAE;IAIvC,QAAQ,IAAI;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;IAS9E,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,SAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAsD7E,QAAQ,IAAI,IAAI;CAUjB;AAED,eAAO,MAAM,cAAc,gBAAuB,CAAC"}
@@ -7,7 +7,7 @@
7
7
  import * as dntShim from "../../../_dnt.shims.js";
8
8
  import { serverLogger } from "../../utils/index.js";
9
9
  import { unrefTimer } from "../../platform/compat/process.js";
10
- import { isWebSocketPath } from "./request-utils.js";
10
+ import { isLightweightPath, isWebSocketPath } from "./request-utils.js";
11
11
  const logger = serverLogger.component("request-tracker");
12
12
  /** Threshold in ms before logging a warning about a slow request */
13
13
  const SLOW_REQUEST_THRESHOLD_MS = 10_000; // 10 seconds
@@ -66,8 +66,9 @@ class RequestTracker {
66
66
  env,
67
67
  releaseId,
68
68
  };
69
- // WebSocket connections are long-lived by design don't flag them as stuck.
70
- if (!isWebSocketPath(path)) {
69
+ // WebSocket connections are long-lived by design and lightweight internal
70
+ // asset/module requests can be noisy under CI jitter — don't flag them as stuck.
71
+ if (!isWebSocketPath(path) && !isLightweightPath(path)) {
71
72
  tracked.slowTimer = dntShim.setTimeout(() => {
72
73
  const elapsedMs = Math.round(performance.now() - startTime);
73
74
  logger.warn("Slow request detected", {
@@ -118,9 +119,7 @@ class RequestTracker {
118
119
  this.totalTimedOut++;
119
120
  else
120
121
  this.totalCompleted++;
121
- const isModuleRequest = tracked.path.startsWith("/_vf_modules/") ||
122
- tracked.path.startsWith("/_veryfront/");
123
- if (isModuleRequest) {
122
+ if (isLightweightPath(tracked.path)) {
124
123
  if (durationMs > MODULE_REQUEST_LOG_THRESHOLD_MS) {
125
124
  logger.debug(`${tracked.method} ${tracked.path} ${statusCode} ${durationMs}ms`);
126
125
  }
@@ -1 +1 @@
1
- {"version":3,"file":"request-utils.d.ts","sourceRoot":"","sources":["../../../../src/src/server/runtime-handler/request-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,qDAAqD;AACrD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAkBpD;AAED,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,aAA+C,CAAC;AAK7E,yFAAyF;AACzF,wBAAgB,iBAAiB,IAAI,MAAM,CAK1C;AAED,OAAO,EAAE,oBAAoB,EAAE,CAAC;AAEhC,sEAAsE;AACtE,eAAO,MAAM,gBAAgB,eAA4B,CAAC;AAE1D,oFAAoF;AACpF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,uFAAuF;AACvF,eAAO,MAAM,yBAAyB,UAQrC,CAAC;AAEF,mFAAmF;AACnF,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEnE"}
1
+ {"version":3,"file":"request-utils.d.ts","sourceRoot":"","sources":["../../../../src/src/server/runtime-handler/request-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,qDAAqD;AACrD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAkBpD;AAED,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,aAA+C,CAAC;AAK7E,yFAAyF;AACzF,wBAAgB,iBAAiB,IAAI,MAAM,CAK1C;AAED,OAAO,EAAE,oBAAoB,EAAE,CAAC;AAEhC,sEAAsE;AACtE,eAAO,MAAM,gBAAgB,eAA4B,CAAC;AAE1D,oFAAoF;AACpF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,uFAAuF;AACvF,eAAO,MAAM,yBAAyB,UASrC,CAAC;AAEF,mFAAmF;AACnF,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEnE"}
@@ -48,6 +48,7 @@ export function isMonitoringPath(pathname) {
48
48
  /** Lightweight paths that should skip concurrency limiting (modules, static assets) */
49
49
  export const LIGHTWEIGHT_PATH_PREFIXES = [
50
50
  "/_vf_modules/",
51
+ "/_vf_styles/",
51
52
  "/_veryfront/modules/",
52
53
  "/_veryfront/hydration-runtime.js",
53
54
  "/_veryfront/preview-hmr.js",
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.1.217";
1
+ export declare const VERSION = "0.1.219";
2
2
  //# sourceMappingURL=version-constant.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
- export const VERSION = "0.1.217";
3
+ export const VERSION = "0.1.219";