veryfront 0.1.18 → 0.1.20
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/deno.js +1 -1
- package/esm/src/integrations/_data.js +1 -1
- package/esm/src/modules/react-loader/ssr-module-loader/cache/memory.d.ts.map +1 -1
- package/esm/src/modules/react-loader/ssr-module-loader/cache/memory.js +2 -1
- package/esm/src/modules/react-loader/ssr-module-loader/loader.d.ts.map +1 -1
- package/esm/src/modules/react-loader/ssr-module-loader/loader.js +2 -1
- package/esm/src/modules/react-loader/ssr-module-loader/tmp-paths.d.ts.map +1 -1
- package/esm/src/modules/react-loader/ssr-module-loader/tmp-paths.js +3 -2
- package/esm/src/modules/react-loader/ssr-module-loader/vf-module-resolver.d.ts.map +1 -1
- package/esm/src/modules/react-loader/ssr-module-loader/vf-module-resolver.js +2 -1
- package/esm/src/platform/adapters/fs/veryfront/file-list-index.d.ts +1 -0
- package/esm/src/platform/adapters/fs/veryfront/file-list-index.d.ts.map +1 -1
- package/esm/src/platform/adapters/fs/veryfront/file-list-index.js +28 -1
- package/esm/src/platform/adapters/fs/veryfront/websocket-manager.d.ts +2 -0
- package/esm/src/platform/adapters/fs/veryfront/websocket-manager.d.ts.map +1 -1
- package/esm/src/platform/adapters/fs/veryfront/websocket-manager.js +44 -11
- package/esm/src/routing/api/route-executor.d.ts.map +1 -1
- package/esm/src/routing/api/route-executor.js +28 -6
- package/esm/src/server/context/request-context.d.ts.map +1 -1
- package/esm/src/server/context/request-context.js +2 -1
- package/esm/src/server/dev-server/server.d.ts +1 -0
- package/esm/src/server/dev-server/server.d.ts.map +1 -1
- package/esm/src/server/dev-server/server.js +23 -1
- package/esm/src/server/dev-server/types.d.ts +1 -0
- package/esm/src/server/dev-server/types.d.ts.map +1 -1
- package/esm/src/server/handlers/preview/hmr.handler.d.ts +2 -0
- package/esm/src/server/handlers/preview/hmr.handler.d.ts.map +1 -1
- package/esm/src/server/handlers/preview/hmr.handler.js +21 -2
- package/esm/src/server/index.d.ts +3 -1
- package/esm/src/server/index.d.ts.map +1 -1
- package/esm/src/server/index.js +9 -3
- package/esm/src/server/utils/domain-parser.d.ts +8 -0
- package/esm/src/server/utils/domain-parser.d.ts.map +1 -1
- package/esm/src/server/utils/domain-parser.js +45 -0
- package/esm/src/utils/constants/security.d.ts +2 -2
- package/esm/src/utils/constants/security.d.ts.map +1 -1
- package/esm/src/utils/constants/security.js +3 -3
- package/package.json +1 -1
- package/src/deno.js +1 -1
- package/src/src/integrations/_data.ts +1 -1
- package/src/src/modules/react-loader/ssr-module-loader/cache/memory.ts +2 -1
- package/src/src/modules/react-loader/ssr-module-loader/loader.ts +2 -1
- package/src/src/modules/react-loader/ssr-module-loader/tmp-paths.ts +3 -2
- package/src/src/modules/react-loader/ssr-module-loader/vf-module-resolver.ts +2 -1
- package/src/src/platform/adapters/fs/veryfront/file-list-index.ts +30 -1
- package/src/src/platform/adapters/fs/veryfront/websocket-manager.ts +45 -10
- package/src/src/routing/api/route-executor.ts +34 -7
- package/src/src/server/context/request-context.ts +2 -1
- package/src/src/server/dev-server/server.ts +28 -1
- package/src/src/server/dev-server/types.ts +1 -0
- package/src/src/server/handlers/preview/hmr.handler.ts +28 -2
- package/src/src/server/index.ts +16 -2
- package/src/src/server/utils/domain-parser.ts +55 -0
- package/src/src/utils/constants/security.ts +3 -3
package/esm/deno.js
CHANGED
|
@@ -12,7 +12,7 @@ export const connectors = [
|
|
|
12
12
|
{ "name": "docs-google", "displayName": "Google Docs", "icon": "docs-google.svg", "description": "Read, create, and manage Google Docs documents", "auth": { "type": "oauth2", "provider": "google", "authorizationUrl": "https://accounts.google.com/o/oauth2/v2/auth", "tokenUrl": "https://oauth2.googleapis.com/token", "scopes": ["https://www.googleapis.com/auth/documents.readonly", "https://www.googleapis.com/auth/documents", "https://www.googleapis.com/auth/drive.readonly"], "requiredApis": [{ "name": "Google Docs API", "enableUrl": "https://console.cloud.google.com/apis/library/docs.googleapis.com" }, { "name": "Google Drive API", "enableUrl": "https://console.cloud.google.com/apis/library/drive.googleapis.com" }] }, "envVars": [{ "name": "GOOGLE_CLIENT_ID", "description": "Google OAuth Client ID", "required": true, "sensitive": false, "docsUrl": "https://console.cloud.google.com/apis/credentials" }, { "name": "GOOGLE_CLIENT_SECRET", "description": "Google OAuth Client Secret", "required": true, "sensitive": true, "docsUrl": "https://console.cloud.google.com/apis/credentials" }], "tools": [{ "id": "list-documents", "name": "List Documents", "description": "List recent Google Docs documents from Drive", "requiresWrite": false }, { "id": "get-document", "name": "Get Document", "description": "Get document content and metadata", "requiresWrite": false }, { "id": "create-document", "name": "Create Document", "description": "Create a new document with optional initial content", "requiresWrite": true }, { "id": "update-document", "name": "Update Document", "description": "Update document content using batch requests", "requiresWrite": true }, { "id": "search-documents", "name": "Search Documents", "description": "Search for documents by query string", "requiresWrite": false }], "prompts": [{ "id": "summarize-doc", "title": "Summarize a document", "prompt": "Read a Google Docs document and provide a concise summary of its contents, key points, and main themes.", "category": "productivity", "icon": "file-text" }, { "id": "create-report", "title": "Create a report document", "prompt": "Create a new Google Docs document with a well-formatted report including headings, bullet points, and structured content.", "category": "productivity", "icon": "plus" }, { "id": "edit-document", "title": "Edit a document", "prompt": "Update an existing Google Docs document with new content, formatting changes, or corrections.", "category": "productivity", "icon": "edit" }], "suggestedWith": ["gmail", "calendar", "drive", "sheets"] },
|
|
13
13
|
{ "name": "drive", "displayName": "Google Drive", "icon": "drive.svg", "description": "Access, search, and manage files and folders in Google Drive", "auth": { "type": "oauth2", "provider": "google", "authorizationUrl": "https://accounts.google.com/o/oauth2/v2/auth", "tokenUrl": "https://oauth2.googleapis.com/token", "scopes": ["https://www.googleapis.com/auth/drive.readonly", "https://www.googleapis.com/auth/drive.file"], "requiredApis": [{ "name": "Google Drive API", "enableUrl": "https://console.cloud.google.com/apis/library/drive.googleapis.com" }] }, "envVars": [{ "name": "GOOGLE_CLIENT_ID", "description": "Google OAuth Client ID", "required": true, "sensitive": false, "docsUrl": "https://console.cloud.google.com/apis/credentials" }, { "name": "GOOGLE_CLIENT_SECRET", "description": "Google OAuth Client Secret", "required": true, "sensitive": true, "docsUrl": "https://console.cloud.google.com/apis/credentials" }], "tools": [{ "id": "list-files", "name": "List Files", "description": "List files and folders in a Google Drive folder or root", "requiresWrite": false }, { "id": "get-file", "name": "Get File", "description": "Get metadata and details about a specific file or folder", "requiresWrite": false }, { "id": "search-files", "name": "Search Files", "description": "Search for files and folders using queries", "requiresWrite": false }, { "id": "create-folder", "name": "Create Folder", "description": "Create a new folder in Google Drive", "requiresWrite": true }, { "id": "upload-file", "name": "Upload File", "description": "Upload or create a file in Google Drive", "requiresWrite": true }], "prompts": [{ "id": "organize-files", "title": "Organize Drive files", "prompt": "Help me organize files in Google Drive by creating folders and moving files based on file types or names.", "category": "productivity", "icon": "folder" }, { "id": "find-document", "title": "Find a document", "prompt": "Search Google Drive for a specific file or document by name, type, or content.", "category": "productivity", "icon": "search" }, { "id": "backup-files", "title": "Create backup structure", "prompt": "Create a backup folder structure in Google Drive and organize important files.", "category": "productivity", "icon": "upload" }], "suggestedWith": ["gmail", "calendar", "sheets"] },
|
|
14
14
|
{ "name": "dropbox", "displayName": "Dropbox", "icon": "dropbox.svg", "description": "Access, search, and manage files in your Dropbox storage", "auth": { "type": "oauth2", "provider": "dropbox", "authorizationUrl": "https://www.dropbox.com/oauth2/authorize", "tokenUrl": "https://api.dropboxapi.com/oauth2/token", "scopes": ["files.content.read", "files.content.write", "files.metadata.read", "files.metadata.write", "account_info.read"], "tokenAuthMethod": "request_body", "supportsRefreshToken": true, "requiredApis": [{ "name": "Dropbox App", "enableUrl": "https://www.dropbox.com/developers/apps" }] }, "envVars": [{ "name": "DROPBOX_APP_KEY", "description": "Dropbox App Key (Client ID)", "required": true, "sensitive": false, "docsUrl": "https://www.dropbox.com/developers/apps" }, { "name": "DROPBOX_APP_SECRET", "description": "Dropbox App Secret", "required": true, "sensitive": true, "docsUrl": "https://www.dropbox.com/developers/apps" }], "tools": [{ "id": "list-files", "name": "List Files", "description": "List files and folders in a Dropbox folder", "requiresWrite": false }, { "id": "get-file", "name": "Get File", "description": "Get file metadata and optionally download file content", "requiresWrite": false }, { "id": "upload-file", "name": "Upload File", "description": "Upload or update a file in Dropbox", "requiresWrite": true }, { "id": "search-files", "name": "Search Files", "description": "Search for files and folders by name or content", "requiresWrite": false }, { "id": "get-account", "name": "Get Account Info", "description": "Get current user account information and storage usage", "requiresWrite": false }], "prompts": [{ "id": "find-documents", "title": "Find my documents", "prompt": "Search my Dropbox for specific documents or files by name or content.", "category": "productivity", "icon": "search" }, { "id": "organize-files", "title": "Organize files", "prompt": "Help me organize and manage files in my Dropbox, including moving, copying, or cleaning up duplicates.", "category": "productivity", "icon": "folder" }, { "id": "backup-file", "title": "Backup a file", "prompt": "Upload and backup a file to my Dropbox storage.", "category": "productivity", "icon": "upload" }, { "id": "check-storage", "title": "Check storage", "prompt": "Check my Dropbox storage usage and available space.", "category": "productivity", "icon": "database" }], "suggestedWith": ["notion", "gmail", "drive"] },
|
|
15
|
-
{ "name": "figma", "displayName": "Figma", "icon": "figma.svg", "description": "Access Figma designs, files, comments, and collaborate on design projects", "auth": { "type": "oauth2", "provider": "figma", "authorizationUrl": "https://www.figma.com/oauth", "tokenUrl": "https://
|
|
15
|
+
{ "name": "figma", "displayName": "Figma", "icon": "figma.svg", "description": "Access Figma designs, files, comments, and collaborate on design projects", "auth": { "type": "oauth2", "provider": "figma", "authorizationUrl": "https://www.figma.com/oauth", "tokenUrl": "https://api.figma.com/v1/oauth/token", "scopes": ["file_content:read"], "tokenAuthMethod": "client_secret_basic", "requiredApis": [{ "name": "Figma OAuth App", "enableUrl": "https://www.figma.com/developers/apps" }] }, "envVars": [{ "name": "FIGMA_CLIENT_ID", "description": "Figma OAuth Client ID (from your app settings)", "required": true, "sensitive": false, "docsUrl": "https://www.figma.com/developers/apps" }, { "name": "FIGMA_CLIENT_SECRET", "description": "Figma OAuth Client Secret", "required": true, "sensitive": true, "docsUrl": "https://www.figma.com/developers/apps" }], "tools": [{ "id": "list-files", "name": "List Files", "description": "List recent Figma files accessible to the user", "requiresWrite": false }, { "id": "get-file", "name": "Get File", "description": "Get detailed information about a Figma file including components and styles", "requiresWrite": false }, { "id": "get-comments", "name": "Get Comments", "description": "Get all comments on a Figma file", "requiresWrite": false }, { "id": "post-comment", "name": "Post Comment", "description": "Post a comment on a Figma file", "requiresWrite": true }, { "id": "list-projects", "name": "List Projects", "description": "List all projects in a team", "requiresWrite": false }], "prompts": [{ "id": "review-design", "title": "Review a design", "prompt": "Review a Figma design file and provide feedback on the components, layout, and design system usage.", "category": "design", "icon": "eye" }, { "id": "summarize-comments", "title": "Summarize comments", "prompt": "Read all comments on a Figma file and summarize the feedback, action items, and unresolved discussions.", "category": "design", "icon": "message" }, { "id": "extract-components", "title": "Extract components", "prompt": "List all components in a Figma file and describe their structure, variants, and properties.", "category": "design", "icon": "component" }, { "id": "design-feedback", "title": "Give design feedback", "prompt": "Review the design file and post constructive feedback as comments on specific elements.", "category": "design", "icon": "plus" }], "suggestedWith": ["linear", "slack", "notion"] },
|
|
16
16
|
{ "name": "freshdesk", "displayName": "Freshdesk", "icon": "freshdesk.svg", "description": "Manage customer support tickets and contacts in Freshdesk", "auth": { "type": "oauth2", "provider": "freshdesk", "authorizationUrl": "https://accounts.freshworks.com/authorize", "tokenUrl": "https://accounts.freshworks.com/oauth/token", "scopes": ["freshdesk"], "requiredApis": [{ "name": "Freshdesk Developer Portal", "enableUrl": "https://developers.freshdesk.com/apps/" }] }, "envVars": [{ "name": "FRESHDESK_CLIENT_ID", "description": "Freshdesk OAuth Client ID", "required": true, "sensitive": false, "docsUrl": "https://developers.freshdesk.com/api/" }, { "name": "FRESHDESK_CLIENT_SECRET", "description": "Freshdesk OAuth Client Secret", "required": true, "sensitive": true, "docsUrl": "https://developers.freshdesk.com/api/" }], "tools": [{ "id": "list-tickets", "name": "List Tickets", "description": "List support tickets from Freshdesk", "requiresWrite": false }, { "id": "get-ticket", "name": "Get Ticket", "description": "Get details of a specific ticket", "requiresWrite": false }, { "id": "create-ticket", "name": "Create Ticket", "description": "Create a new support ticket", "requiresWrite": true }, { "id": "update-ticket", "name": "Update Ticket", "description": "Update an existing ticket", "requiresWrite": true }, { "id": "list-contacts", "name": "List Contacts", "description": "List customer contacts in Freshdesk", "requiresWrite": false }], "prompts": [{ "id": "my-tickets", "title": "Show my tickets", "prompt": "List all open support tickets assigned to me with their priority and status.", "category": "support", "icon": "inbox" }, { "id": "create-ticket", "title": "Create a ticket", "prompt": "Create a new support ticket with a subject, description, priority, and contact.", "category": "support", "icon": "plus" }], "suggestedWith": ["slack", "intercom", "zendesk"] },
|
|
17
17
|
{ "name": "github", "displayName": "GitHub", "icon": "github.svg", "description": "Manage repositories, issues, and pull requests", "auth": { "type": "oauth2", "provider": "github", "authorizationUrl": "https://github.com/login/oauth/authorize", "tokenUrl": "https://github.com/login/oauth/access_token", "scopes": ["repo", "read:user", "read:org"] }, "envVars": [{ "name": "GITHUB_CLIENT_ID", "description": "GitHub OAuth App Client ID", "required": true, "sensitive": false, "docsUrl": "https://github.com/settings/developers" }, { "name": "GITHUB_CLIENT_SECRET", "description": "GitHub OAuth App Client Secret", "required": true, "sensitive": true, "docsUrl": "https://github.com/settings/developers" }], "tools": [{ "id": "list-repos", "name": "List Repositories", "description": "Get list of user's repositories", "requiresWrite": false }, { "id": "list-prs", "name": "List Pull Requests", "description": "Get open pull requests", "requiresWrite": false }, { "id": "create-issue", "name": "Create Issue", "description": "Create a new issue in a repository", "requiresWrite": true }, { "id": "get-pr-diff", "name": "Get PR Diff", "description": "Get the diff for a pull request", "requiresWrite": false }], "prompts": [{ "id": "review-prs", "title": "Review my open PRs", "prompt": "Show me my open pull requests and help me review them. Summarize the changes and any comments.", "category": "development", "icon": "git-pull-request" }, { "id": "create-issue", "title": "Create GitHub issue", "prompt": "Help me create a new GitHub issue with a clear description and appropriate labels.", "category": "development", "icon": "circle-dot" }, { "id": "summarize-commits", "title": "Summarize recent commits", "prompt": "Summarize the recent commits in my repository and highlight significant changes.", "category": "development", "icon": "git-commit" }], "suggestedWith": ["jira", "slack"] },
|
|
18
18
|
{ "name": "gitlab", "displayName": "GitLab", "icon": "gitlab.svg", "description": "Search and manage GitLab issues, merge requests, and projects", "auth": { "type": "oauth2", "provider": "gitlab", "authorizationUrl": "https://gitlab.com/oauth/authorize", "tokenUrl": "https://gitlab.com/oauth/token", "scopes": ["api", "read_user", "read_repository"], "tokenAuthMethod": "body", "requiredApis": [{ "name": "GitLab Application", "enableUrl": "https://gitlab.com/-/profile/applications" }] }, "envVars": [{ "name": "GITLAB_CLIENT_ID", "description": "GitLab OAuth Application ID", "required": true, "sensitive": false, "docsUrl": "https://docs.gitlab.com/ee/api/oauth2.html" }, { "name": "GITLAB_CLIENT_SECRET", "description": "GitLab OAuth Application Secret", "required": true, "sensitive": true, "docsUrl": "https://docs.gitlab.com/ee/api/oauth2.html" }], "tools": [{ "id": "search-issues", "name": "Search Issues", "description": "Search for issues across projects", "requiresWrite": false }, { "id": "get-issue", "name": "Get Issue", "description": "Get detailed information about a specific issue", "requiresWrite": false }, { "id": "create-issue", "name": "Create Issue", "description": "Create a new issue in a project", "requiresWrite": true }, { "id": "list-merge-requests", "name": "List Merge Requests", "description": "List merge requests for a project or across projects", "requiresWrite": false }, { "id": "list-projects", "name": "List Projects", "description": "List accessible GitLab projects", "requiresWrite": false }], "prompts": [{ "id": "find-issues", "title": "Find my issues", "prompt": "Search for issues assigned to me that are open. Show me the most important ones.", "category": "development", "icon": "bug" }, { "id": "review-mrs", "title": "Review merge requests", "prompt": "Show me all open merge requests that need my review. Summarize what each one does.", "category": "development", "icon": "git-merge" }, { "id": "create-bug-report", "title": "Create bug report", "prompt": "Help me create a detailed bug report issue with steps to reproduce, expected vs actual behavior.", "category": "development", "icon": "plus" }, { "id": "project-status", "title": "Project status", "prompt": "Give me a summary of my projects: open issues, merge requests, and recent activity.", "category": "development", "icon": "list" }], "suggestedWith": ["github", "jira", "slack"] },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../../../../src/src/modules/react-loader/ssr-module-loader/cache/memory.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../../../../src/src/modules/react-loader/ssr-module-loader/cache/memory.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAO5D,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAExD,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAOnE,eAAO,MAAM,iBAAiB,oCAE5B,CAAC;AAEH,eAAO,MAAM,uBAAuB,oCAElC,CAAC;AAEH,eAAO,MAAM,gBAAgB,4BAAmC,CAAC;AAEjE,eAAO,MAAM,aAAa,0BAExB,CAAC;AAEH,eAAO,MAAM,gBAAgB,4BAAmC,CAAC;AAGjE,wBAAgB,qBAAqB,IAAI,SAAS,CAKjD;AAsBD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAW/D;AAKD;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAUlB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAU5D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI;IACnC,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC,CAOA;AAiDD,wBAAgB,mBAAmB,IAAI,IAAI,CAqB1C;AAED,wBAAgB,6BAA6B,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAiDrE"}
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
import * as dntShim from "../../../../../_dnt.shims.js";
|
|
16
16
|
import { registerCache } from "../../../../utils/memory/index.js";
|
|
17
17
|
import { isKeyForProject, registerMapCache } from "../../../../cache/keys.js";
|
|
18
|
+
import { hashCodeHex } from "../../../../utils/hash-utils.js";
|
|
18
19
|
import { rendererLogger } from "../../../../utils/index.js";
|
|
19
20
|
import { LRUCache } from "../../../../utils/lru-wrapper.js";
|
|
20
21
|
import { getMaxConcurrentTransforms, getTransformPerProjectLimit, resetCachedTransformLimits, SSR_TMP_DIRS_MAX_ENTRIES, } from "../constants.js";
|
|
@@ -179,7 +180,7 @@ export function clearSSRModuleCache() {
|
|
|
179
180
|
}
|
|
180
181
|
export function clearSSRModuleCacheForProject(projectId) {
|
|
181
182
|
let cleared = 0;
|
|
182
|
-
const encodedProjectId =
|
|
183
|
+
const encodedProjectId = hashCodeHex(projectId);
|
|
183
184
|
for (const key of globalModuleCache.keys()) {
|
|
184
185
|
if (!isKeyForProject(key, projectId))
|
|
185
186
|
continue;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../../../src/src/modules/react-loader/ssr-module-loader/loader.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../../../src/src/modules/react-loader/ssr-module-loader/loader.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAiCpC,OAAO,KAAK,EAAoB,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAwB3E;;;;;GAKG;AACH,qBAAa,eAAe;IAKd,OAAO,CAAC,OAAO;IAJ3B,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,cAAc,CAA2B;IACjD,OAAO,CAAC,YAAY,CAAyB;gBAEzB,OAAO,EAAE,sBAAsB;IAWnD,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,4BAA4B;YAetB,qBAAqB;YAuCrB,0BAA0B;IA2FxC,UAAU,CACR,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;YA+C1C,2BAA2B;IAYzC,OAAO,CAAC,yBAAyB;YAiBnB,2BAA2B;CAqU1C"}
|
|
@@ -11,6 +11,7 @@ import { parseLocalImports, } from "../../../transforms/esm/import-parser.js";
|
|
|
11
11
|
import { createFileSystem } from "../../../platform/compat/fs.js";
|
|
12
12
|
import { verifyCacheFileExists, writeCacheFile } from "../../../utils/cache-file-ops.js";
|
|
13
13
|
import { createError, toError } from "../../../errors/veryfront-error.js";
|
|
14
|
+
import { hashCodeHex } from "../../../utils/hash-utils.js";
|
|
14
15
|
import { rendererLogger } from "../../../utils/index.js";
|
|
15
16
|
import { withSpan } from "../../../observability/tracing/otlp-setup.js";
|
|
16
17
|
import { SpanNames } from "../../../observability/tracing/span-names.js";
|
|
@@ -253,7 +254,7 @@ export class SSRModuleLoader {
|
|
|
253
254
|
}
|
|
254
255
|
if (this.options.projectId && this.options.contentSourceId) {
|
|
255
256
|
const baseCacheDir = getMdxEsmCacheDir();
|
|
256
|
-
const projectKey =
|
|
257
|
+
const projectKey = hashCodeHex(this.options.projectId);
|
|
257
258
|
const sourceKey = this.options.contentSourceId;
|
|
258
259
|
const mdxCacheDir = join(baseCacheDir, projectKey, sourceKey);
|
|
259
260
|
const mdxCacheResult = await lookupMdxEsmCache(filePath, mdxCacheDir, this.options.projectDir, contentHash);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tmp-paths.d.ts","sourceRoot":"","sources":["../../../../../src/src/modules/react-loader/ssr-module-loader/tmp-paths.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"tmp-paths.d.ts","sourceRoot":"","sources":["../../../../../src/src/modules/react-loader/ssr-module-loader/tmp-paths.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,MAAM,GACtB,MAAM,CAGR;AAED,wBAAgB,eAAe,CAC7B,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,MAAM,GACtB,MAAM,CAGR;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,CAYR"}
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
* Temp directory and temp file path helpers for SSR module loader cache.
|
|
3
3
|
*/
|
|
4
4
|
import { join } from "../../../platform/compat/path/index.js";
|
|
5
|
+
import { hashCodeHex } from "../../../utils/hash-utils.js";
|
|
5
6
|
export function getTmpDirCacheKey(baseCacheDir, projectId, contentSourceId) {
|
|
6
|
-
const projectKey =
|
|
7
|
+
const projectKey = hashCodeHex(projectId);
|
|
7
8
|
return `${baseCacheDir}|${projectKey}|${contentSourceId}`;
|
|
8
9
|
}
|
|
9
10
|
export function buildTmpDirPath(baseCacheDir, projectId, contentSourceId) {
|
|
10
|
-
const projectKey =
|
|
11
|
+
const projectKey = hashCodeHex(projectId);
|
|
11
12
|
return join(baseCacheDir, projectKey, contentSourceId);
|
|
12
13
|
}
|
|
13
14
|
export function buildTempModulePath(tmpDir, filePath, projectDir, version, contentHash) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vf-module-resolver.d.ts","sourceRoot":"","sources":["../../../../../src/src/modules/react-loader/ssr-module-loader/vf-module-resolver.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"vf-module-resolver.d.ts","sourceRoot":"","sources":["../../../../../src/src/modules/react-loader/ssr-module-loader/vf-module-resolver.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAWzE,UAAU,cAAc;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,6BAA6B;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,cAAc,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,EAAE,CAelE;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,MAAM,CAAC,CA8CjB"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Extracts and resolves /_vf_modules/* imports into file:// cache paths.
|
|
5
5
|
*/
|
|
6
6
|
import { join } from "../../../platform/compat/path/index.js";
|
|
7
|
+
import { hashCodeHex } from "../../../utils/hash-utils.js";
|
|
7
8
|
import { rendererLogger } from "../../../utils/index.js";
|
|
8
9
|
import { getMdxEsmCacheDir } from "../../../utils/cache-dir.js";
|
|
9
10
|
import { createModuleFetcherContext, fetchAndCacheModule, } from "../../../transforms/mdx/esm-module-loader/module-fetcher/index.js";
|
|
@@ -40,7 +41,7 @@ export async function resolveVfModuleImports(code, options) {
|
|
|
40
41
|
paths: imports.map((i) => i.path).slice(0, 5),
|
|
41
42
|
});
|
|
42
43
|
const baseCacheDir = getMdxEsmCacheDir();
|
|
43
|
-
const projectKey =
|
|
44
|
+
const projectKey = hashCodeHex(options.projectId);
|
|
44
45
|
const esmCacheDir = join(baseCacheDir, projectKey, options.contentSourceId);
|
|
45
46
|
const fetcherContext = createModuleFetcherContext(esmCacheDir, options.adapter, options.projectDir, options.projectId, {
|
|
46
47
|
reactVersion: options.reactVersion,
|
|
@@ -6,6 +6,7 @@ export declare class FileListIndex {
|
|
|
6
6
|
private readonly getFileListCache?;
|
|
7
7
|
private index;
|
|
8
8
|
private indexKey;
|
|
9
|
+
private indexBuiltAt;
|
|
9
10
|
private readyPromise;
|
|
10
11
|
constructor(getFileListCache?: (() => Promise<Array<FileListCacheEntry> | undefined>) | undefined);
|
|
11
12
|
setReadyPromise(promise: Promise<void>): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-list-index.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/fs/veryfront/file-list-index.ts"],"names":[],"mappings":"AAIA,UAAU,kBAAkB;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;
|
|
1
|
+
{"version":3,"file":"file-list-index.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/fs/veryfront/file-list-index.ts"],"names":[],"mappings":"AAIA,UAAU,kBAAkB;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAeD,qBAAa,aAAa;IAOtB,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;IANpC,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,YAAY,CAA8B;gBAG/B,gBAAgB,CAAC,GAAE,MAAM,OAAO,CAAC,KAAK,CAAC,kBAAkB,CAAC,GAAG,SAAS,CAAC,aAAA;IAG1F,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAI7C,KAAK,IAAI,IAAI;IAUP,MAAM,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;YAkCnD,UAAU;CA0EzB"}
|
|
@@ -9,10 +9,12 @@ function hashPreview(content) {
|
|
|
9
9
|
function previewText(content, max = 80) {
|
|
10
10
|
return content.length > max ? `${content.slice(0, max)}...` : content;
|
|
11
11
|
}
|
|
12
|
+
const INDEX_STALENESS_LIMIT_MS = 5 * 60 * 1000; // 5 minutes
|
|
12
13
|
export class FileListIndex {
|
|
13
14
|
getFileListCache;
|
|
14
15
|
index = null;
|
|
15
16
|
indexKey = null;
|
|
17
|
+
indexBuiltAt = 0;
|
|
16
18
|
readyPromise = null;
|
|
17
19
|
constructor(getFileListCache) {
|
|
18
20
|
this.getFileListCache = getFileListCache;
|
|
@@ -26,6 +28,7 @@ export class FileListIndex {
|
|
|
26
28
|
const size = this.index.size;
|
|
27
29
|
this.index = null;
|
|
28
30
|
this.indexKey = null;
|
|
31
|
+
this.indexBuiltAt = 0;
|
|
29
32
|
logger.debug("Cleared file list index", { entriesCleared: size });
|
|
30
33
|
}
|
|
31
34
|
async lookup(normalizedPath) {
|
|
@@ -65,6 +68,27 @@ export class FileListIndex {
|
|
|
65
68
|
}
|
|
66
69
|
const fileList = await this.getFileListCache();
|
|
67
70
|
if (!fileList) {
|
|
71
|
+
// Cache entry expired or unavailable. If we already have a built index from a
|
|
72
|
+
// previous successful cache read, keep using it rather than forcing network fetches.
|
|
73
|
+
// The index stays valid until explicitly cleared via clear() (triggered by WebSocket pokes)
|
|
74
|
+
// or until INDEX_STALENESS_LIMIT_MS elapses (safety net for missed pokes).
|
|
75
|
+
if (this.index) {
|
|
76
|
+
const age = Date.now() - this.indexBuiltAt;
|
|
77
|
+
if (age < INDEX_STALENESS_LIMIT_MS) {
|
|
78
|
+
logger.debug("getOrBuildFileListIndex: cache expired, using existing in-memory index", {
|
|
79
|
+
indexSize: this.index.size,
|
|
80
|
+
indexAgeMs: age,
|
|
81
|
+
});
|
|
82
|
+
return this.index;
|
|
83
|
+
}
|
|
84
|
+
logger.debug("getOrBuildFileListIndex: in-memory index too stale, discarding", {
|
|
85
|
+
indexSize: this.index.size,
|
|
86
|
+
indexAgeMs: age,
|
|
87
|
+
staleLimitMs: INDEX_STALENESS_LIMIT_MS,
|
|
88
|
+
});
|
|
89
|
+
this.index = null;
|
|
90
|
+
this.indexKey = null;
|
|
91
|
+
}
|
|
68
92
|
logger.debug("[ReadOperations] getOrBuildFileListIndex: getFileListCache returned null/undefined");
|
|
69
93
|
return null;
|
|
70
94
|
}
|
|
@@ -77,8 +101,10 @@ export class FileListIndex {
|
|
|
77
101
|
sampleContentPreview: cacheCheckSample?.content?.slice(0, 200)?.replace(/\n/g, "\\n"),
|
|
78
102
|
});
|
|
79
103
|
const indexKey = `${fileList.length}:${fileList[0]?.path ?? ""}:${fileList[fileList.length - 1]?.path ?? ""}`;
|
|
80
|
-
if (this.index && this.indexKey === indexKey)
|
|
104
|
+
if (this.index && this.indexKey === indexKey) {
|
|
105
|
+
this.indexBuiltAt = Date.now();
|
|
81
106
|
return this.index;
|
|
107
|
+
}
|
|
82
108
|
const index = new Map();
|
|
83
109
|
for (const file of fileList) {
|
|
84
110
|
if (file.content)
|
|
@@ -86,6 +112,7 @@ export class FileListIndex {
|
|
|
86
112
|
}
|
|
87
113
|
this.index = index;
|
|
88
114
|
this.indexKey = indexKey;
|
|
115
|
+
this.indexBuiltAt = Date.now();
|
|
89
116
|
const sampleFile = fileList.find((f) => /welcome/i.test(f.path));
|
|
90
117
|
const sampleContent = sampleFile?.content;
|
|
91
118
|
logger.debug("Built file list index", {
|
|
@@ -28,6 +28,7 @@ export declare class WebSocketManager {
|
|
|
28
28
|
private selectiveInvalidationTimer;
|
|
29
29
|
private pendingChangedPaths;
|
|
30
30
|
private wsConnectionId;
|
|
31
|
+
private wsConsecutiveFailures;
|
|
31
32
|
private pokeMetrics;
|
|
32
33
|
constructor(deps: WebSocketDeps);
|
|
33
34
|
getPokeMetrics(): {
|
|
@@ -37,6 +38,7 @@ export declare class WebSocketManager {
|
|
|
37
38
|
connectionId: string | null;
|
|
38
39
|
};
|
|
39
40
|
connect(projectId: string): void;
|
|
41
|
+
private getReconnectDelay;
|
|
40
42
|
dispose(): void;
|
|
41
43
|
private handlePokeMessage;
|
|
42
44
|
private clearPersistentCacheForPublish;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websocket-manager.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/fs/veryfront/websocket-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,aAAa,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"websocket-manager.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/fs/veryfront/websocket-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,aAAa,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAsB/F,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,qBAAqB,EAAE,qBAAqB,CAAC;IAE7C,iBAAiB,EAAE,MAAM,sBAAsB,GAAG,IAAI,CAAC;IACvD,gBAAgB,EAAE,MAAM,aAAa,CAAC;IACtC,aAAa,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACxC,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,gBAAgB,EAAE,CAChB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,KAC7C,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB;AAED,qBAAa,gBAAgB;IAiBf,OAAO,CAAC,QAAQ,CAAC,IAAI;IAhBjC,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,gBAAgB,CAAsD;IAC9E,OAAO,CAAC,gBAAgB,CAAuD;IAC/E,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,iBAAiB,CAAsD;IAC/E,OAAO,CAAC,0BAA0B,CAAsD;IACxF,OAAO,CAAC,mBAAmB,CAAqB;IAEhD,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,qBAAqB,CAAK;IAClC,OAAO,CAAC,WAAW,CAIjB;gBAE2B,IAAI,EAAE,aAAa;IAEhD,cAAc,IAAI;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,sBAAsB,EAAE,MAAM,CAAC;QAC/B,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;KAC7B;IAID,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IA0EhC,OAAO,CAAC,iBAAiB;IAMzB,OAAO,IAAI,IAAI;IAwBf,OAAO,CAAC,iBAAiB;IAkJzB,OAAO,CAAC,8BAA8B;IA0GtC,OAAO,CAAC,oBAAoB;IAa5B,OAAO,CAAC,6BAA6B;YAiBvB,4BAA4B;YA2H5B,mBAAmB;IAmIjC,OAAO,CAAC,cAAc;IA4BtB,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,WAAW;CAyBpB"}
|
|
@@ -5,6 +5,8 @@ import { addPendingInvalidation, getPendingInvalidationsCount, removePendingInva
|
|
|
5
5
|
const logger = baseLogger.component("web-socket-manager");
|
|
6
6
|
const INVALIDATION_DEBOUNCE_MS = 100;
|
|
7
7
|
const WS_RECONNECT_DELAY_MS = 5000;
|
|
8
|
+
const WS_RECONNECT_MAX_DELAY_MS = 120000;
|
|
9
|
+
const WS_RECONNECT_MAX_FAILURES = 10;
|
|
8
10
|
const WS_HEARTBEAT_INTERVAL_MS = 60000;
|
|
9
11
|
const WS_HEARTBEAT_TIMEOUT_MS = 300000;
|
|
10
12
|
export class WebSocketManager {
|
|
@@ -17,6 +19,7 @@ export class WebSocketManager {
|
|
|
17
19
|
selectiveInvalidationTimer = null;
|
|
18
20
|
pendingChangedPaths = new Set();
|
|
19
21
|
wsConnectionId = null;
|
|
22
|
+
wsConsecutiveFailures = 0;
|
|
20
23
|
pokeMetrics = {
|
|
21
24
|
received: 0,
|
|
22
25
|
invalidationsTriggered: 0,
|
|
@@ -30,6 +33,15 @@ export class WebSocketManager {
|
|
|
30
33
|
}
|
|
31
34
|
connect(projectId) {
|
|
32
35
|
this.cleanupTimers();
|
|
36
|
+
if (this.wsConsecutiveFailures >= WS_RECONNECT_MAX_FAILURES) {
|
|
37
|
+
logger.warn("WebSocket reconnect failure cap reached, resetting failure counter", {
|
|
38
|
+
consecutiveFailures: this.wsConsecutiveFailures,
|
|
39
|
+
maxFailures: WS_RECONNECT_MAX_FAILURES,
|
|
40
|
+
cappedDelayMs: WS_RECONNECT_MAX_DELAY_MS,
|
|
41
|
+
projectId,
|
|
42
|
+
});
|
|
43
|
+
this.wsConsecutiveFailures = 0;
|
|
44
|
+
}
|
|
33
45
|
const wsUrl = this.deps.apiBaseUrl
|
|
34
46
|
.replace(/^http:/, "ws:")
|
|
35
47
|
.replace(/^https:/, "wss:")
|
|
@@ -37,11 +49,13 @@ export class WebSocketManager {
|
|
|
37
49
|
const url = `${wsUrl}/ws/${projectId}/events?token=${this.deps.apiToken}`;
|
|
38
50
|
logger.debug("Connecting to WebSocket", {
|
|
39
51
|
url: url.replace(this.deps.apiToken, "***"),
|
|
52
|
+
consecutiveFailures: this.wsConsecutiveFailures,
|
|
40
53
|
});
|
|
41
54
|
try {
|
|
42
55
|
this.ws = new WebSocket(url);
|
|
43
56
|
this.wsConnectionId = dntShim.crypto.randomUUID().slice(0, 8);
|
|
44
57
|
this.ws.onopen = () => {
|
|
58
|
+
this.wsConsecutiveFailures = 0;
|
|
45
59
|
logger.debug("WebSocket connected to events channel", {
|
|
46
60
|
projectId,
|
|
47
61
|
connectionId: this.wsConnectionId,
|
|
@@ -57,24 +71,37 @@ export class WebSocketManager {
|
|
|
57
71
|
this.handlePokeMessage(event);
|
|
58
72
|
};
|
|
59
73
|
this.ws.onclose = () => {
|
|
74
|
+
this.wsConsecutiveFailures++;
|
|
75
|
+
const delay = this.getReconnectDelay();
|
|
60
76
|
logger.debug("WebSocket closed, reconnecting", {
|
|
61
|
-
delayMs:
|
|
77
|
+
delayMs: delay,
|
|
62
78
|
connectionId: this.wsConnectionId,
|
|
63
79
|
totalPokesReceived: this.pokeMetrics.received,
|
|
80
|
+
consecutiveFailures: this.wsConsecutiveFailures,
|
|
64
81
|
});
|
|
65
82
|
this.wsConnectionId = null;
|
|
66
83
|
this.cleanupTimers();
|
|
67
|
-
this.wsReconnectTimer = dntShim.setTimeout(() => this.connect(projectId),
|
|
84
|
+
this.wsReconnectTimer = dntShim.setTimeout(() => this.connect(projectId), delay);
|
|
68
85
|
};
|
|
69
86
|
this.ws.onerror = (error) => {
|
|
70
87
|
logger.warn("WebSocket error", { error });
|
|
71
88
|
};
|
|
72
89
|
}
|
|
73
90
|
catch (error) {
|
|
74
|
-
|
|
75
|
-
|
|
91
|
+
this.wsConsecutiveFailures++;
|
|
92
|
+
const delay = this.getReconnectDelay();
|
|
93
|
+
logger.warn("Failed to connect WebSocket", {
|
|
94
|
+
error,
|
|
95
|
+
consecutiveFailures: this.wsConsecutiveFailures,
|
|
96
|
+
});
|
|
97
|
+
this.wsReconnectTimer = dntShim.setTimeout(() => this.connect(projectId), delay);
|
|
76
98
|
}
|
|
77
99
|
}
|
|
100
|
+
getReconnectDelay() {
|
|
101
|
+
// Exponential backoff: 5s, 10s, 20s, 40s, 80s, capped at 120s
|
|
102
|
+
const delay = WS_RECONNECT_DELAY_MS * Math.pow(2, this.wsConsecutiveFailures - 1);
|
|
103
|
+
return Math.min(delay, WS_RECONNECT_MAX_DELAY_MS);
|
|
104
|
+
}
|
|
78
105
|
dispose() {
|
|
79
106
|
this.cleanupTimers();
|
|
80
107
|
if (this.invalidationTimer) {
|
|
@@ -529,13 +556,19 @@ export class WebSocketManager {
|
|
|
529
556
|
logger.warn("WebSocket heartbeat timeout, reconnecting", {
|
|
530
557
|
timeSinceLastPong,
|
|
531
558
|
});
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
559
|
+
// Detach onclose before closing to prevent double-reconnect:
|
|
560
|
+
// ws.close() triggers onclose asynchronously, which would increment
|
|
561
|
+
// the failure counter and schedule a separate reconnect timer.
|
|
562
|
+
if (this.ws) {
|
|
563
|
+
this.ws.onclose = null;
|
|
564
|
+
try {
|
|
565
|
+
this.ws.close();
|
|
566
|
+
}
|
|
567
|
+
catch (error) {
|
|
568
|
+
logger.error("WebSocket close failed during heartbeat timeout", {
|
|
569
|
+
error: error instanceof Error ? error.message : String(error),
|
|
570
|
+
});
|
|
571
|
+
}
|
|
539
572
|
}
|
|
540
573
|
this.cleanupTimers();
|
|
541
574
|
this.connect(projectId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-executor.d.ts","sourceRoot":"","sources":["../../../../src/src/routing/api/route-executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAClD,OAAO,KAAK,EAAqB,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEzF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,KAAK,EACV,QAAQ,EAKT,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"route-executor.d.ts","sourceRoot":"","sources":["../../../../src/src/routing/api/route-executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAClD,OAAO,KAAK,EAAqB,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEzF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,KAAK,EACV,QAAQ,EAKT,MAAM,0BAA0B,CAAC;AA0GlC,wBAAgB,eAAe,CAC7B,OAAO,EAAE,QAAQ,EACjB,OAAO,EAAE,OAAO,CAAC,OAAO,EACxB,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CA4B3B;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,QAAQ,EACjB,OAAO,EAAE,OAAO,CAAC,OAAO,EACxB,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,EACvB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAsB3B"}
|
|
@@ -44,9 +44,34 @@ function createProjectScopedFs(fs, projectDir) {
|
|
|
44
44
|
resolveFile: fs.resolveFile ? (path) => fs.resolveFile(resolvePath(path)) : undefined,
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Check if an object is a cross-context Response (e.g. Deno native Response
|
|
49
|
+
* when this code runs in the npm package context with a different constructor).
|
|
50
|
+
*/
|
|
51
|
+
function isCrossContextResponse(value) {
|
|
52
|
+
if (value == null || typeof value !== "object")
|
|
53
|
+
return false;
|
|
54
|
+
const r = value;
|
|
55
|
+
return (typeof r.status === "number" &&
|
|
56
|
+
typeof r.headers === "object" &&
|
|
57
|
+
r.headers !== null &&
|
|
58
|
+
typeof r.headers.get === "function" &&
|
|
59
|
+
typeof r.text === "function" &&
|
|
60
|
+
typeof r.arrayBuffer === "function");
|
|
61
|
+
}
|
|
47
62
|
function validateResponse(response) {
|
|
48
63
|
if (response instanceof dntShim.Response)
|
|
49
|
-
return;
|
|
64
|
+
return response;
|
|
65
|
+
// Normalize cross-context Response objects into a real Response so downstream
|
|
66
|
+
// code (toHeadResponse, applyCORSHeaders, withHeaders) always receives a
|
|
67
|
+
// genuine instance with correct body, headers, and status.
|
|
68
|
+
if (isCrossContextResponse(response)) {
|
|
69
|
+
return new dntShim.Response(response.body, {
|
|
70
|
+
status: response.status,
|
|
71
|
+
statusText: response.statusText,
|
|
72
|
+
headers: response.headers,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
50
75
|
throw toError(createError({
|
|
51
76
|
type: "api",
|
|
52
77
|
message: "API handler must return a Response",
|
|
@@ -69,8 +94,7 @@ export function executeAppRoute(handler, request, match, pathname, adapter) {
|
|
|
69
94
|
return createAppRouteMethodNotAllowed(handlerModule);
|
|
70
95
|
try {
|
|
71
96
|
const appContext = { params: normalizeParams(match.params) };
|
|
72
|
-
const response = await resolvedFn(request, appContext);
|
|
73
|
-
validateResponse(response);
|
|
97
|
+
const response = validateResponse(await resolvedFn(request, appContext));
|
|
74
98
|
return method === "HEAD" ? toHeadResponse(response) : response;
|
|
75
99
|
}
|
|
76
100
|
catch (error) {
|
|
@@ -88,9 +112,7 @@ export function executePagesRoute(handler, request, match, pathname, adapter, pr
|
|
|
88
112
|
try {
|
|
89
113
|
const fs = projectDir ? createProjectScopedFs(adapter.fs, projectDir) : adapter.fs;
|
|
90
114
|
const ctx = createContext(request, match, fs);
|
|
91
|
-
|
|
92
|
-
validateResponse(response);
|
|
93
|
-
return response;
|
|
115
|
+
return validateResponse(await methodHandler(ctx));
|
|
94
116
|
}
|
|
95
117
|
catch (error) {
|
|
96
118
|
return handleAPIError(error, pathname, adapter);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../../../src/src/server/context/request-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAIlD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,SAAS,GAAG,YAAY,CAAC;CAChC;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,GAAG,cAAc,
|
|
1
|
+
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../../../src/src/server/context/request-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAIlD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,SAAS,GAAG,YAAY,CAAC;CAChC;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,GAAG,cAAc,CAwBzE;AAED,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,cAAc,EACnB,cAAc,CAAC,EAAE,OAAO,GACvB,MAAM,GAAG,YAAY,GAAG,WAAW,CAIrC;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,cAAc,EAAE,cAAc,CAAC,EAAE,OAAO,GAAG,OAAO,CAExF;AAED,wBAAgB,uBAAuB,CAAC,GAAG,CAAC,EAAE,cAAc,EAAE,cAAc,CAAC,EAAE,OAAO,GAAG,OAAO,CAG/F"}
|
|
@@ -9,7 +9,8 @@ export function createRequestContext(req) {
|
|
|
9
9
|
const effectiveHost = forwardedHost ?? hostHeader ?? hostname;
|
|
10
10
|
const parsed = parseProjectDomain(effectiveHost);
|
|
11
11
|
const xEnvironment = req.headers.get("x-environment");
|
|
12
|
-
const mode =
|
|
12
|
+
const mode = parsed.environment === "preview" ||
|
|
13
|
+
effectiveHost.includes(".preview.") ||
|
|
13
14
|
xEnvironment === "preview"
|
|
14
15
|
? "preview"
|
|
15
16
|
: "production";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../../src/src/server/dev-server/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../../src/src/server/dev-server/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAclD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAkCvD,qBAAa,SAAS;IAiBR,OAAO,CAAC,OAAO;IAhB3B,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,iBAAiB,CAAqB;IAC9C,OAAO,CAAC,cAAc,CAAC,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,cAAc,CAAC,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,CAAsD;IACvE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,iBAAiB,CAAC,CAAa;IACvC,OAAO,CAAC,qBAAqB,CAAC,CAAa;IAC3C,OAAO,CAAC,8BAA8B,CAAC,CAAa;gBAEhC,OAAO,EAAE,gBAAgB;IAQ7C,OAAO,CAAC,OAAO;YAID,YAAY;IAWpB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAqL5B,sEAAsE;IACtE,IAAI,OAAO,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAGjE;IAED,OAAO,CAAC,oBAAoB;YAcd,cAAc;YAiBd,yBAAyB;YAoBzB,uBAAuB;YA4BvB,wBAAwB;IAkBtC,OAAO,CAAC,kBAAkB;IAuBpB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;YAarB,iBAAiB;IAoC/B,qBAAqB,IAAI,UAAU,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,GAAG,IAAI;IAIlE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CA6B5B"}
|
|
@@ -7,6 +7,8 @@ import { ComponentRegistry } from "../../modules/component-registry/index.js";
|
|
|
7
7
|
import { MiddlewarePipeline } from "../../middleware/core/pipeline/index.js";
|
|
8
8
|
import { bootstrapDev } from "../bootstrap.js";
|
|
9
9
|
import { ReloadNotifier } from "../reload-notifier.js";
|
|
10
|
+
import { broadcastUpdate } from "../handlers/preview/hmr-message-router.js";
|
|
11
|
+
import { HMRHandler } from "../handlers/preview/hmr.handler.js";
|
|
10
12
|
import { RequestHandler } from "./request-handler.js";
|
|
11
13
|
import { setupMiddleware } from "./middleware.js";
|
|
12
14
|
import { RouteDiscovery } from "./route-discovery.js";
|
|
@@ -50,6 +52,7 @@ export class DevServer {
|
|
|
50
52
|
_isReady = false;
|
|
51
53
|
reloadUnsubscribe;
|
|
52
54
|
invalidateUnsubscribe;
|
|
55
|
+
releaseExternalBroadcastSource;
|
|
53
56
|
constructor(options) {
|
|
54
57
|
this.options = options;
|
|
55
58
|
this.ready = new Promise((resolve) => {
|
|
@@ -98,6 +101,9 @@ export class DevServer {
|
|
|
98
101
|
hmr: this.options.enableHMR,
|
|
99
102
|
fastRefresh: this.options.enableFastRefresh,
|
|
100
103
|
});
|
|
104
|
+
if (this.options.hmrPort !== undefined) {
|
|
105
|
+
devServerLog.warn("`hmrPort` is deprecated and ignored. HMR now uses /_ws on the main dev server port.", { hmrPort: this.options.hmrPort, serverPort: this.options.port });
|
|
106
|
+
}
|
|
101
107
|
// Set VERYFRONT_DEV_PORT for ESM module loader HTTP fallback
|
|
102
108
|
// This ensures the correct port is used when fetching modules via localhost
|
|
103
109
|
setEnv("VERYFRONT_DEV_PORT", String(this.options.port));
|
|
@@ -125,7 +131,22 @@ export class DevServer {
|
|
|
125
131
|
devServerLog.debug("INVALIDATE callback triggered - clearing runtime handler");
|
|
126
132
|
this.requestHandler?.invalidateRuntimeHandler();
|
|
127
133
|
});
|
|
128
|
-
|
|
134
|
+
// Subscribe to debounced reload for broadcasting updates to connected HMR clients.
|
|
135
|
+
// This subscription must be eagerly registered here rather than lazily inside
|
|
136
|
+
// HMRHandler.initialize(), because HMRHandler.initialize() only runs when the
|
|
137
|
+
// first /_ws WebSocket request arrives. If that connection fails or hasn't
|
|
138
|
+
// happened yet, file changes are silently lost.
|
|
139
|
+
this.releaseExternalBroadcastSource = HMRHandler.registerExternalBroadcastSource();
|
|
140
|
+
this.reloadUnsubscribe = ReloadNotifier.subscribe((changedPaths, project) => {
|
|
141
|
+
hmrLog.debug("RELOAD callback triggered - broadcasting to HMR clients", {
|
|
142
|
+
changedPaths,
|
|
143
|
+
projectSlug: project?.projectSlug,
|
|
144
|
+
});
|
|
145
|
+
// Broadcast without projectSlug filter so that connectHMR() clients
|
|
146
|
+
// (which are registered without a projectSlug) also receive updates.
|
|
147
|
+
broadcastUpdate(changedPaths);
|
|
148
|
+
});
|
|
149
|
+
hmrLog.debug("ReloadNotifier subscriptions registered (invalidate + reload broadcast)");
|
|
129
150
|
}
|
|
130
151
|
const moduleServerUrl = buildLocalhostUrl(this.options.port);
|
|
131
152
|
const vendorBundleHash = "dev-vendor-bundle";
|
|
@@ -334,6 +355,7 @@ export class DevServer {
|
|
|
334
355
|
logger.info("Shutting down dev server...");
|
|
335
356
|
this.reloadUnsubscribe?.();
|
|
336
357
|
this.invalidateUnsubscribe?.();
|
|
358
|
+
this.releaseExternalBroadcastSource?.();
|
|
337
359
|
if (this.fileWatchSetup) {
|
|
338
360
|
const metrics = this.fileWatchSetup.getMetrics();
|
|
339
361
|
if (metrics) {
|
|
@@ -6,6 +6,7 @@ export interface DevServerOptions {
|
|
|
6
6
|
handlerOnly?: boolean;
|
|
7
7
|
/** 0.0.0.0 = all interfaces, 127.0.0.1 = localhost only */
|
|
8
8
|
bindAddress?: string;
|
|
9
|
+
/** @deprecated Ignored: HMR now uses /_ws on the main dev server port. */
|
|
9
10
|
hmrPort?: number;
|
|
10
11
|
moduleServerPort?: number;
|
|
11
12
|
enableHMR?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/src/server/dev-server/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAClD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,mGAAmG;IACnG,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1F,sFAAsF;IACtF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,KAAK,GAAG,OAAO,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,MAAM,CAAC;CAC9B"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/src/server/dev-server/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAClD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,mGAAmG;IACnG,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1F,sFAAsF;IACtF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,KAAK,GAAG,OAAO,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,MAAM,CAAC;CAC9B"}
|
|
@@ -5,6 +5,7 @@ export type { HMRClientInfo } from "./hmr-client-manager.js";
|
|
|
5
5
|
export declare class HMRHandler extends BaseHandler {
|
|
6
6
|
private static rateLimiter;
|
|
7
7
|
private static reloadUnsubscribe;
|
|
8
|
+
private static externalBroadcastSourceCount;
|
|
8
9
|
private static initialized;
|
|
9
10
|
metadata: HandlerMetadata;
|
|
10
11
|
private static initialize;
|
|
@@ -23,6 +24,7 @@ export declare class HMRHandler extends BaseHandler {
|
|
|
23
24
|
messagesForwarded: number;
|
|
24
25
|
lastBroadcastTime: number;
|
|
25
26
|
};
|
|
27
|
+
static registerExternalBroadcastSource(): () => void;
|
|
26
28
|
static shutdown(): void;
|
|
27
29
|
private static getMessageSize;
|
|
28
30
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hmr.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/preview/hmr.handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AASrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,eAAe,EAEpB,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"hmr.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/preview/hmr.handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AASrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,eAAe,EAEpB,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAmBrB,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAK7D,qBAAa,UAAW,SAAQ,WAAW;IACzC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAgD;IAC1E,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAA6B;IAC7D,OAAO,CAAC,MAAM,CAAC,4BAA4B,CAAK;IAChD,OAAO,CAAC,MAAM,CAAC,WAAW,CAAS;IAEnC,QAAQ,EAAE,eAAe,CAKvB;IAEF,OAAO,CAAC,MAAM,CAAC,UAAU;IAsCzB,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IA0JzE;;;;;OAKG;YACW,wBAAwB;IAuCtC,MAAM,CAAC,cAAc,IAAI,MAAM;IAI/B,MAAM,CAAC,UAAU,IAAI;QACnB,OAAO,EAAE,MAAM,CAAC;QAChB,cAAc,EAAE,MAAM,CAAC;QACvB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,iBAAiB,EAAE,MAAM,CAAC;KAC3B;IAID,MAAM,CAAC,+BAA+B,IAAI,MAAM,IAAI;IAWpD,MAAM,CAAC,QAAQ,IAAI,IAAI;IAcvB,OAAO,CAAC,MAAM,CAAC,cAAc;CAO9B"}
|