@ecopages/core 0.2.0-beta.2 → 0.2.0-beta.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/README.md +1 -1
- package/package.json +163 -3
- package/src/adapters/abstract/application-adapter.d.ts +104 -5
- package/src/adapters/abstract/application-adapter.js +125 -1
- package/src/adapters/abstract/server-adapter.d.ts +6 -2
- package/src/adapters/abstract/ws-pattern-matcher.d.ts +60 -0
- package/src/adapters/abstract/ws-pattern-matcher.js +61 -0
- package/src/adapters/bun/client-bridge.d.ts +1 -0
- package/src/adapters/bun/client-bridge.js +3 -0
- package/src/adapters/bun/create-app.d.ts +6 -4
- package/src/adapters/bun/create-app.js +65 -43
- package/src/adapters/bun/hmr-manager.d.ts +2 -1
- package/src/adapters/bun/hmr-manager.js +2 -2
- package/src/adapters/bun/server-adapter.d.ts +90 -22
- package/src/adapters/bun/server-adapter.js +265 -84
- package/src/adapters/bun/static-preview-host.js +25 -20
- package/src/adapters/create-app.d.ts +13 -11
- package/src/adapters/create-app.js +2 -51
- package/src/adapters/index.d.ts +1 -1
- package/src/adapters/index.js +1 -2
- package/src/adapters/node/create-app.d.ts +5 -1
- package/src/adapters/node/create-app.js +51 -12
- package/src/adapters/node/node-client-bridge.d.ts +1 -0
- package/src/adapters/node/node-client-bridge.js +3 -0
- package/src/adapters/node/node-hmr-manager.d.ts +2 -1
- package/src/adapters/node/node-hmr-manager.js +2 -2
- package/src/adapters/node/server-adapter-dependencies.js +4 -0
- package/src/adapters/node/server-adapter.d.ts +62 -20
- package/src/adapters/node/server-adapter.js +161 -131
- package/src/adapters/node/static-content-server.d.ts +1 -0
- package/src/adapters/node/static-content-server.js +10 -2
- package/src/adapters/node/static-preview-host.js +27 -12
- package/src/adapters/shared/bun-user-websocket-lifecycle.d.ts +22 -0
- package/src/adapters/shared/bun-user-websocket-lifecycle.js +96 -0
- package/src/adapters/shared/copy-runtime-public-dir.d.ts +6 -0
- package/src/adapters/shared/copy-runtime-public-dir.js +24 -0
- package/src/adapters/shared/fs-server-response-matcher.d.ts +2 -0
- package/src/adapters/shared/fs-server-response-matcher.js +40 -18
- package/src/adapters/shared/hmr-entrypoint-registrar.d.ts +0 -2
- package/src/adapters/shared/hmr-entrypoint-registrar.js +3 -26
- package/src/adapters/shared/hmr-html-response.d.ts +1 -1
- package/src/adapters/shared/hmr-html-response.js +4 -1
- package/src/adapters/shared/node-http-websocket-upgrades.d.ts +21 -0
- package/src/adapters/shared/node-http-websocket-upgrades.js +100 -0
- package/src/adapters/shared/port-manager.d.ts +116 -0
- package/src/adapters/shared/port-manager.js +196 -0
- package/src/adapters/shared/runtime-app-bootstrap.d.ts +2 -1
- package/src/adapters/shared/runtime-app-bootstrap.js +3 -6
- package/src/adapters/shared/runtime-server-lifecycle.d.ts +38 -0
- package/src/adapters/shared/runtime-server-lifecycle.js +43 -0
- package/src/adapters/shared/server-adapter.d.ts +2 -1
- package/src/adapters/shared/server-adapter.js +13 -6
- package/src/adapters/shared/server-route-handler.d.ts +4 -1
- package/src/adapters/shared/server-route-handler.js +5 -2
- package/src/adapters/shared/server-static-builder.d.ts +23 -32
- package/src/adapters/shared/server-static-builder.js +97 -73
- package/src/adapters/shared/shared-hmr-manager.d.ts +28 -0
- package/src/adapters/shared/shared-hmr-manager.js +119 -9
- package/src/adapters/shared/static-preview-host.d.ts +5 -0
- package/src/adapters/shared/websocket-lifecycle.d.ts +24 -0
- package/src/adapters/shared/websocket-lifecycle.js +55 -0
- package/src/build/README.md +77 -14
- package/src/build/app-build-manifest-runtime.d.ts +10 -0
- package/src/build/app-build-manifest-runtime.js +90 -0
- package/src/build/build-adapter.d.ts +17 -319
- package/src/build/build-adapter.js +28 -94
- package/src/build/build-contracts.d.ts +97 -0
- package/src/build/build-contracts.js +0 -0
- package/src/build/build-input-fingerprint.d.ts +28 -0
- package/src/build/build-input-fingerprint.js +31 -0
- package/src/build/build-profile-options.d.ts +7 -0
- package/src/build/build-profile-options.js +37 -0
- package/src/build/build-runtime.d.ts +24 -0
- package/src/build/build-runtime.js +65 -0
- package/src/build/deduping-build-executor.d.ts +28 -0
- package/src/build/deduping-build-executor.js +56 -0
- package/src/build/jsx-ownership-plugins.d.ts +24 -0
- package/src/build/jsx-ownership-plugins.js +41 -0
- package/src/build/pages-unified-graph-build.d.ts +31 -0
- package/src/build/pages-unified-graph-build.js +206 -0
- package/src/build/parallel-build-executor.d.ts +21 -0
- package/src/build/parallel-build-executor.js +52 -0
- package/src/build/production-build-cache.d.ts +20 -0
- package/src/build/production-build-cache.js +63 -0
- package/src/build/rolldown-adapter-helpers.d.ts +3 -6
- package/src/build/rolldown-adapter-helpers.js +71 -6
- package/src/build/rolldown-build-adapter.d.ts +2 -6
- package/src/build/rolldown-build-adapter.js +3 -3
- package/src/build/rolldown-build-invocation-metrics.d.ts +12 -0
- package/src/build/rolldown-build-invocation-metrics.js +43 -0
- package/src/build/rolldown-plugin-bridge.d.ts +15 -1
- package/src/build/rolldown-plugin-bridge.js +20 -5
- package/src/build/rolldown-source-transform-pass.d.ts +15 -0
- package/src/build/rolldown-source-transform-pass.js +58 -0
- package/src/build/runtime-build-executor.d.ts +8 -15
- package/src/build/runtime-build-executor.js +12 -15
- package/src/build/runtime-build-output-normalizer.d.ts +7 -0
- package/src/build/runtime-build-output-normalizer.js +94 -2
- package/src/build/server-entry-build-cache.d.ts +44 -0
- package/src/build/server-entry-build-cache.js +161 -0
- package/src/client/navigation-scripts/classification.d.ts +16 -0
- package/src/client/navigation-scripts/classification.js +41 -0
- package/src/client/navigation-scripts/index.d.ts +3 -0
- package/src/client/navigation-scripts/index.js +23 -0
- package/src/client/navigation-scripts/navigation-scripts.test.browser.js +65 -0
- package/src/client/navigation-scripts/registry.d.ts +11 -0
- package/src/client/navigation-scripts/registry.js +12 -0
- package/src/client/navigation-scripts/rerun-queue.d.ts +37 -0
- package/src/client/navigation-scripts/rerun-queue.js +73 -0
- package/src/client/scroll.d.ts +17 -0
- package/src/client/scroll.js +25 -0
- package/src/client/scroll.test.browser.js +37 -0
- package/src/client/view-transitions.d.ts +16 -0
- package/src/client/view-transitions.js +63 -0
- package/src/config/config-builder.d.ts +12 -7
- package/src/config/config-builder.js +12 -9
- package/src/dev/client-bridge-registry.d.ts +5 -0
- package/src/dev/client-bridge-registry.js +15 -0
- package/src/dev/dev-client-ownership.d.ts +7 -0
- package/src/dev/dev-client-ownership.js +6 -0
- package/src/dev/hmr-manager-registry.d.ts +8 -0
- package/src/dev/hmr-manager-registry.js +15 -0
- package/src/dev/host-runtime.d.ts +3 -0
- package/src/dev/host-runtime.js +7 -0
- package/src/dev/runtime-server-started-message.d.ts +2 -0
- package/src/dev/runtime-server-started-message.js +6 -0
- package/src/eco/README.md +11 -0
- package/src/eco/eco-declared-component.d.ts +14 -0
- package/src/eco/eco-declared-component.js +16 -0
- package/src/eco/eco.browser.js +5 -6
- package/src/eco/eco.js +5 -6
- package/src/eco/eco.types.d.ts +2 -2
- package/src/eco/page-layout-normalization.d.ts +21 -0
- package/src/eco/page-layout-normalization.js +59 -0
- package/src/errors/index.d.ts +1 -0
- package/src/errors/index.js +7 -1
- package/src/errors/undeclared-component-dependency-error.d.ts +11 -0
- package/src/errors/undeclared-component-dependency-error.js +17 -0
- package/src/hmr/client/hmr-runtime.js +5 -2
- package/src/hmr/hmr-entrypoint-output.d.ts +28 -0
- package/src/hmr/hmr-entrypoint-output.js +58 -0
- package/src/hmr/strategies/js-hmr-strategy.d.ts +3 -0
- package/src/hmr/strategies/js-hmr-strategy.js +68 -18
- package/src/hmr/strategies/server-rendered-template-hmr-strategy.d.ts +17 -0
- package/src/hmr/strategies/server-rendered-template-hmr-strategy.js +29 -0
- package/src/integrations/ghtml/ghtml-renderer.d.ts +2 -6
- package/src/integrations/ghtml/ghtml-renderer.js +2 -51
- package/src/integrations/ghtml/ghtml.plugin.d.ts +3 -16
- package/src/integrations/ghtml/ghtml.plugin.js +7 -14
- package/src/plugins/define-integration.d.ts +26 -0
- package/src/plugins/define-integration.js +19 -0
- package/src/plugins/eco-component-meta-plugin.js +5 -8
- package/src/plugins/foreign-jsx-override-plugin.js +4 -6
- package/src/plugins/integration-plugin.d.ts +19 -9
- package/src/plugins/integration-plugin.js +7 -4
- package/src/plugins/jsx-import-source.utils.d.ts +8 -0
- package/src/plugins/jsx-import-source.utils.js +26 -0
- package/src/plugins/processor.d.ts +19 -4
- package/src/plugins/processor.js +22 -4
- package/src/plugins/source-transform.d.ts +31 -0
- package/src/plugins/source-transform.js +23 -1
- package/src/route-renderer/GRAPH.md +8 -8
- package/src/route-renderer/README.md +30 -28
- package/src/route-renderer/orchestration/component-graph-collectors.d.ts +10 -0
- package/src/route-renderer/orchestration/component-graph-collectors.js +143 -0
- package/src/route-renderer/orchestration/component-graph.d.ts +36 -0
- package/src/route-renderer/orchestration/component-graph.js +98 -0
- package/src/route-renderer/orchestration/component-render-context.d.ts +3 -10
- package/src/route-renderer/orchestration/component-render-context.js +3 -1
- package/src/route-renderer/orchestration/declared-ownership-graph.d.ts +1 -18
- package/src/route-renderer/orchestration/declared-ownership-graph.js +5 -31
- package/src/route-renderer/orchestration/document-shell-render.service.d.ts +90 -0
- package/src/route-renderer/orchestration/document-shell-render.service.js +120 -0
- package/src/route-renderer/orchestration/foreign-subtree-execution.service.d.ts +59 -29
- package/src/route-renderer/orchestration/foreign-subtree-execution.service.js +164 -35
- package/src/route-renderer/orchestration/global-injector-assets.service.d.ts +7 -0
- package/src/route-renderer/orchestration/global-injector-assets.service.js +32 -0
- package/src/route-renderer/orchestration/integration-renderer.d.ts +18 -54
- package/src/route-renderer/orchestration/integration-renderer.js +113 -195
- package/src/route-renderer/orchestration/integration-route-render-adapter.d.ts +38 -0
- package/src/route-renderer/orchestration/integration-route-render-adapter.js +27 -0
- package/src/route-renderer/orchestration/layout-shell-props.service.d.ts +20 -0
- package/src/route-renderer/orchestration/layout-shell-props.service.js +31 -0
- package/src/route-renderer/orchestration/ownership-validation.service.d.ts +5 -0
- package/src/route-renderer/orchestration/ownership-validation.service.js +29 -1
- package/src/route-renderer/orchestration/page-browser-graph-contribution.loader.d.ts +9 -0
- package/src/route-renderer/orchestration/page-browser-graph-contribution.loader.js +7 -0
- package/src/route-renderer/orchestration/page-browser-graph.service.d.ts +25 -0
- package/src/route-renderer/orchestration/page-browser-graph.service.js +174 -0
- package/src/route-renderer/orchestration/render-output.utils.d.ts +2 -0
- package/src/route-renderer/orchestration/render-output.utils.js +4 -0
- package/src/route-renderer/orchestration/route-html-finalization.service.d.ts +17 -0
- package/src/route-renderer/orchestration/route-html-finalization.service.js +26 -0
- package/src/route-renderer/orchestration/route-prepared-options.builder.d.ts +26 -0
- package/src/route-renderer/orchestration/route-prepared-options.builder.js +54 -0
- package/src/route-renderer/orchestration/route-prepared-options.utils.d.ts +4 -0
- package/src/route-renderer/orchestration/route-prepared-options.utils.js +33 -0
- package/src/route-renderer/orchestration/route-render-orchestrator.d.ts +8 -39
- package/src/route-renderer/orchestration/route-render-orchestrator.js +53 -461
- package/src/route-renderer/orchestration/string-markup-renderer.d.ts +14 -0
- package/src/route-renderer/orchestration/string-markup-renderer.js +55 -0
- package/src/route-renderer/page-loading/component-dependency-collection.js +5 -2
- package/src/router/client/link-intent.d.ts +11 -21
- package/src/router/client/link-intent.js +10 -0
- package/src/router/client/link-intent.test.browser.js +12 -1
- package/src/router/client/link-navigation-policy.d.ts +45 -0
- package/src/router/client/link-navigation-policy.js +101 -0
- package/src/router/client/link-navigation-policy.test.browser.d.ts +1 -0
- package/src/router/client/link-navigation-policy.test.browser.js +92 -0
- package/src/router/client/navigation-coordinator.d.ts +1 -1
- package/src/router/client/navigation-coordinator.js +12 -2
- package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.d.ts +1 -0
- package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.js +1 -0
- package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.d.ts +4 -2
- package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.js +27 -7
- package/src/services/assets/asset-processing-service/processors/script/file-script.processor.js +36 -14
- package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.js +17 -3
- package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.d.ts +0 -3
- package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.js +2 -31
- package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.d.ts +0 -3
- package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.js +2 -30
- package/src/services/assets/asset-processing-service/processors/stylesheet/stylesheet-processor-pipeline.d.ts +2 -0
- package/src/services/assets/asset-processing-service/processors/stylesheet/stylesheet-processor-pipeline.js +43 -0
- package/src/services/assets/browser-bundle.service.d.ts +3 -1
- package/src/services/assets/browser-bundle.service.js +17 -5
- package/src/services/html/html-transformer.service.d.ts +1 -1
- package/src/services/html/html-transformer.service.js +4 -4
- package/src/services/invalidation/development-invalidation.service.d.ts +20 -2
- package/src/services/invalidation/development-invalidation.service.js +56 -2
- package/src/services/module-loading/README.md +49 -0
- package/src/services/module-loading/app-server-module-transpiler.service.js +5 -17
- package/src/services/module-loading/page-module-import.service.d.ts +5 -1
- package/src/services/module-loading/page-module-import.service.js +97 -45
- package/src/services/module-loading/route-module-build-cache-registry.d.ts +24 -0
- package/src/services/module-loading/route-module-build-cache-registry.js +37 -0
- package/src/services/module-loading/route-module-build-cache.d.ts +4 -0
- package/src/services/module-loading/route-module-build-cache.js +38 -0
- package/src/services/module-loading/route-module-build-cache.store.d.ts +57 -0
- package/src/services/module-loading/route-module-build-cache.store.js +207 -0
- package/src/services/module-loading/route-module-build-manifest.d.ts +61 -0
- package/src/services/module-loading/route-module-build-manifest.js +116 -0
- package/src/services/module-loading/route-module-dependency-hasher.d.ts +81 -0
- package/src/services/module-loading/route-module-dependency-hasher.js +121 -0
- package/src/services/module-loading/server-module-transpiler.service.js +1 -1
- package/src/static-site-generator/README.md +33 -0
- package/src/static-site-generator/static-build-invalidation.d.ts +10 -0
- package/src/static-site-generator/static-build-invalidation.js +59 -0
- package/src/static-site-generator/static-export-context.d.ts +22 -0
- package/src/static-site-generator/static-export-context.js +0 -0
- package/src/static-site-generator/static-site-generator.d.ts +17 -20
- package/src/static-site-generator/static-site-generator.js +188 -85
- package/src/types/internal-types.d.ts +16 -9
- package/src/types/public-types.d.ts +138 -26
- package/src/utils/parse-cli-args.d.ts +2 -0
- package/src/utils/parse-cli-args.js +6 -0
- package/src/utils/server-utils.module.d.ts +3 -2
- package/src/utils/server-utils.module.js +5 -6
- package/src/utils/static-file-extensions.d.ts +12 -0
- package/src/utils/static-file-extensions.js +48 -0
- package/src/watchers/project-watcher-ignore.d.ts +11 -0
- package/src/watchers/project-watcher-ignore.js +16 -0
- package/src/watchers/project-watcher.d.ts +25 -2
- package/src/watchers/project-watcher.js +130 -23
- package/src/build/rolldown-dev-build-adapter.d.ts +0 -82
- package/src/build/rolldown-dev-build-adapter.js +0 -166
- package/src/hmr/hmr.postcss.test.e2e.js +0 -31
- package/src/hmr/hmr.test.e2e.js +0 -43
- package/src/route-renderer/orchestration/ownership-planning.service.d.ts +0 -24
- package/src/route-renderer/orchestration/ownership-planning.service.js +0 -63
- package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.d.ts +0 -91
- package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.js +0 -170
- /package/src/{hmr/hmr.postcss.test.e2e.d.ts → client/navigation-scripts/navigation-scripts.test.browser.d.ts} +0 -0
- /package/src/{hmr/hmr.test.e2e.d.ts → client/scroll.test.browser.d.ts} +0 -0
|
@@ -1,22 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {} from "node:http";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { fileSystem } from "@ecopages/file-system";
|
|
4
|
-
import {
|
|
4
|
+
import { setupAppRuntimePlugins } from "../../build/build-adapter.js";
|
|
5
5
|
import { installAppRuntimeBuildExecutor } from "../../build/runtime-build-executor.js";
|
|
6
|
-
import { RESOLVED_ASSETS_DIR } from "../../config/constants.js";
|
|
7
6
|
import { appLogger } from "../../global/app-logger.js";
|
|
8
7
|
import { NodeClientBridge } from "./node-client-bridge.js";
|
|
9
8
|
import { NodeHmrManager } from "./node-hmr-manager.js";
|
|
10
9
|
import { ProjectWatcher } from "../../watchers/project-watcher.js";
|
|
10
|
+
import {
|
|
11
|
+
attachNodeHttpWebSocketUpgrades
|
|
12
|
+
} from "../shared/node-http-websocket-upgrades.js";
|
|
11
13
|
import { StaticSiteGenerator } from "../../static-site-generator/static-site-generator.js";
|
|
12
14
|
import { SharedServerAdapter } from "../shared/server-adapter.js";
|
|
13
15
|
import { ServerStaticBuilder } from "../shared/server-static-builder.js";
|
|
14
16
|
import { DEFAULT_ECOPAGES_HOSTNAME, DEFAULT_ECOPAGES_PORT } from "../../config/constants.js";
|
|
15
17
|
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
maybeInjectAdapterHmrHtmlResponse,
|
|
19
|
+
prepareRuntimePublicDir,
|
|
20
|
+
wireIntegrationHmrManagers,
|
|
21
|
+
disposeDevResources
|
|
22
|
+
} from "../shared/runtime-server-lifecycle.js";
|
|
20
23
|
import { resolveServeRuntimeOrigin } from "../shared/runtime-app-bootstrap.js";
|
|
21
24
|
import { NodeClientAbortError, NodeHttpRequestBridge } from "./http-request-bridge.js";
|
|
22
25
|
import { NodeStaticPreviewHost } from "./static-preview-host.js";
|
|
@@ -29,29 +32,73 @@ class NodeServerAdapter extends SharedServerAdapter {
|
|
|
29
32
|
errorHandler;
|
|
30
33
|
bridge = null;
|
|
31
34
|
hmrManager = null;
|
|
35
|
+
projectWatcher = null;
|
|
36
|
+
adapterDisposed = false;
|
|
37
|
+
deferRuntimeAssetSetup;
|
|
38
|
+
allowPortFallback;
|
|
32
39
|
previewHost;
|
|
33
40
|
requestBridge;
|
|
34
41
|
devRuntimeFactory;
|
|
35
|
-
|
|
36
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Reference to the application-level WebSocket handlers map.
|
|
44
|
+
*
|
|
45
|
+
* @remarks
|
|
46
|
+
* This is a reference to the map owned by `AbstractApplicationAdapter`,
|
|
47
|
+
* passed in via the constructor. The Node adapter reads from it to wire
|
|
48
|
+
* WebSocket upgrades for user-registered patterns.
|
|
49
|
+
*/
|
|
50
|
+
websocketHandlers = /* @__PURE__ */ new Map();
|
|
51
|
+
/**
|
|
52
|
+
* Wires user WebSocket routes onto a foreign Node HTTP server.
|
|
53
|
+
*
|
|
54
|
+
* Host integrations such as the Vite plugin call this so `app.websocket()`
|
|
55
|
+
* handlers work while HTTP is still served by the host dev server.
|
|
56
|
+
*/
|
|
57
|
+
attachUserWebSocketUpgrades(server, options) {
|
|
58
|
+
attachNodeHttpWebSocketUpgrades(server, {
|
|
59
|
+
runtimeOrigin: this.runtimeOrigin,
|
|
60
|
+
websocketHandlers: this.websocketHandlers,
|
|
61
|
+
passthroughUnmatched: options?.passthroughUnmatched
|
|
62
|
+
});
|
|
37
63
|
}
|
|
38
|
-
|
|
39
|
-
|
|
64
|
+
wireUserWebSocketUpgrades(server, preflight) {
|
|
65
|
+
attachNodeHttpWebSocketUpgrades(server, {
|
|
66
|
+
runtimeOrigin: this.runtimeOrigin,
|
|
67
|
+
websocketHandlers: this.websocketHandlers,
|
|
68
|
+
passthroughUnmatched: false,
|
|
69
|
+
preflight
|
|
70
|
+
});
|
|
40
71
|
}
|
|
41
72
|
async maybeInjectHmrScript(response) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
73
|
+
return maybeInjectAdapterHmrHtmlResponse(response, {
|
|
74
|
+
watch: this.options?.watch === true,
|
|
75
|
+
hmrManager: this.hmrManager ?? void 0,
|
|
76
|
+
hostOwnsDevClient: this.hostOwnsDevClient
|
|
77
|
+
});
|
|
46
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* @remarks
|
|
81
|
+
* `previewHost`, `requestBridge`, and `devRuntimeFactory` are optional on the
|
|
82
|
+
* public {@link NodeServerAdapterParams} so factory callers can omit them, but
|
|
83
|
+
* they are mandatory by the time the concrete adapter is constructed —
|
|
84
|
+
* {@link createNodeServerAdapter} fills in Node-specific defaults first. The
|
|
85
|
+
* constructor signature makes that invariant explicit instead of relying on
|
|
86
|
+
* non-null assertions.
|
|
87
|
+
*/
|
|
47
88
|
constructor(options) {
|
|
48
89
|
super(options);
|
|
90
|
+
this.deferRuntimeAssetSetup = options.deferRuntimeAssetSetup === true;
|
|
91
|
+
this.allowPortFallback = options.allowPortFallback !== false;
|
|
49
92
|
this.apiHandlers = options.apiHandlers || [];
|
|
50
93
|
this.staticRoutes = options.staticRoutes || [];
|
|
51
94
|
this.errorHandler = options.errorHandler;
|
|
52
95
|
this.previewHost = options.previewHost;
|
|
53
96
|
this.requestBridge = options.requestBridge;
|
|
54
97
|
this.devRuntimeFactory = options.devRuntimeFactory;
|
|
98
|
+
if (options.websocketHandlers) {
|
|
99
|
+
this.websocketHandlers = options.websocketHandlers;
|
|
100
|
+
}
|
|
101
|
+
this.hostOwnsDevClient = options.hostOwnsDevClient === true;
|
|
55
102
|
}
|
|
56
103
|
/**
|
|
57
104
|
* Prepares the adapter for use.
|
|
@@ -68,12 +115,14 @@ class NodeServerAdapter extends SharedServerAdapter {
|
|
|
68
115
|
*/
|
|
69
116
|
async initialize() {
|
|
70
117
|
installAppRuntimeBuildExecutor(this.appConfig);
|
|
71
|
-
this.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
118
|
+
prepareRuntimePublicDir(this.appConfig);
|
|
119
|
+
if (!this.deferRuntimeAssetSetup) {
|
|
120
|
+
await setupAppRuntimePlugins({
|
|
121
|
+
appConfig: this.appConfig,
|
|
122
|
+
runtimeOrigin: this.runtimeOrigin,
|
|
123
|
+
hmrManager: this.hmrManager ?? void 0
|
|
124
|
+
});
|
|
125
|
+
}
|
|
77
126
|
await this.initializeSharedRouteHandling({
|
|
78
127
|
staticRoutes: this.staticRoutes,
|
|
79
128
|
hmrManager: this.hmrManager ?? void 0
|
|
@@ -83,17 +132,12 @@ class NodeServerAdapter extends SharedServerAdapter {
|
|
|
83
132
|
appConfig: this.appConfig,
|
|
84
133
|
staticSiteGenerator: this.staticSiteGenerator,
|
|
85
134
|
serveOptions: this.serveOptions,
|
|
86
|
-
|
|
135
|
+
runtimeOrigin: this.runtimeOrigin,
|
|
136
|
+
needsServerBundle: this.apiHandlers.length > 0 || this.websocketHandlers.size > 0,
|
|
137
|
+
hmrManager: this.hmrManager ?? void 0
|
|
87
138
|
});
|
|
88
139
|
this.initialized = true;
|
|
89
140
|
}
|
|
90
|
-
prepareRuntimePublicDir() {
|
|
91
|
-
const srcPublicDir = path.join(this.appConfig.rootDir, this.appConfig.srcDir, this.appConfig.publicDir);
|
|
92
|
-
if (fileSystem.exists(srcPublicDir)) {
|
|
93
|
-
fileSystem.copyDir(srcPublicDir, path.join(this.appConfig.rootDir, this.appConfig.distDir));
|
|
94
|
-
}
|
|
95
|
-
fileSystem.ensureDir(path.join(this.appConfig.absolutePaths.distDir, RESOLVED_ASSETS_DIR));
|
|
96
|
-
}
|
|
97
141
|
getServerOptions() {
|
|
98
142
|
return {
|
|
99
143
|
...this.serveOptions
|
|
@@ -103,106 +147,84 @@ class NodeServerAdapter extends SharedServerAdapter {
|
|
|
103
147
|
if (!this.initialized) {
|
|
104
148
|
await this.initialize();
|
|
105
149
|
}
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
routeRendererFactory: this.routeRendererFactory,
|
|
114
|
-
staticRoutes: this.staticRoutes
|
|
115
|
-
}
|
|
116
|
-
);
|
|
117
|
-
} finally {
|
|
118
|
-
await this.stopBuildRuntimeServer(buildServer);
|
|
119
|
-
}
|
|
120
|
-
if (!options?.preview) {
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
await this.previewHost.start({
|
|
124
|
-
appConfig: this.appConfig,
|
|
125
|
-
hostname: String(this.serveOptions.hostname || DEFAULT_ECOPAGES_HOSTNAME),
|
|
126
|
-
port: Number(this.serveOptions.port || DEFAULT_ECOPAGES_PORT)
|
|
127
|
-
});
|
|
128
|
-
const previewHostname = this.serveOptions.hostname || DEFAULT_ECOPAGES_HOSTNAME;
|
|
129
|
-
const previewPort = this.serveOptions.port || DEFAULT_ECOPAGES_PORT;
|
|
130
|
-
appLogger.info(`Preview running at http://${previewHostname}:${previewPort}`);
|
|
131
|
-
}
|
|
132
|
-
async startBuildRuntimeServer() {
|
|
133
|
-
const hostname = String(this.serveOptions.hostname || DEFAULT_ECOPAGES_HOSTNAME);
|
|
134
|
-
const port = 0;
|
|
135
|
-
const server = createServer(async (req, res) => {
|
|
136
|
-
try {
|
|
137
|
-
const webRequest = this.requestBridge.createWebRequest(req, this.runtimeOrigin);
|
|
138
|
-
const response = await this.handleRequest(webRequest);
|
|
139
|
-
await this.requestBridge.sendNodeResponse(res, response);
|
|
140
|
-
} catch (error) {
|
|
141
|
-
if (error instanceof NodeClientAbortError) {
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
appLogger.error("Node static build runtime request failed", error);
|
|
145
|
-
res.statusCode = 500;
|
|
146
|
-
res.end("Internal Server Error");
|
|
150
|
+
const baseUrl = resolveServeRuntimeOrigin(this.serveOptions);
|
|
151
|
+
await this.staticBuilder.build(
|
|
152
|
+
{ baseUrl, force: options?.force },
|
|
153
|
+
{
|
|
154
|
+
router: this.router,
|
|
155
|
+
routeRendererFactory: this.routeRendererFactory,
|
|
156
|
+
staticRoutes: this.staticRoutes
|
|
147
157
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
server.listen(port, hostname, () => {
|
|
152
|
-
server.off("error", reject);
|
|
153
|
-
resolve();
|
|
154
|
-
});
|
|
155
|
-
});
|
|
156
|
-
this.serverInstance = server;
|
|
157
|
-
appLogger.info(`Server running at ${this.getListeningServerOrigin(server)}`);
|
|
158
|
-
return server;
|
|
159
|
-
}
|
|
160
|
-
getListeningServerOrigin(server) {
|
|
161
|
-
const address = server.address();
|
|
162
|
-
const hostname = String(this.serveOptions.hostname || DEFAULT_ECOPAGES_HOSTNAME);
|
|
163
|
-
if (!address || typeof address === "string") {
|
|
164
|
-
throw new Error("Build runtime server did not expose a numeric listening port");
|
|
158
|
+
);
|
|
159
|
+
if (!options?.preview) {
|
|
160
|
+
return void 0;
|
|
165
161
|
}
|
|
166
|
-
return
|
|
162
|
+
return this.startPreviewServer();
|
|
167
163
|
}
|
|
168
164
|
/**
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
* `closeAllConnections()` is called *before* `close()` because `server.close()`
|
|
172
|
-
* only stops accepting new connections — it waits for existing keep-alive
|
|
173
|
-
* connections to finish naturally, which can stall the build indefinitely.
|
|
174
|
-
* `closeAllConnections()` force-closes any lingering sockets immediately so
|
|
175
|
-
* the `close()` callback fires promptly.
|
|
176
|
-
*
|
|
177
|
-
* The `NodeClientBridge` heartbeat is also destroyed here so its `setInterval`
|
|
178
|
-
* does not prevent the Node.js process from exiting cleanly after the build.
|
|
165
|
+
* Serves an existing static export without running SSG. Used by e2e preview
|
|
166
|
+
* launchers after a shared prewarm build.
|
|
179
167
|
*/
|
|
180
|
-
async
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
168
|
+
async servePreviewOnly() {
|
|
169
|
+
if (!this.initialized) {
|
|
170
|
+
await this.initialize();
|
|
171
|
+
}
|
|
172
|
+
const distPath = path.join(this.appConfig.rootDir, this.appConfig.distDir);
|
|
173
|
+
if (!fileSystem.exists(distPath)) {
|
|
174
|
+
throw new Error(
|
|
175
|
+
`Cannot serve preview without building first: dist directory "${this.appConfig.distDir}" not found in "${this.appConfig.rootDir}".`
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
return this.startPreviewServer();
|
|
179
|
+
}
|
|
180
|
+
async startPreviewServer() {
|
|
181
|
+
const activePreviewPort = await this.previewHost.start({
|
|
182
|
+
appConfig: this.appConfig,
|
|
183
|
+
hostname: String(this.serveOptions.hostname || DEFAULT_ECOPAGES_HOSTNAME),
|
|
184
|
+
port: Number(this.serveOptions.port || DEFAULT_ECOPAGES_PORT),
|
|
185
|
+
allowPortFallback: this.allowPortFallback
|
|
190
186
|
});
|
|
191
|
-
if (
|
|
192
|
-
|
|
187
|
+
if (!activePreviewPort) {
|
|
188
|
+
return void 0;
|
|
193
189
|
}
|
|
194
|
-
this.
|
|
195
|
-
|
|
190
|
+
const previewHostname = this.serveOptions.hostname || DEFAULT_ECOPAGES_HOSTNAME;
|
|
191
|
+
return `http://${previewHostname}:${activePreviewPort}`;
|
|
196
192
|
}
|
|
197
193
|
async createAdapter() {
|
|
198
194
|
await this.initialize();
|
|
199
195
|
return {
|
|
200
196
|
getServerOptions: this.getServerOptions.bind(this),
|
|
201
197
|
buildStatic: this.buildStatic.bind(this),
|
|
198
|
+
servePreviewOnly: this.servePreviewOnly.bind(this),
|
|
202
199
|
completeInitialization: this.completeInitialization.bind(this),
|
|
203
|
-
handleRequest: this.handleRequest.bind(this)
|
|
200
|
+
handleRequest: this.handleRequest.bind(this),
|
|
201
|
+
attachUserWebSocketUpgrades: this.attachUserWebSocketUpgrades.bind(this),
|
|
202
|
+
dispose: this.dispose.bind(this)
|
|
204
203
|
};
|
|
205
204
|
}
|
|
205
|
+
/**
|
|
206
|
+
* Releases dev-time resources owned by the adapter.
|
|
207
|
+
*
|
|
208
|
+
* @remarks
|
|
209
|
+
* Safe to call multiple times. Does not stop the bound HTTP server — callers
|
|
210
|
+
* should shut down transport through the runtime host before disposing.
|
|
211
|
+
*/
|
|
212
|
+
async dispose() {
|
|
213
|
+
if (this.adapterDisposed) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
this.adapterDisposed = true;
|
|
217
|
+
await disposeDevResources({
|
|
218
|
+
projectWatcher: this.projectWatcher,
|
|
219
|
+
appConfig: this.appConfig,
|
|
220
|
+
hmrManager: this.hmrManager,
|
|
221
|
+
bridge: this.bridge,
|
|
222
|
+
previewHost: this.previewHost
|
|
223
|
+
});
|
|
224
|
+
this.projectWatcher = null;
|
|
225
|
+
this.hmrManager = null;
|
|
226
|
+
this.bridge = null;
|
|
227
|
+
}
|
|
206
228
|
/**
|
|
207
229
|
* Handles a single incoming Web `Request` and returns a Web `Response`.
|
|
208
230
|
*
|
|
@@ -244,35 +266,39 @@ class NodeServerAdapter extends SharedServerAdapter {
|
|
|
244
266
|
* - Shared watcher bootstrapping listens for route-level file changes and
|
|
245
267
|
* refreshes the router and response handlers when pages are added or removed.
|
|
246
268
|
*
|
|
247
|
-
* WebSocket upgrade requests that do not
|
|
269
|
+
* WebSocket upgrade requests that do not match a known path are rejected with an
|
|
248
270
|
* immediate socket destroy to prevent unhandled upgrade leaks.
|
|
249
271
|
*/
|
|
250
272
|
async completeInitialization(server) {
|
|
251
273
|
this.serverInstance = server;
|
|
274
|
+
const hasUserWs = this.websocketHandlers.size > 0;
|
|
252
275
|
if (this.options?.watch) {
|
|
253
276
|
const devRuntime = this.devRuntimeFactory.create({ appConfig: this.appConfig });
|
|
254
277
|
const wss = devRuntime.websocketServer;
|
|
255
278
|
this.bridge = devRuntime.bridge;
|
|
256
279
|
this.hmrManager = devRuntime.hmrManager;
|
|
257
280
|
this.hmrManager.setEnabled(true);
|
|
258
|
-
await this.hmrManager.
|
|
259
|
-
|
|
281
|
+
await this.hmrManager.ensureRuntimeReady();
|
|
282
|
+
const hmrPreflight = (req, socket, head) => {
|
|
260
283
|
const url = new URL(req.url ?? "/", this.runtimeOrigin);
|
|
261
|
-
if (url.pathname
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
284
|
+
if (url.pathname !== "/_hmr") return false;
|
|
285
|
+
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
286
|
+
this.bridge.subscribe(ws);
|
|
287
|
+
ws.on("close", () => this.bridge.unsubscribe(ws));
|
|
288
|
+
ws.on("error", (err) => appLogger.error("[HMR] WebSocket error:", err));
|
|
289
|
+
});
|
|
290
|
+
return true;
|
|
291
|
+
};
|
|
292
|
+
if (hasUserWs) {
|
|
293
|
+
this.wireUserWebSocketUpgrades(server, hmrPreflight);
|
|
294
|
+
} else {
|
|
295
|
+
server.on("upgrade", (req, socket, head) => {
|
|
296
|
+
if (!hmrPreflight(req, socket, head)) {
|
|
297
|
+
socket.destroy();
|
|
298
|
+
}
|
|
299
|
+
});
|
|
275
300
|
}
|
|
301
|
+
wireIntegrationHmrManagers(this.appConfig, this.hmrManager);
|
|
276
302
|
this.configureSharedResponseHandlers(this.staticRoutes, this.hmrManager);
|
|
277
303
|
const watcher = new ProjectWatcher({
|
|
278
304
|
config: this.appConfig,
|
|
@@ -281,9 +307,13 @@ class NodeServerAdapter extends SharedServerAdapter {
|
|
|
281
307
|
hmrManager: this.hmrManager
|
|
282
308
|
}),
|
|
283
309
|
hmrManager: this.hmrManager,
|
|
284
|
-
bridge: this.bridge
|
|
310
|
+
bridge: this.bridge,
|
|
311
|
+
hostOwnsDevClient: this.hostOwnsDevClient
|
|
285
312
|
});
|
|
313
|
+
this.projectWatcher = watcher;
|
|
286
314
|
await watcher.createWatcherSubscription();
|
|
315
|
+
} else if (hasUserWs) {
|
|
316
|
+
this.wireUserWebSocketUpgrades(server);
|
|
287
317
|
}
|
|
288
318
|
appLogger.debug("Node server adapter initialization completed", {
|
|
289
319
|
apiHandlers: this.apiHandlers.length,
|
|
@@ -161,8 +161,13 @@ class NodeStaticContentServer {
|
|
|
161
161
|
this.server = createServer(this.handleRequest.bind(this));
|
|
162
162
|
const hostname = this.options.hostname ?? DEFAULT_ECOPAGES_HOSTNAME;
|
|
163
163
|
const port = this.options.port ?? DEFAULT_ECOPAGES_PORT;
|
|
164
|
-
await new Promise((resolve) => {
|
|
165
|
-
this.server
|
|
164
|
+
await new Promise((resolve, reject) => {
|
|
165
|
+
const activeServer = this.server;
|
|
166
|
+
activeServer.once("error", reject);
|
|
167
|
+
activeServer.listen(port, hostname, () => {
|
|
168
|
+
activeServer.off("error", reject);
|
|
169
|
+
resolve();
|
|
170
|
+
});
|
|
166
171
|
});
|
|
167
172
|
return this.server;
|
|
168
173
|
}
|
|
@@ -188,6 +193,9 @@ class NodeStaticContentServer {
|
|
|
188
193
|
}
|
|
189
194
|
});
|
|
190
195
|
}
|
|
196
|
+
async [Symbol.asyncDispose]() {
|
|
197
|
+
await this.stop();
|
|
198
|
+
}
|
|
191
199
|
}
|
|
192
200
|
export {
|
|
193
201
|
NodeStaticContentServer
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { appLogger } from "../../global/app-logger.js";
|
|
2
|
+
import { PortManager } from "../shared/port-manager.js";
|
|
1
3
|
import { NodeStaticContentServer } from "./static-content-server.js";
|
|
2
4
|
class NodeStaticPreviewHost {
|
|
3
5
|
/**
|
|
@@ -20,20 +22,33 @@ class NodeStaticPreviewHost {
|
|
|
20
22
|
*/
|
|
21
23
|
async start(options) {
|
|
22
24
|
await this.stop();
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
const portManager = new PortManager({
|
|
26
|
+
startOnPort: async (port) => {
|
|
27
|
+
const previewServer = new this.previewServerFactory({
|
|
28
|
+
appConfig: options.appConfig,
|
|
29
|
+
options: {
|
|
30
|
+
hostname: options.hostname,
|
|
31
|
+
port
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
const server = await previewServer.start();
|
|
35
|
+
this.previewServer = previewServer;
|
|
36
|
+
const address = server.address();
|
|
37
|
+
if (address && typeof address === "object") {
|
|
38
|
+
return address.port;
|
|
39
|
+
}
|
|
40
|
+
return port;
|
|
41
|
+
},
|
|
42
|
+
warn: (message) => appLogger.warn(message)
|
|
43
|
+
});
|
|
44
|
+
const previewPort = await portManager.bind({
|
|
45
|
+
preferredPort: options.port,
|
|
46
|
+
allowPortFallback: options.allowPortFallback === true
|
|
29
47
|
});
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const address = server.address();
|
|
33
|
-
if (address && typeof address === "object") {
|
|
34
|
-
return address.port;
|
|
48
|
+
if (!previewPort) {
|
|
49
|
+
this.previewServer = null;
|
|
35
50
|
}
|
|
36
|
-
return
|
|
51
|
+
return previewPort;
|
|
37
52
|
}
|
|
38
53
|
/**
|
|
39
54
|
* Stops the active preview server and coalesces overlapping stop requests onto
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ServerWebSocket } from 'bun';
|
|
2
|
+
import type { EcopagesSocket, EcopagesWebSocketHandler } from '../../types/public-types.js';
|
|
3
|
+
export type BunUserWebSocketData = {
|
|
4
|
+
kind: string;
|
|
5
|
+
params: Record<string, string>;
|
|
6
|
+
search: Record<string, string>;
|
|
7
|
+
upgradeUrl?: string;
|
|
8
|
+
context?: unknown;
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
};
|
|
11
|
+
export type BunUserWebSocketLifecycleDeps<TWsData extends BunUserWebSocketData> = {
|
|
12
|
+
runtimeOrigin: string;
|
|
13
|
+
userHandlers: Map<string, EcopagesWebSocketHandler<any, any>>;
|
|
14
|
+
resolveContext: <TContext, TParams extends Record<string, string>>(request: Request, handler: EcopagesWebSocketHandler<TContext, TParams>, kind: string, params: TParams, search: Record<string, string>) => Promise<TContext>;
|
|
15
|
+
adaptSocket: <TContext, TParams extends Record<string, string>>(ws: ServerWebSocket<TWsData>, kind: string, params: TParams, search: Record<string, string>, context: TContext) => EcopagesSocket<TContext, TParams>;
|
|
16
|
+
};
|
|
17
|
+
export declare function createBunUserWebSocketLifecycle<TWsData extends BunUserWebSocketData>(deps: BunUserWebSocketLifecycleDeps<TWsData>): {
|
|
18
|
+
open(ws: ServerWebSocket<TWsData>): void;
|
|
19
|
+
message(ws: ServerWebSocket<TWsData>, msg: string | Buffer): void;
|
|
20
|
+
close(ws: ServerWebSocket<TWsData>, code: number, reason: string): void;
|
|
21
|
+
error(ws: ServerWebSocket<TWsData>, error: Error): void;
|
|
22
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { appLogger } from "../../global/app-logger.js";
|
|
2
|
+
import { invokeWebSocketHandlerHook, toWebSocketCloseInfo } from "./websocket-lifecycle.js";
|
|
3
|
+
function toUpgradeRequest(ws, runtimeOrigin) {
|
|
4
|
+
const upgradeUrl = ws.data?.upgradeUrl;
|
|
5
|
+
if (upgradeUrl) {
|
|
6
|
+
return new Request(upgradeUrl);
|
|
7
|
+
}
|
|
8
|
+
return new Request(runtimeOrigin);
|
|
9
|
+
}
|
|
10
|
+
async function runUserWebSocketOpen(ws, kind, deps) {
|
|
11
|
+
const handler = deps.userHandlers.get(kind);
|
|
12
|
+
if (!handler) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const params = ws.data?.params ?? {};
|
|
16
|
+
const search = ws.data?.search ?? {};
|
|
17
|
+
const request = toUpgradeRequest(ws, deps.runtimeOrigin);
|
|
18
|
+
let context;
|
|
19
|
+
try {
|
|
20
|
+
context = await deps.resolveContext(request, handler, kind, params, search);
|
|
21
|
+
} catch {
|
|
22
|
+
ws.close(1011, "context initialization failed");
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
ws.data.context = context;
|
|
26
|
+
const socket = deps.adaptSocket(ws, kind, params, search, context);
|
|
27
|
+
try {
|
|
28
|
+
await handler.onConnect?.(socket);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
appLogger.error(`[WS:${kind}] onConnect failed:`, error);
|
|
31
|
+
ws.close(1011, "onConnect failed");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function createBunUserWebSocketLifecycle(deps) {
|
|
35
|
+
const resolveSocketForEvent = (ws) => {
|
|
36
|
+
const kind = ws.data?.kind;
|
|
37
|
+
if (!kind) {
|
|
38
|
+
return void 0;
|
|
39
|
+
}
|
|
40
|
+
const handler = deps.userHandlers.get(kind);
|
|
41
|
+
if (!handler) {
|
|
42
|
+
return void 0;
|
|
43
|
+
}
|
|
44
|
+
const params = ws.data?.params ?? {};
|
|
45
|
+
const search = ws.data?.search ?? {};
|
|
46
|
+
const socket = deps.adaptSocket(ws, kind, params, search, ws.data?.context);
|
|
47
|
+
return { kind, handler, socket };
|
|
48
|
+
};
|
|
49
|
+
return {
|
|
50
|
+
open(ws) {
|
|
51
|
+
const kind = ws.data?.kind;
|
|
52
|
+
if (!kind) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
void runUserWebSocketOpen(ws, kind, deps).catch((error) => {
|
|
56
|
+
appLogger.error(`[WS:${kind}] open failed:`, error);
|
|
57
|
+
ws.close(1011, "internal error");
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
message(ws, msg) {
|
|
61
|
+
const resolved = resolveSocketForEvent(ws);
|
|
62
|
+
if (!resolved) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (ws.data?.context === void 0 && resolved.handler.context) {
|
|
66
|
+
appLogger.warn(`[WS:${resolved.kind}] message received before context resolved; dropping.`);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const message = typeof msg === "string" ? { kind: "text", text: msg } : { kind: "binary", data: new Uint8Array(msg.buffer, msg.byteOffset, msg.byteLength) };
|
|
70
|
+
invokeWebSocketHandlerHook(
|
|
71
|
+
resolved.kind,
|
|
72
|
+
"onMessage",
|
|
73
|
+
resolved.handler.onMessage?.(resolved.socket, message)
|
|
74
|
+
);
|
|
75
|
+
},
|
|
76
|
+
close(ws, code, reason) {
|
|
77
|
+
const resolved = resolveSocketForEvent(ws);
|
|
78
|
+
if (!resolved) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const event = toWebSocketCloseInfo(code, reason);
|
|
82
|
+
invokeWebSocketHandlerHook(resolved.kind, "onClose", resolved.handler.onClose?.(resolved.socket, event));
|
|
83
|
+
},
|
|
84
|
+
error(ws, error) {
|
|
85
|
+
const resolved = resolveSocketForEvent(ws);
|
|
86
|
+
if (!resolved) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
appLogger.error(`[WS:${resolved.kind}] error:`, error);
|
|
90
|
+
invokeWebSocketHandlerHook(resolved.kind, "onError", resolved.handler.onError?.(resolved.socket, error));
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
export {
|
|
95
|
+
createBunUserWebSocketLifecycle
|
|
96
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copies a source public directory into the runtime dist dir, skipping unchanged files.
|
|
3
|
+
*
|
|
4
|
+
* Dev restarts call this on every boot; byte comparison avoids rewriting identical assets.
|
|
5
|
+
*/
|
|
6
|
+
export declare function copyRuntimePublicDirIfChanged(sourceDir: string, destinationDir: string): void;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { readdirSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileSystem } from "@ecopages/file-system";
|
|
4
|
+
function copyRuntimePublicDirIfChanged(sourceDir, destinationDir) {
|
|
5
|
+
fileSystem.ensureDir(destinationDir);
|
|
6
|
+
for (const entry of readdirSync(sourceDir, { withFileTypes: true })) {
|
|
7
|
+
const sourcePath = path.join(sourceDir, entry.name);
|
|
8
|
+
const destinationPath = path.join(destinationDir, entry.name);
|
|
9
|
+
if (entry.isDirectory()) {
|
|
10
|
+
copyRuntimePublicDirIfChanged(sourcePath, destinationPath);
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
if (!entry.isFile()) {
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
if (fileSystem.exists(destinationPath) && Buffer.compare(fileSystem.readFileAsBuffer(sourcePath), fileSystem.readFileAsBuffer(destinationPath)) === 0) {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
fileSystem.copyFile(sourcePath, destinationPath);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
copyRuntimePublicDirIfChanged
|
|
24
|
+
};
|
|
@@ -55,6 +55,8 @@ export declare class FileSystemResponseMatcher {
|
|
|
55
55
|
* when the page template cannot be resolved.
|
|
56
56
|
*/
|
|
57
57
|
private renderCustomNotFoundResponse;
|
|
58
|
+
private renderCustomNotFoundResponseOrServerError;
|
|
59
|
+
private createInternalServerErrorResponse;
|
|
58
60
|
private createExecutionPlan;
|
|
59
61
|
/**
|
|
60
62
|
* Loads the matched page module for request-time inspection.
|