veryfront 0.1.215 → 0.1.217
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/README.md +1 -1
- package/esm/cli/commands/extension/command-help.d.ts +3 -0
- package/esm/cli/commands/extension/command-help.d.ts.map +1 -0
- package/esm/cli/commands/extension/command-help.js +16 -0
- package/esm/cli/commands/extension/handler.d.ts +3 -0
- package/esm/cli/commands/extension/handler.d.ts.map +1 -0
- package/esm/cli/commands/extension/handler.js +36 -0
- package/esm/cli/commands/extension/init-command.d.ts +19 -0
- package/esm/cli/commands/extension/init-command.d.ts.map +1 -0
- package/esm/cli/commands/extension/init-command.js +122 -0
- package/esm/cli/commands/extension/validate-command.d.ts +13 -0
- package/esm/cli/commands/extension/validate-command.d.ts.map +1 -0
- package/esm/cli/commands/extension/validate-command.js +62 -0
- package/esm/cli/commands/generate/integration-generator-helpers.d.ts +35 -0
- package/esm/cli/commands/generate/integration-generator-helpers.d.ts.map +1 -0
- package/esm/cli/commands/generate/integration-generator-helpers.js +123 -0
- package/esm/cli/commands/generate/integration-generator.d.ts +1 -2
- package/esm/cli/commands/generate/integration-generator.d.ts.map +1 -1
- package/esm/cli/commands/generate/integration-generator.js +1 -123
- package/esm/cli/commands/knowledge/command-helpers.d.ts +48 -0
- package/esm/cli/commands/knowledge/command-helpers.d.ts.map +1 -0
- package/esm/cli/commands/knowledge/command-helpers.js +216 -0
- package/esm/cli/commands/knowledge/command.d.ts +12 -17
- package/esm/cli/commands/knowledge/command.d.ts.map +1 -1
- package/esm/cli/commands/knowledge/command.js +26 -214
- package/esm/cli/help/command-definitions.d.ts.map +1 -1
- package/esm/cli/help/command-definitions.js +2 -0
- package/esm/cli/mcp/remote-file-tool-helpers.d.ts +5 -0
- package/esm/cli/mcp/remote-file-tool-helpers.d.ts.map +1 -0
- package/esm/cli/mcp/remote-file-tool-helpers.js +22 -0
- package/esm/cli/mcp/remote-file-tools.d.ts.map +1 -1
- package/esm/cli/mcp/remote-file-tools.js +1 -22
- package/esm/cli/router.d.ts.map +1 -1
- package/esm/cli/router.js +2 -0
- package/esm/cli/templates/integration-loader-helpers.d.ts +8 -0
- package/esm/cli/templates/integration-loader-helpers.d.ts.map +1 -0
- package/esm/cli/templates/integration-loader-helpers.js +29 -0
- package/esm/cli/templates/integration-loader.d.ts.map +1 -1
- package/esm/cli/templates/integration-loader.js +5 -21
- package/esm/cli/templates/manifest.d.ts +1 -0
- package/esm/cli/templates/manifest.js +2 -1
- package/esm/deno.d.ts +3 -0
- package/esm/deno.js +5 -2
- package/esm/src/agent/runtime/index.d.ts.map +1 -1
- package/esm/src/agent/runtime/index.js +48 -90
- package/esm/src/chat/ag-ui-helpers.d.ts +17 -0
- package/esm/src/chat/ag-ui-helpers.d.ts.map +1 -0
- package/esm/src/chat/ag-ui-helpers.js +111 -0
- package/esm/src/chat/ag-ui.d.ts.map +1 -1
- package/esm/src/chat/ag-ui.js +1 -111
- package/esm/src/config/schemas/config.schema.d.ts +1 -0
- package/esm/src/config/schemas/config.schema.d.ts.map +1 -1
- package/esm/src/config/schemas/config.schema.js +11 -0
- package/esm/src/config/schemas/index.d.ts +11 -1
- package/esm/src/config/schemas/index.d.ts.map +1 -1
- package/esm/src/errors/error-registry-helpers.d.ts +6 -0
- package/esm/src/errors/error-registry-helpers.d.ts.map +1 -0
- package/esm/src/errors/error-registry-helpers.js +9 -0
- package/esm/src/errors/error-registry.d.ts.map +1 -1
- package/esm/src/errors/error-registry.js +4 -3
- package/esm/src/extensions/capabilities.d.ts +20 -0
- package/esm/src/extensions/capabilities.d.ts.map +1 -0
- package/esm/src/extensions/capabilities.js +77 -0
- package/esm/src/extensions/contracts.d.ts +10 -0
- package/esm/src/extensions/contracts.d.ts.map +1 -0
- package/esm/src/extensions/contracts.js +28 -0
- package/esm/src/extensions/discovery.d.ts +48 -0
- package/esm/src/extensions/discovery.d.ts.map +1 -0
- package/esm/src/extensions/discovery.js +179 -0
- package/esm/src/extensions/errors.d.ts +10 -0
- package/esm/src/extensions/errors.d.ts.map +1 -0
- package/esm/src/extensions/errors.js +34 -0
- package/esm/src/extensions/factory-loader.d.ts +29 -0
- package/esm/src/extensions/factory-loader.d.ts.map +1 -0
- package/esm/src/extensions/factory-loader.js +63 -0
- package/esm/src/extensions/index.d.ts +37 -0
- package/esm/src/extensions/index.d.ts.map +1 -0
- package/esm/src/extensions/index.js +41 -0
- package/esm/src/extensions/interfaces/ai-model-provider.d.ts +94 -0
- package/esm/src/extensions/interfaces/ai-model-provider.d.ts.map +1 -0
- package/esm/src/extensions/interfaces/ai-model-provider.js +8 -0
- package/esm/src/extensions/interfaces/auth-provider.d.ts +49 -0
- package/esm/src/extensions/interfaces/auth-provider.d.ts.map +1 -0
- package/esm/src/extensions/interfaces/auth-provider.js +8 -0
- package/esm/src/extensions/interfaces/bundler.d.ts +118 -0
- package/esm/src/extensions/interfaces/bundler.d.ts.map +1 -0
- package/esm/src/extensions/interfaces/bundler.js +8 -0
- package/esm/src/extensions/interfaces/cache-store.d.ts +27 -0
- package/esm/src/extensions/interfaces/cache-store.d.ts.map +1 -0
- package/esm/src/extensions/interfaces/cache-store.js +8 -0
- package/esm/src/extensions/interfaces/code-parser.d.ts +76 -0
- package/esm/src/extensions/interfaces/code-parser.d.ts.map +1 -0
- package/esm/src/extensions/interfaces/code-parser.js +8 -0
- package/esm/src/extensions/interfaces/content-transformer.d.ts +40 -0
- package/esm/src/extensions/interfaces/content-transformer.d.ts.map +1 -0
- package/esm/src/extensions/interfaces/content-transformer.js +8 -0
- package/esm/src/extensions/interfaces/css-processor.d.ts +38 -0
- package/esm/src/extensions/interfaces/css-processor.d.ts.map +1 -0
- package/esm/src/extensions/interfaces/css-processor.js +8 -0
- package/esm/src/extensions/interfaces/database-client.d.ts +31 -0
- package/esm/src/extensions/interfaces/database-client.d.ts.map +1 -0
- package/esm/src/extensions/interfaces/database-client.js +8 -0
- package/esm/src/extensions/interfaces/embedding-provider.d.ts +37 -0
- package/esm/src/extensions/interfaces/embedding-provider.d.ts.map +1 -0
- package/esm/src/extensions/interfaces/embedding-provider.js +8 -0
- package/esm/src/extensions/interfaces/index.d.ts +21 -0
- package/esm/src/extensions/interfaces/index.d.ts.map +1 -0
- package/esm/src/extensions/interfaces/index.js +9 -0
- package/esm/src/extensions/interfaces/node-compat.d.ts +25 -0
- package/esm/src/extensions/interfaces/node-compat.d.ts.map +1 -0
- package/esm/src/extensions/interfaces/node-compat.js +8 -0
- package/esm/src/extensions/interfaces/schema-validator.d.ts +46 -0
- package/esm/src/extensions/interfaces/schema-validator.d.ts.map +1 -0
- package/esm/src/extensions/interfaces/schema-validator.js +8 -0
- package/esm/src/extensions/interfaces/tracing-exporter.d.ts +44 -0
- package/esm/src/extensions/interfaces/tracing-exporter.d.ts.map +1 -0
- package/esm/src/extensions/interfaces/tracing-exporter.js +8 -0
- package/esm/src/extensions/loader.d.ts +33 -0
- package/esm/src/extensions/loader.d.ts.map +1 -0
- package/esm/src/extensions/loader.js +209 -0
- package/esm/src/extensions/orchestrate.d.ts +54 -0
- package/esm/src/extensions/orchestrate.d.ts.map +1 -0
- package/esm/src/extensions/orchestrate.js +116 -0
- package/esm/src/extensions/recommendations.d.ts +7 -0
- package/esm/src/extensions/recommendations.d.ts.map +1 -0
- package/esm/src/extensions/recommendations.js +22 -0
- package/esm/src/extensions/types.d.ts +47 -0
- package/esm/src/extensions/types.d.ts.map +1 -0
- package/esm/src/extensions/types.js +6 -0
- package/esm/src/extensions/validation.d.ts +44 -0
- package/esm/src/extensions/validation.d.ts.map +1 -0
- package/esm/src/extensions/validation.js +115 -0
- package/esm/src/html/styles-builder/plugin-loader.d.ts.map +1 -1
- package/esm/src/html/styles-builder/plugin-loader.js +23 -0
- package/esm/src/html/styles-builder/tailwind-plugin-allowlist.d.ts +29 -0
- package/esm/src/html/styles-builder/tailwind-plugin-allowlist.d.ts.map +1 -0
- package/esm/src/html/styles-builder/tailwind-plugin-allowlist.js +48 -0
- package/esm/src/modules/react-loader/ssr-module-loader/loader-helpers.d.ts +15 -0
- package/esm/src/modules/react-loader/ssr-module-loader/loader-helpers.d.ts.map +1 -0
- package/esm/src/modules/react-loader/ssr-module-loader/loader-helpers.js +22 -0
- package/esm/src/modules/react-loader/ssr-module-loader/loader.d.ts +0 -2
- 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 +4 -24
- package/esm/src/platform/adapters/fs/veryfront/adapter-helpers.d.ts +19 -0
- package/esm/src/platform/adapters/fs/veryfront/adapter-helpers.d.ts.map +1 -0
- package/esm/src/platform/adapters/fs/veryfront/adapter-helpers.js +26 -0
- package/esm/src/platform/adapters/fs/veryfront/adapter.d.ts.map +1 -1
- package/esm/src/platform/adapters/fs/veryfront/adapter.js +4 -20
- package/esm/src/platform/adapters/fs/veryfront/read-operations-helpers.d.ts +1 -0
- package/esm/src/platform/adapters/fs/veryfront/read-operations-helpers.d.ts.map +1 -1
- package/esm/src/platform/adapters/fs/veryfront/read-operations-helpers.js +3 -0
- package/esm/src/platform/adapters/fs/veryfront/read-operations.d.ts.map +1 -1
- package/esm/src/platform/adapters/fs/veryfront/read-operations.js +4 -7
- package/esm/src/platform/adapters/fs/veryfront/websocket-manager-helpers.d.ts +28 -0
- package/esm/src/platform/adapters/fs/veryfront/websocket-manager-helpers.d.ts.map +1 -0
- package/esm/src/platform/adapters/fs/veryfront/websocket-manager-helpers.js +41 -0
- package/esm/src/platform/adapters/fs/veryfront/websocket-manager.d.ts +1 -4
- package/esm/src/platform/adapters/fs/veryfront/websocket-manager.d.ts.map +1 -1
- package/esm/src/platform/adapters/fs/veryfront/websocket-manager.js +7 -40
- package/esm/src/platform/compat/process/command.d.ts +31 -0
- package/esm/src/platform/compat/process/command.d.ts.map +1 -0
- package/esm/src/platform/compat/process/command.js +193 -0
- package/esm/src/platform/compat/process/env.d.ts +31 -0
- package/esm/src/platform/compat/process/env.d.ts.map +1 -0
- package/esm/src/platform/compat/process/env.js +175 -0
- package/esm/src/platform/compat/process/lifecycle.d.ts +98 -0
- package/esm/src/platform/compat/process/lifecycle.d.ts.map +1 -0
- package/esm/src/platform/compat/process/lifecycle.js +305 -0
- package/esm/src/platform/compat/process/runtime-process.d.ts +10 -0
- package/esm/src/platform/compat/process/runtime-process.d.ts.map +1 -0
- package/esm/src/platform/compat/process/runtime-process.js +24 -0
- package/esm/src/platform/compat/process.d.ts +4 -165
- package/esm/src/platform/compat/process.d.ts.map +1 -1
- package/esm/src/platform/compat/process.js +4 -682
- package/esm/src/platform/index.d.ts +1 -1
- package/esm/src/platform/index.d.ts.map +1 -1
- package/esm/src/provider/runtime-loader/provider-endpoints.d.ts +8 -0
- package/esm/src/provider/runtime-loader/provider-endpoints.d.ts.map +1 -0
- package/esm/src/provider/runtime-loader/provider-endpoints.js +27 -0
- package/esm/src/provider/runtime-loader/provider-request-init.d.ts +32 -0
- package/esm/src/provider/runtime-loader/provider-request-init.d.ts.map +1 -0
- package/esm/src/provider/runtime-loader/provider-request-init.js +67 -0
- package/esm/src/provider/runtime-loader/tool-input-status.d.ts +17 -0
- package/esm/src/provider/runtime-loader/tool-input-status.d.ts.map +1 -0
- package/esm/src/provider/runtime-loader/tool-input-status.js +155 -0
- package/esm/src/provider/runtime-loader.d.ts +2 -3
- package/esm/src/provider/runtime-loader.d.ts.map +1 -1
- package/esm/src/provider/runtime-loader.js +92 -291
- package/esm/src/proxy/handler.d.ts.map +1 -1
- package/esm/src/proxy/handler.js +14 -0
- package/esm/src/rendering/orchestrator/pipeline-helpers.d.ts +8 -0
- package/esm/src/rendering/orchestrator/pipeline-helpers.d.ts.map +1 -0
- package/esm/src/rendering/orchestrator/pipeline-helpers.js +20 -0
- package/esm/src/rendering/orchestrator/pipeline.d.ts +0 -3
- package/esm/src/rendering/orchestrator/pipeline.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/pipeline.js +4 -22
- package/esm/src/routing/api/module-loader/loader-helpers.d.ts +10 -0
- package/esm/src/routing/api/module-loader/loader-helpers.d.ts.map +1 -0
- package/esm/src/routing/api/module-loader/loader-helpers.js +62 -0
- package/esm/src/routing/api/module-loader/loader.d.ts +1 -1
- package/esm/src/routing/api/module-loader/loader.d.ts.map +1 -1
- package/esm/src/routing/api/module-loader/loader.js +2 -60
- package/esm/src/server/bootstrap.d.ts +22 -2
- package/esm/src/server/bootstrap.d.ts.map +1 -1
- package/esm/src/server/bootstrap.js +67 -5
- package/esm/src/server/dev-ui/manifest.d.ts +2 -0
- package/esm/src/server/dev-ui/manifest.js +3 -1
- package/esm/src/server/handlers/request/api/project-discovery.d.ts.map +1 -1
- package/esm/src/server/handlers/request/api/project-discovery.js +14 -8
- package/esm/src/server/production-server.js +1 -1
- package/esm/src/server/services/rsc/endpoints/rsc-bundles.generated.d.ts.map +1 -1
- package/esm/src/server/services/rsc/endpoints/rsc-bundles.generated.js +2 -2
- package/esm/src/server/utils/domain-parser.d.ts.map +1 -1
- package/esm/src/server/utils/domain-parser.js +4 -0
- package/esm/src/studio/bridge/bridge-bundle.generated.d.ts.map +1 -1
- package/esm/src/studio/bridge/bridge-bundle.generated.js +1 -1
- package/esm/src/tool/index.d.ts +1 -1
- package/esm/src/tool/index.d.ts.map +1 -1
- package/esm/src/tool/types.d.ts +20 -0
- package/esm/src/tool/types.d.ts.map +1 -1
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +7 -1
- package/src/cli/commands/extension/command-help.ts +18 -0
- package/src/cli/commands/extension/handler.ts +41 -0
- package/src/cli/commands/extension/init-command.ts +140 -0
- package/src/cli/commands/extension/validate-command.ts +78 -0
- package/src/cli/commands/generate/integration-generator-helpers.ts +185 -0
- package/src/cli/commands/generate/integration-generator.ts +12 -168
- package/src/cli/commands/knowledge/command-helpers.ts +295 -0
- package/src/cli/commands/knowledge/command.ts +34 -261
- package/src/cli/help/command-definitions.ts +2 -0
- package/src/cli/mcp/remote-file-tool-helpers.ts +27 -0
- package/src/cli/mcp/remote-file-tools.ts +6 -28
- package/src/cli/router.ts +2 -0
- package/src/cli/templates/integration-loader-helpers.ts +49 -0
- package/src/cli/templates/integration-loader.ts +10 -28
- package/src/cli/templates/manifest.js +2 -1
- package/src/deno.js +5 -2
- package/src/src/agent/runtime/index.ts +77 -94
- package/src/src/chat/ag-ui-helpers.ts +139 -0
- package/src/src/chat/ag-ui.ts +11 -139
- package/src/src/config/schemas/config.schema.ts +11 -0
- package/src/src/config/schemas/index.ts +15 -1
- package/src/src/errors/error-registry-helpers.ts +23 -0
- package/src/src/errors/error-registry.ts +8 -3
- package/src/src/extensions/capabilities.ts +97 -0
- package/src/src/extensions/contracts.ts +36 -0
- package/src/src/extensions/discovery.ts +221 -0
- package/src/src/extensions/errors.ts +39 -0
- package/src/src/extensions/factory-loader.ts +76 -0
- package/src/src/extensions/index.ts +79 -0
- package/src/src/extensions/interfaces/ai-model-provider.ts +100 -0
- package/src/src/extensions/interfaces/auth-provider.ts +52 -0
- package/src/src/extensions/interfaces/bundler.ts +116 -0
- package/src/src/extensions/interfaces/cache-store.ts +27 -0
- package/src/src/extensions/interfaces/code-parser.ts +84 -0
- package/src/src/extensions/interfaces/content-transformer.ts +38 -0
- package/src/src/extensions/interfaces/css-processor.ts +40 -0
- package/src/src/extensions/interfaces/database-client.ts +35 -0
- package/src/src/extensions/interfaces/embedding-provider.ts +39 -0
- package/src/src/extensions/interfaces/index.ts +81 -0
- package/src/src/extensions/interfaces/node-compat.ts +25 -0
- package/src/src/extensions/interfaces/schema-validator.ts +51 -0
- package/src/src/extensions/interfaces/tracing-exporter.ts +42 -0
- package/src/src/extensions/loader.ts +245 -0
- package/src/src/extensions/orchestrate.ts +184 -0
- package/src/src/extensions/recommendations.ts +24 -0
- package/src/src/extensions/types.ts +57 -0
- package/src/src/extensions/validation.ts +147 -0
- package/src/src/html/styles-builder/plugin-loader.ts +32 -0
- package/src/src/html/styles-builder/tailwind-plugin-allowlist.ts +51 -0
- package/src/src/modules/react-loader/ssr-module-loader/loader-helpers.ts +37 -0
- package/src/src/modules/react-loader/ssr-module-loader/loader.ts +8 -39
- package/src/src/platform/adapters/fs/veryfront/adapter-helpers.ts +43 -0
- package/src/src/platform/adapters/fs/veryfront/adapter.ts +8 -22
- package/src/src/platform/adapters/fs/veryfront/read-operations-helpers.ts +4 -0
- package/src/src/platform/adapters/fs/veryfront/read-operations.ts +4 -7
- package/src/src/platform/adapters/fs/veryfront/websocket-manager-helpers.ts +73 -0
- package/src/src/platform/adapters/fs/veryfront/websocket-manager.ts +29 -44
- package/src/src/platform/compat/process/command.ts +297 -0
- package/src/src/platform/compat/process/env.ts +227 -0
- package/src/src/platform/compat/process/lifecycle.ts +330 -0
- package/src/src/platform/compat/process/runtime-process.ts +27 -0
- package/src/src/platform/compat/process.ts +37 -870
- package/src/src/platform/index.ts +1 -0
- package/src/src/provider/runtime-loader/provider-endpoints.ts +50 -0
- package/src/src/provider/runtime-loader/provider-request-init.ts +101 -0
- package/src/src/provider/runtime-loader/tool-input-status.ts +210 -0
- package/src/src/provider/runtime-loader.ts +113 -368
- package/src/src/proxy/handler.ts +16 -0
- package/src/src/rendering/orchestrator/pipeline-helpers.ts +35 -0
- package/src/src/rendering/orchestrator/pipeline.ts +8 -35
- package/src/src/routing/api/module-loader/loader-helpers.ts +68 -0
- package/src/src/routing/api/module-loader/loader.ts +8 -65
- package/src/src/server/bootstrap.ts +88 -7
- package/src/src/server/dev-ui/manifest.js +3 -1
- package/src/src/server/handlers/request/api/project-discovery.ts +19 -8
- package/src/src/server/production-server.ts +1 -1
- package/src/src/server/services/rsc/endpoints/rsc-bundles.generated.ts +2 -2
- package/src/src/server/utils/domain-parser.ts +4 -0
- package/src/src/studio/bridge/bridge-bundle.generated.ts +1 -1
- package/src/src/tool/index.ts +1 -0
- package/src/src/tool/types.ts +21 -0
- package/src/src/utils/version-constant.ts +1 -1
|
@@ -21,9 +21,34 @@ import {
|
|
|
21
21
|
VeryfrontError,
|
|
22
22
|
} from "../../errors/index.js";
|
|
23
23
|
import { getTailwindPluginBundleUrl } from "../../build/binary-plugin-includes.js";
|
|
24
|
+
import {
|
|
25
|
+
bareName,
|
|
26
|
+
PACKAGE_SPEC_RE,
|
|
27
|
+
TAILWIND_PLUGIN_ALLOWLIST,
|
|
28
|
+
} from "./tailwind-plugin-allowlist.js";
|
|
24
29
|
|
|
25
30
|
const logger = serverLogger.component("tailwind");
|
|
26
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Enforce the Tailwind plugin allowlist (VULN-FS-1).
|
|
34
|
+
*
|
|
35
|
+
* Called at the top of every entry point that can load third-party plugin
|
|
36
|
+
* code. Rejects anything that is not a syntactically valid npm package
|
|
37
|
+
* specifier, and anything whose bare name is not on the allowlist.
|
|
38
|
+
*/
|
|
39
|
+
function assertPluginAllowed(spec: string): void {
|
|
40
|
+
if (!PACKAGE_SPEC_RE.test(spec)) {
|
|
41
|
+
throw new Error(`Invalid Tailwind plugin specifier: ${spec}`);
|
|
42
|
+
}
|
|
43
|
+
const name = bareName(spec);
|
|
44
|
+
if (!TAILWIND_PLUGIN_ALLOWLIST.has(name)) {
|
|
45
|
+
throw new Error(
|
|
46
|
+
`Package "${name}" is not on the Tailwind plugin allowlist. ` +
|
|
47
|
+
`See src/html/styles-builder/tailwind-plugin-allowlist.ts.`,
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
27
52
|
// Provide localStorage shim for plugins that use util-deprecate (which checks localStorage)
|
|
28
53
|
// This prevents "LocalStorage is not supported in this context" errors in Deno.
|
|
29
54
|
try {
|
|
@@ -109,6 +134,8 @@ async function importBundledModule(code: string): Promise<unknown> {
|
|
|
109
134
|
* dynamic imports from URLs. Fetches bundled code, rewrites imports, loads via temp file.
|
|
110
135
|
*/
|
|
111
136
|
export async function loadModuleFromEsmSh(packageName: string): Promise<unknown> {
|
|
137
|
+
assertPluginAllowed(packageName);
|
|
138
|
+
|
|
112
139
|
const stubUrl = getTailwindPluginBundleUrl(packageName);
|
|
113
140
|
logger.debug("Fetching esm.sh stub", { url: stubUrl });
|
|
114
141
|
|
|
@@ -173,6 +200,11 @@ export async function loadPlugin(
|
|
|
173
200
|
pluginCache: Map<string, unknown>,
|
|
174
201
|
pluginErrors: Map<string, Error>,
|
|
175
202
|
): Promise<unknown> {
|
|
203
|
+
// Enforce the allowlist before consulting any caches so a disallowed id can
|
|
204
|
+
// never be served from a pre-seeded or stale cache entry — defence-in-depth
|
|
205
|
+
// against future changes that might pre-populate these maps.
|
|
206
|
+
assertPluginAllowed(id);
|
|
207
|
+
|
|
176
208
|
const cachedError = pluginErrors.get(id);
|
|
177
209
|
if (cachedError) throw cachedError;
|
|
178
210
|
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Allowlist of Tailwind CSS plugin package names that may be dynamically loaded
|
|
3
|
+
* via `loadPlugin` / `loadModuleFromEsmSh`.
|
|
4
|
+
*
|
|
5
|
+
* Tailwind v4 stylesheets can request plugins through the `@plugin "..."`
|
|
6
|
+
* directive. Without restriction, this turns arbitrary project CSS into a
|
|
7
|
+
* remote-code-execution vector because the loader fetches and imports code
|
|
8
|
+
* from https://esm.sh. Only the packages listed here may be loaded.
|
|
9
|
+
*
|
|
10
|
+
* @module html/styles-builder/tailwind-plugin-allowlist
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export const TAILWIND_PLUGIN_ALLOWLIST: ReadonlySet<string> = new Set([
|
|
14
|
+
// Bundled into the compiled binary (see src/build/binary-plugin-includes.ts).
|
|
15
|
+
// Must stay in sync with BINARY_TAILWIND_PLUGIN_PACKAGES — an invariant
|
|
16
|
+
// enforced by tailwind-plugin-allowlist.test.ts.
|
|
17
|
+
"@tailwindcss/typography",
|
|
18
|
+
"@tailwindcss/forms",
|
|
19
|
+
"tailwindcss-animate",
|
|
20
|
+
"tailwind-scrollbar-hide",
|
|
21
|
+
"daisyui",
|
|
22
|
+
// Allowlisted but NOT bundled: loaded from esm.sh on first use. Adding an
|
|
23
|
+
// entry here is arbitrary-code-exec surface; review each one explicitly.
|
|
24
|
+
"@tailwindcss/aspect-ratio",
|
|
25
|
+
"@tailwindcss/container-queries",
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Matches npm package specifiers, optionally scoped and optionally suffixed
|
|
30
|
+
* with an `@version` range. Deliberately restrictive: ASCII only, no path
|
|
31
|
+
* separators, no whitespace, no control characters.
|
|
32
|
+
*/
|
|
33
|
+
export const PACKAGE_SPEC_RE = /^(?:@[a-z0-9][\w.-]*\/)?[a-z0-9][\w.-]*(?:@[\w.+-]+)?$/i;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Return the bare package name (without any `@version` suffix) for a spec.
|
|
37
|
+
*
|
|
38
|
+
* Examples:
|
|
39
|
+
* bareName("pkg") -> "pkg"
|
|
40
|
+
* bareName("pkg@1.0.0") -> "pkg"
|
|
41
|
+
* bareName("@scope/pkg") -> "@scope/pkg"
|
|
42
|
+
* bareName("@scope/pkg@1.0") -> "@scope/pkg"
|
|
43
|
+
*/
|
|
44
|
+
export function bareName(spec: string): string {
|
|
45
|
+
if (spec.startsWith("@")) {
|
|
46
|
+
const idx = spec.indexOf("@", 1);
|
|
47
|
+
return idx === -1 ? spec : spec.slice(0, idx);
|
|
48
|
+
}
|
|
49
|
+
const idx = spec.indexOf("@");
|
|
50
|
+
return idx === -1 ? spec : spec.slice(0, idx);
|
|
51
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { createError, toError } from "../../../errors/veryfront-error.js";
|
|
2
|
+
|
|
3
|
+
const MISSING_HTTP_BUNDLE_PATTERN = /veryfront-http-bundle\/http-([a-f0-9]+)\.mjs/;
|
|
4
|
+
|
|
5
|
+
export type TransformCapacityErrorMode = "plain" | "build";
|
|
6
|
+
|
|
7
|
+
export type ImportErrorClassification =
|
|
8
|
+
| { type: "http-bundle-missing"; hash: string; message: string }
|
|
9
|
+
| { type: "module-not-found"; message: string }
|
|
10
|
+
| { type: "unknown"; message: string };
|
|
11
|
+
|
|
12
|
+
export function classifyImportError(importError: unknown): ImportErrorClassification {
|
|
13
|
+
const message = importError instanceof Error ? importError.message : String(importError);
|
|
14
|
+
const bundleMatch = message.match(MISSING_HTTP_BUNDLE_PATTERN);
|
|
15
|
+
if (bundleMatch?.[1]) {
|
|
16
|
+
return { type: "http-bundle-missing", hash: bundleMatch[1], message };
|
|
17
|
+
}
|
|
18
|
+
if (message.includes("Cannot find module") || message.includes("Module not found")) {
|
|
19
|
+
return { type: "module-not-found", message };
|
|
20
|
+
}
|
|
21
|
+
return { type: "unknown", message };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function createTransformCapacityError(
|
|
25
|
+
mode: TransformCapacityErrorMode,
|
|
26
|
+
message: string,
|
|
27
|
+
filePath: string,
|
|
28
|
+
): Error {
|
|
29
|
+
if (mode === "plain") return new Error(message);
|
|
30
|
+
return toError(
|
|
31
|
+
createError({
|
|
32
|
+
type: "build",
|
|
33
|
+
message,
|
|
34
|
+
context: { file: filePath, phase: "transform" },
|
|
35
|
+
}),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -22,6 +22,11 @@ import { rendererLogger } from "../../../utils/index.js";
|
|
|
22
22
|
import { withSpan } from "../../../observability/tracing/otlp-setup.js";
|
|
23
23
|
import { SpanNames } from "../../../observability/tracing/span-names.js";
|
|
24
24
|
import { extractComponent } from "../extract-component.js";
|
|
25
|
+
import {
|
|
26
|
+
classifyImportError,
|
|
27
|
+
createTransformCapacityError,
|
|
28
|
+
type TransformCapacityErrorMode,
|
|
29
|
+
} from "./loader-helpers.js";
|
|
25
30
|
import {
|
|
26
31
|
getMaxConcurrentTransforms,
|
|
27
32
|
IN_PROGRESS_WAIT_TIMEOUT_MS,
|
|
@@ -58,15 +63,6 @@ import { ensureMdxModuleDependencies } from "../../../transforms/mdx/esm-module-
|
|
|
58
63
|
|
|
59
64
|
const logger = rendererLogger.component("ssr-module-loader");
|
|
60
65
|
|
|
61
|
-
const MISSING_HTTP_BUNDLE_PATTERN = /veryfront-http-bundle\/http-([a-f0-9]+)\.mjs/;
|
|
62
|
-
|
|
63
|
-
type TransformCapacityErrorMode = "plain" | "build";
|
|
64
|
-
|
|
65
|
-
type ImportErrorClassification =
|
|
66
|
-
| { type: "http-bundle-missing"; hash: string; message: string }
|
|
67
|
-
| { type: "module-not-found"; message: string }
|
|
68
|
-
| { type: "unknown"; message: string };
|
|
69
|
-
|
|
70
66
|
/**
|
|
71
67
|
* SSR Module Loader with Redis Support.
|
|
72
68
|
*
|
|
@@ -89,33 +85,6 @@ export class SSRModuleLoader {
|
|
|
89
85
|
);
|
|
90
86
|
}
|
|
91
87
|
|
|
92
|
-
private classifyImportError(importError: unknown): ImportErrorClassification {
|
|
93
|
-
const message = importError instanceof Error ? importError.message : String(importError);
|
|
94
|
-
const bundleMatch = message.match(MISSING_HTTP_BUNDLE_PATTERN);
|
|
95
|
-
if (bundleMatch?.[1]) {
|
|
96
|
-
return { type: "http-bundle-missing", hash: bundleMatch[1], message };
|
|
97
|
-
}
|
|
98
|
-
if (message.includes("Cannot find module") || message.includes("Module not found")) {
|
|
99
|
-
return { type: "module-not-found", message };
|
|
100
|
-
}
|
|
101
|
-
return { type: "unknown", message };
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
private createTransformCapacityError(
|
|
105
|
-
mode: TransformCapacityErrorMode,
|
|
106
|
-
message: string,
|
|
107
|
-
filePath: string,
|
|
108
|
-
): Error {
|
|
109
|
-
if (mode === "plain") return new Error(message);
|
|
110
|
-
return toError(
|
|
111
|
-
createError({
|
|
112
|
-
type: "build",
|
|
113
|
-
message,
|
|
114
|
-
context: { file: filePath, phase: "transform" },
|
|
115
|
-
}),
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
88
|
private async withTransformCapacity<T>(
|
|
120
89
|
filePath: string,
|
|
121
90
|
mode: TransformCapacityErrorMode,
|
|
@@ -127,7 +96,7 @@ export class SSRModuleLoader {
|
|
|
127
96
|
let semaphoreAcquired = false;
|
|
128
97
|
|
|
129
98
|
if (!await tryAcquireTransformSlot(projectId, TRANSFORM_ACQUIRE_TIMEOUT_MS)) {
|
|
130
|
-
throw
|
|
99
|
+
throw createTransformCapacityError(
|
|
131
100
|
mode,
|
|
132
101
|
`Project ${projectId} at transform capacity. Consider reducing page complexity or request rate.`,
|
|
133
102
|
filePath,
|
|
@@ -138,7 +107,7 @@ export class SSRModuleLoader {
|
|
|
138
107
|
if (semaphore) {
|
|
139
108
|
semaphoreAcquired = await semaphore.tryAcquire(TRANSFORM_ACQUIRE_TIMEOUT_MS);
|
|
140
109
|
if (!semaphoreAcquired) {
|
|
141
|
-
throw
|
|
110
|
+
throw createTransformCapacityError(
|
|
142
111
|
mode,
|
|
143
112
|
`Transform capacity exceeded (${semaphore.waiting} waiting). Service is overloaded.`,
|
|
144
113
|
filePath,
|
|
@@ -189,7 +158,7 @@ export class SSRModuleLoader {
|
|
|
189
158
|
{ "ssr.file": fileName },
|
|
190
159
|
)) as Record<string, unknown>;
|
|
191
160
|
} catch (importError) {
|
|
192
|
-
const classifiedError =
|
|
161
|
+
const classifiedError = classifyImportError(importError);
|
|
193
162
|
|
|
194
163
|
if (classifiedError.type === "http-bundle-missing") {
|
|
195
164
|
const hash = classifiedError.hash;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { VeryfrontAPIConfig } from "../../veryfront-api-client/types.js";
|
|
2
|
+
import type { FileCacheOptions } from "../cache/types.js";
|
|
3
|
+
import type { ContentSource, FSAdapterConfig } from "./types.js";
|
|
4
|
+
|
|
5
|
+
export const DEFAULT_MAX_RETRIES = 3;
|
|
6
|
+
export const DEFAULT_INITIAL_RETRY_DELAY_MS = 1_000;
|
|
7
|
+
export const DEFAULT_MAX_RETRY_DELAY_MS = 10_000;
|
|
8
|
+
export const DEFAULT_CACHE_TTL_MS = 60_000;
|
|
9
|
+
export const DEFAULT_CACHE_MAX_ENTRIES = 1_000;
|
|
10
|
+
export const DEFAULT_CACHE_MAX_MEMORY_BYTES = 100 * 1024 * 1024;
|
|
11
|
+
|
|
12
|
+
type VeryfrontConfigOverrides = NonNullable<FSAdapterConfig["veryfront"]>;
|
|
13
|
+
type RetryOverrides = VeryfrontConfigOverrides["retry"];
|
|
14
|
+
type CacheOverrides = VeryfrontConfigOverrides["cache"];
|
|
15
|
+
|
|
16
|
+
export function buildRetryConfig(
|
|
17
|
+
retry?: RetryOverrides,
|
|
18
|
+
): NonNullable<VeryfrontAPIConfig["retry"]> {
|
|
19
|
+
return {
|
|
20
|
+
maxRetries: DEFAULT_MAX_RETRIES,
|
|
21
|
+
initialDelay: DEFAULT_INITIAL_RETRY_DELAY_MS,
|
|
22
|
+
maxDelay: DEFAULT_MAX_RETRY_DELAY_MS,
|
|
23
|
+
...retry,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function buildFileCacheOptions(
|
|
28
|
+
cache?: CacheOverrides,
|
|
29
|
+
): FileCacheOptions {
|
|
30
|
+
return {
|
|
31
|
+
enabled: true,
|
|
32
|
+
ttl: DEFAULT_CACHE_TTL_MS,
|
|
33
|
+
maxSize: DEFAULT_CACHE_MAX_ENTRIES,
|
|
34
|
+
maxMemory: DEFAULT_CACHE_MAX_MEMORY_BYTES,
|
|
35
|
+
...cache,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function shouldBackgroundPregenerateStyles(
|
|
40
|
+
contentContext: { sourceType: ContentSource["type"] } | null,
|
|
41
|
+
): boolean {
|
|
42
|
+
return contentContext?.sourceType !== "branch";
|
|
43
|
+
}
|
|
@@ -13,7 +13,6 @@ import type { FileInfo, ResolveFileOptions } from "../../base.js";
|
|
|
13
13
|
import { VeryfrontApiClient } from "../../veryfront-api-client/index.js";
|
|
14
14
|
import type { Project } from "../../veryfront-api-client/index.js";
|
|
15
15
|
import { FileCache } from "../cache/file-cache.js";
|
|
16
|
-
import type { FileCacheOptions } from "../cache/types.js";
|
|
17
16
|
import { PathNormalizer } from "./path-normalizer.js";
|
|
18
17
|
import { ReadOperations } from "./read-operations.js";
|
|
19
18
|
import { DirectoryOperations } from "./directory-operations.js";
|
|
@@ -28,16 +27,14 @@ import {
|
|
|
28
27
|
summarizeFileList,
|
|
29
28
|
toClientContext,
|
|
30
29
|
} from "./adapter-content-context.js";
|
|
30
|
+
import {
|
|
31
|
+
buildFileCacheOptions,
|
|
32
|
+
buildRetryConfig,
|
|
33
|
+
shouldBackgroundPregenerateStyles,
|
|
34
|
+
} from "./adapter-helpers.js";
|
|
31
35
|
|
|
32
36
|
const logger = baseLogger.component("veryfront-fs-adapter");
|
|
33
37
|
|
|
34
|
-
const DEFAULT_MAX_RETRIES = 3;
|
|
35
|
-
const DEFAULT_INITIAL_RETRY_DELAY_MS = 1_000;
|
|
36
|
-
const DEFAULT_MAX_RETRY_DELAY_MS = 10_000;
|
|
37
|
-
const DEFAULT_CACHE_TTL_MS = 60_000;
|
|
38
|
-
const DEFAULT_CACHE_MAX_ENTRIES = 1_000;
|
|
39
|
-
const DEFAULT_CACHE_MAX_MEMORY_BYTES = 100 * 1024 * 1024;
|
|
40
|
-
|
|
41
38
|
export class VeryfrontFSAdapter implements FSAdapter {
|
|
42
39
|
private client: VeryfrontApiClient;
|
|
43
40
|
private cache: FileCache;
|
|
@@ -126,12 +123,7 @@ export class VeryfrontFSAdapter implements FSAdapter {
|
|
|
126
123
|
this.contentSource = vf.contentSource ?? { type: "branch", branch: "main" };
|
|
127
124
|
this.proxyMode = vf.proxyMode ?? false;
|
|
128
125
|
|
|
129
|
-
const retryConfig =
|
|
130
|
-
maxRetries: DEFAULT_MAX_RETRIES,
|
|
131
|
-
initialDelay: DEFAULT_INITIAL_RETRY_DELAY_MS,
|
|
132
|
-
maxDelay: DEFAULT_MAX_RETRY_DELAY_MS,
|
|
133
|
-
...vf.retry,
|
|
134
|
-
};
|
|
126
|
+
const retryConfig = buildRetryConfig(vf.retry);
|
|
135
127
|
|
|
136
128
|
this.client = new VeryfrontApiClient({
|
|
137
129
|
apiBaseUrl: this.apiBaseUrl,
|
|
@@ -142,13 +134,7 @@ export class VeryfrontFSAdapter implements FSAdapter {
|
|
|
142
134
|
retry: retryConfig,
|
|
143
135
|
});
|
|
144
136
|
|
|
145
|
-
const cacheConfig
|
|
146
|
-
enabled: true,
|
|
147
|
-
ttl: DEFAULT_CACHE_TTL_MS,
|
|
148
|
-
maxSize: DEFAULT_CACHE_MAX_ENTRIES,
|
|
149
|
-
maxMemory: DEFAULT_CACHE_MAX_MEMORY_BYTES,
|
|
150
|
-
...vf.cache,
|
|
151
|
-
};
|
|
137
|
+
const cacheConfig = buildFileCacheOptions(vf.cache);
|
|
152
138
|
|
|
153
139
|
this.cache = new FileCache(cacheConfig);
|
|
154
140
|
this.normalizer = new PathNormalizer(config.projectDir);
|
|
@@ -396,7 +382,7 @@ export class VeryfrontFSAdapter implements FSAdapter {
|
|
|
396
382
|
// Branch previews should recover the last registered stylesheet artifact on
|
|
397
383
|
// cold starts before rebuilding CSS locally. Live edit pokes still
|
|
398
384
|
// pregenerate through the WebSocket path after branch content changes.
|
|
399
|
-
return this.contentContext
|
|
385
|
+
return shouldBackgroundPregenerateStyles(this.contentContext);
|
|
400
386
|
}
|
|
401
387
|
|
|
402
388
|
private scheduleFileListWarmup(reason: string, cacheKey?: string): void {
|
|
@@ -80,6 +80,10 @@ export function getResolvedCacheKey(
|
|
|
80
80
|
return `${cacheKeyPrefix}:${normalizedResolvedPath}`;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
export function buildContentPreview(content: string, max = 80): string {
|
|
84
|
+
return content.length > max ? `${content.slice(0, max)}...` : content;
|
|
85
|
+
}
|
|
86
|
+
|
|
83
87
|
export function buildExtensionCandidatePaths(basePath: string): string[] {
|
|
84
88
|
return READ_OPERATION_EXTENSION_PRIORITY.map((ext) => `${basePath}${ext}`);
|
|
85
89
|
}
|
|
@@ -10,6 +10,7 @@ import { PathNormalizer } from "./path-normalizer.js";
|
|
|
10
10
|
import type { ContentContextProvider } from "./file-list-access.js";
|
|
11
11
|
import {
|
|
12
12
|
assertProjectSourcePath,
|
|
13
|
+
buildContentPreview,
|
|
13
14
|
buildExtensionCandidatePaths,
|
|
14
15
|
buildReadFetchState,
|
|
15
16
|
createNotFoundLikeError,
|
|
@@ -33,10 +34,6 @@ const IN_FLIGHT_REQUEST_TIMEOUT_MS = 15_000;
|
|
|
33
34
|
const MAX_IN_FLIGHT_REQUESTS = 100;
|
|
34
35
|
const IN_FLIGHT_CLEANUP_INTERVAL_MS = 1_000;
|
|
35
36
|
|
|
36
|
-
function previewText(content: string, max = 80): string {
|
|
37
|
-
return content.length > max ? `${content.slice(0, max)}...` : content;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
37
|
export class ReadOperations {
|
|
41
38
|
private readonly inFlightRequests = new InFlightRequestDeduper<string>({
|
|
42
39
|
timeoutMs: IN_FLIGHT_REQUEST_TIMEOUT_MS,
|
|
@@ -110,7 +107,7 @@ export class ReadOperations {
|
|
|
110
107
|
path: normalizedPath,
|
|
111
108
|
cacheKey,
|
|
112
109
|
contentLength: requestCached.length,
|
|
113
|
-
preview:
|
|
110
|
+
preview: buildContentPreview(requestCached).replace(/\n/g, "\\n"),
|
|
114
111
|
});
|
|
115
112
|
return requestCached;
|
|
116
113
|
}
|
|
@@ -151,7 +148,7 @@ export class ReadOperations {
|
|
|
151
148
|
path: normalizedPath,
|
|
152
149
|
cacheKey,
|
|
153
150
|
contentLength: cached.length,
|
|
154
|
-
preview:
|
|
151
|
+
preview: buildContentPreview(cached).replace(/\n/g, "\\n"),
|
|
155
152
|
});
|
|
156
153
|
setRequestScopedFile(cacheKey, cached);
|
|
157
154
|
return cached;
|
|
@@ -772,7 +769,7 @@ export class ReadOperations {
|
|
|
772
769
|
logger.debug("API_FETCH_DONE - got content from API", {
|
|
773
770
|
path: normalizedPath,
|
|
774
771
|
contentLength: content.length,
|
|
775
|
-
preview:
|
|
772
|
+
preview: buildContentPreview(content).replace(/\n/g, "\\n"),
|
|
776
773
|
willCache: shouldCache,
|
|
777
774
|
});
|
|
778
775
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { ContentSource, ResolvedContentContext } from "./types.js";
|
|
2
|
+
import { buildFileCacheKeyPrefix } from "./cache-keys.js";
|
|
3
|
+
|
|
4
|
+
export const INVALIDATION_DEBOUNCE_MS = 100;
|
|
5
|
+
export const WS_RECONNECT_DELAY_MS = 5000;
|
|
6
|
+
export const WS_RECONNECT_MAX_DELAY_MS = 120000;
|
|
7
|
+
export const WS_RECONNECT_MAX_FAILURES = 10;
|
|
8
|
+
export const WS_HEARTBEAT_INTERVAL_MS = 60000;
|
|
9
|
+
export const WS_HEARTBEAT_TIMEOUT_MS = 300000;
|
|
10
|
+
|
|
11
|
+
export interface PreviewStyleArtifactInfo {
|
|
12
|
+
hash: string;
|
|
13
|
+
assetPath: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function getConnectionLogContext(
|
|
17
|
+
projectSlug: string | undefined,
|
|
18
|
+
context: Record<string, unknown> = {},
|
|
19
|
+
): Record<string, unknown> {
|
|
20
|
+
if (!projectSlug) return context;
|
|
21
|
+
return { projectSlug, ...context };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function getPreviewInvalidationPrefixes(
|
|
25
|
+
contentContext: ResolvedContentContext | null,
|
|
26
|
+
): string[] {
|
|
27
|
+
if (contentContext?.sourceType !== "branch") return [];
|
|
28
|
+
return [buildFileCacheKeyPrefix(contentContext)];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function getReconnectDelay(consecutiveFailures: number): number {
|
|
32
|
+
const delay = WS_RECONNECT_DELAY_MS * Math.pow(2, consecutiveFailures - 1);
|
|
33
|
+
return Math.min(delay, WS_RECONNECT_MAX_DELAY_MS);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function buildReloadProjectContext(
|
|
37
|
+
contentContext: ResolvedContentContext | null,
|
|
38
|
+
projectSlug: string,
|
|
39
|
+
projectId: string,
|
|
40
|
+
preparedStyleArtifact?: PreviewStyleArtifactInfo,
|
|
41
|
+
): {
|
|
42
|
+
projectSlug: string;
|
|
43
|
+
projectId: string;
|
|
44
|
+
environment: "preview" | "production";
|
|
45
|
+
branch: string | null;
|
|
46
|
+
releaseId: string | null;
|
|
47
|
+
styleArtifactHash: string | undefined;
|
|
48
|
+
styleAssetPath: string | undefined;
|
|
49
|
+
} {
|
|
50
|
+
const environment: "preview" | "production" = contentContext?.sourceType === "branch"
|
|
51
|
+
? "preview"
|
|
52
|
+
: "production";
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
projectSlug,
|
|
56
|
+
projectId,
|
|
57
|
+
environment,
|
|
58
|
+
branch: contentContext?.branch ?? null,
|
|
59
|
+
releaseId: contentContext?.releaseId ?? null,
|
|
60
|
+
styleArtifactHash: preparedStyleArtifact?.hash,
|
|
61
|
+
styleAssetPath: preparedStyleArtifact?.assetPath,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function buildContentSourceLabel(
|
|
66
|
+
getContentSource: () => ContentSource,
|
|
67
|
+
getContentContext: () => ResolvedContentContext | null,
|
|
68
|
+
): { contentSource: ContentSource; branch: string | null } {
|
|
69
|
+
return {
|
|
70
|
+
contentSource: getContentSource(),
|
|
71
|
+
branch: getContentContext()?.branch ?? null,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -14,23 +14,24 @@ import {
|
|
|
14
14
|
getPendingInvalidationsCount,
|
|
15
15
|
removePendingInvalidation,
|
|
16
16
|
} from "./invalidation-state.js";
|
|
17
|
+
import {
|
|
18
|
+
buildContentSourceLabel,
|
|
19
|
+
buildReloadProjectContext,
|
|
20
|
+
getConnectionLogContext as getConnectionLogContextHelper,
|
|
21
|
+
getPreviewInvalidationPrefixes as getPreviewInvalidationPrefixesHelper,
|
|
22
|
+
getReconnectDelay as getReconnectDelayHelper,
|
|
23
|
+
INVALIDATION_DEBOUNCE_MS,
|
|
24
|
+
type PreviewStyleArtifactInfo,
|
|
25
|
+
WS_HEARTBEAT_INTERVAL_MS,
|
|
26
|
+
WS_HEARTBEAT_TIMEOUT_MS,
|
|
27
|
+
WS_RECONNECT_MAX_DELAY_MS,
|
|
28
|
+
WS_RECONNECT_MAX_FAILURES,
|
|
29
|
+
} from "./websocket-manager-helpers.js";
|
|
17
30
|
|
|
18
31
|
const logger = getBaseLogger("SERVER", { injectTraceContext: false }).component(
|
|
19
32
|
"web-socket-manager",
|
|
20
33
|
);
|
|
21
34
|
|
|
22
|
-
const INVALIDATION_DEBOUNCE_MS = 100;
|
|
23
|
-
const WS_RECONNECT_DELAY_MS = 5000;
|
|
24
|
-
const WS_RECONNECT_MAX_DELAY_MS = 120000;
|
|
25
|
-
const WS_RECONNECT_MAX_FAILURES = 10;
|
|
26
|
-
const WS_HEARTBEAT_INTERVAL_MS = 60000;
|
|
27
|
-
const WS_HEARTBEAT_TIMEOUT_MS = 300000;
|
|
28
|
-
|
|
29
|
-
interface PreviewStyleArtifactInfo {
|
|
30
|
-
hash: string;
|
|
31
|
-
assetPath: string;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
35
|
interface WebSocketDeps {
|
|
35
36
|
apiBaseUrl: string;
|
|
36
37
|
apiToken: string;
|
|
@@ -77,15 +78,13 @@ export class WebSocketManager {
|
|
|
77
78
|
constructor(private readonly deps: WebSocketDeps) {}
|
|
78
79
|
|
|
79
80
|
private getConnectionLogContext(context: Record<string, unknown> = {}): Record<string, unknown> {
|
|
80
|
-
|
|
81
|
-
return { projectSlug: this.deps.projectSlug, ...context };
|
|
81
|
+
return getConnectionLogContextHelper(this.deps.projectSlug, context);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
private getPreviewInvalidationPrefixes(
|
|
85
85
|
contentContext: ResolvedContentContext | null,
|
|
86
86
|
): string[] {
|
|
87
|
-
|
|
88
|
-
return [buildFileCacheKeyPrefix(contentContext)];
|
|
87
|
+
return getPreviewInvalidationPrefixesHelper(contentContext);
|
|
89
88
|
}
|
|
90
89
|
|
|
91
90
|
private beginPreviewInvalidation(contentContext: ResolvedContentContext | null): void {
|
|
@@ -169,8 +168,7 @@ export class WebSocketManager {
|
|
|
169
168
|
this.getConnectionLogContext({
|
|
170
169
|
projectId,
|
|
171
170
|
connectionId: this.wsConnectionId,
|
|
172
|
-
|
|
173
|
-
branch: this.deps.getContentContext()?.branch,
|
|
171
|
+
...buildContentSourceLabel(this.deps.getContentSource, this.deps.getContentContext),
|
|
174
172
|
}),
|
|
175
173
|
);
|
|
176
174
|
this.wsLastPong = Date.now();
|
|
@@ -233,8 +231,7 @@ export class WebSocketManager {
|
|
|
233
231
|
|
|
234
232
|
private getReconnectDelay(): number {
|
|
235
233
|
// Exponential backoff: 5s, 10s, 20s, 40s, 80s, capped at 120s
|
|
236
|
-
|
|
237
|
-
return Math.min(delay, WS_RECONNECT_MAX_DELAY_MS);
|
|
234
|
+
return getReconnectDelayHelper(this.wsConsecutiveFailures);
|
|
238
235
|
}
|
|
239
236
|
|
|
240
237
|
dispose(): void {
|
|
@@ -664,18 +661,12 @@ export class WebSocketManager {
|
|
|
664
661
|
},
|
|
665
662
|
);
|
|
666
663
|
|
|
667
|
-
const
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
environment,
|
|
674
|
-
branch: contentContext?.branch ?? null,
|
|
675
|
-
releaseId: contentContext?.releaseId ?? null,
|
|
676
|
-
styleArtifactHash: preparedStyleArtifact?.hash,
|
|
677
|
-
styleAssetPath: preparedStyleArtifact?.assetPath,
|
|
678
|
-
};
|
|
664
|
+
const projectContext = buildReloadProjectContext(
|
|
665
|
+
contentContext,
|
|
666
|
+
this.deps.projectSlug,
|
|
667
|
+
this.deps.client.getProjectId(),
|
|
668
|
+
preparedStyleArtifact,
|
|
669
|
+
);
|
|
679
670
|
|
|
680
671
|
this.deps.invalidationCallbacks.triggerReload?.(changedPaths, projectContext);
|
|
681
672
|
|
|
@@ -806,18 +797,12 @@ export class WebSocketManager {
|
|
|
806
797
|
hasTriggerReloadCallback: !!this.deps.invalidationCallbacks.triggerReload,
|
|
807
798
|
});
|
|
808
799
|
|
|
809
|
-
const
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
environment,
|
|
816
|
-
branch: contentContext?.branch ?? null,
|
|
817
|
-
releaseId: contentContext?.releaseId ?? null,
|
|
818
|
-
styleArtifactHash: preparedStyleArtifact?.hash,
|
|
819
|
-
styleAssetPath: preparedStyleArtifact?.assetPath,
|
|
820
|
-
};
|
|
800
|
+
const projectContext = buildReloadProjectContext(
|
|
801
|
+
contentContext,
|
|
802
|
+
this.deps.projectSlug,
|
|
803
|
+
this.deps.client.getProjectId(),
|
|
804
|
+
preparedStyleArtifact,
|
|
805
|
+
);
|
|
821
806
|
|
|
822
807
|
this.deps.invalidationCallbacks.triggerReload?.(undefined, projectContext);
|
|
823
808
|
|