@spine-event-engine/server 2.0.0-snapshot.11
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/LICENSE +201 -0
- package/README.md +209 -0
- package/REFERENCE.md +760 -0
- package/dist/browser/browser-server.d.ts +95 -0
- package/dist/browser/browser-server.d.ts.map +1 -0
- package/dist/browser/browser-server.js +719 -0
- package/dist/browser/browser-server.js.map +1 -0
- package/dist/browser/durable-subscription-bindings.d.ts +122 -0
- package/dist/browser/durable-subscription-bindings.d.ts.map +1 -0
- package/dist/browser/durable-subscription-bindings.js +524 -0
- package/dist/browser/durable-subscription-bindings.js.map +1 -0
- package/dist/browser/index.d.ts +12 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +24 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/options.d.ts +183 -0
- package/dist/browser/options.d.ts.map +1 -0
- package/dist/browser/options.js +15 -0
- package/dist/browser/options.js.map +1 -0
- package/dist/bus/command-bus.d.ts +63 -0
- package/dist/bus/command-bus.d.ts.map +1 -0
- package/dist/bus/command-bus.js +236 -0
- package/dist/bus/command-bus.js.map +1 -0
- package/dist/bus/command-dispatcher-registry.d.ts +33 -0
- package/dist/bus/command-dispatcher-registry.d.ts.map +1 -0
- package/dist/bus/command-dispatcher-registry.js +75 -0
- package/dist/bus/command-dispatcher-registry.js.map +1 -0
- package/dist/bus/command-dispatcher.d.ts +25 -0
- package/dist/bus/command-dispatcher.d.ts.map +1 -0
- package/dist/bus/command-dispatcher.js +15 -0
- package/dist/bus/command-dispatcher.js.map +1 -0
- package/dist/bus/command-errors.d.ts +23 -0
- package/dist/bus/command-errors.d.ts.map +1 -0
- package/dist/bus/command-errors.js +52 -0
- package/dist/bus/command-errors.js.map +1 -0
- package/dist/bus/event-bus.d.ts +113 -0
- package/dist/bus/event-bus.d.ts.map +1 -0
- package/dist/bus/event-bus.js +518 -0
- package/dist/bus/event-bus.js.map +1 -0
- package/dist/bus/event-dispatcher-origin-schemas.d.ts +17 -0
- package/dist/bus/event-dispatcher-origin-schemas.d.ts.map +1 -0
- package/dist/bus/event-dispatcher-origin-schemas.js +32 -0
- package/dist/bus/event-dispatcher-origin-schemas.js.map +1 -0
- package/dist/bus/event-dispatcher-registry.d.ts +48 -0
- package/dist/bus/event-dispatcher-registry.d.ts.map +1 -0
- package/dist/bus/event-dispatcher-registry.js +176 -0
- package/dist/bus/event-dispatcher-registry.js.map +1 -0
- package/dist/bus/event-dispatcher.d.ts +48 -0
- package/dist/bus/event-dispatcher.d.ts.map +1 -0
- package/dist/bus/event-dispatcher.js +15 -0
- package/dist/bus/event-dispatcher.js.map +1 -0
- package/dist/context/bounded-context.d.ts +592 -0
- package/dist/context/bounded-context.d.ts.map +1 -0
- package/dist/context/bounded-context.js +1897 -0
- package/dist/context/bounded-context.js.map +1 -0
- package/dist/context/entity-inbox.d.ts +63 -0
- package/dist/context/entity-inbox.d.ts.map +1 -0
- package/dist/context/entity-inbox.js +387 -0
- package/dist/context/entity-inbox.js.map +1 -0
- package/dist/context/local-inbox-handoff.d.ts +248 -0
- package/dist/context/local-inbox-handoff.d.ts.map +1 -0
- package/dist/context/local-inbox-handoff.js +340 -0
- package/dist/context/local-inbox-handoff.js.map +1 -0
- package/dist/context/projection-handoff.d.ts +46 -0
- package/dist/context/projection-handoff.d.ts.map +1 -0
- package/dist/context/projection-handoff.js +177 -0
- package/dist/context/projection-handoff.js.map +1 -0
- package/dist/context/tenant-index.d.ts +41 -0
- package/dist/context/tenant-index.d.ts.map +1 -0
- package/dist/context/tenant-index.js +93 -0
- package/dist/context/tenant-index.js.map +1 -0
- package/dist/delivery/conditional-pickup.d.ts +25 -0
- package/dist/delivery/conditional-pickup.d.ts.map +1 -0
- package/dist/delivery/conditional-pickup.js +26 -0
- package/dist/delivery/conditional-pickup.js.map +1 -0
- package/dist/delivery/delivery-builder.d.ts +216 -0
- package/dist/delivery/delivery-builder.d.ts.map +1 -0
- package/dist/delivery/delivery-builder.js +323 -0
- package/dist/delivery/delivery-builder.js.map +1 -0
- package/dist/delivery/delivery-lease.d.ts +15 -0
- package/dist/delivery/delivery-lease.d.ts.map +1 -0
- package/dist/delivery/delivery-lease.js +44 -0
- package/dist/delivery/delivery-lease.js.map +1 -0
- package/dist/delivery/delivery-loop.d.ts +113 -0
- package/dist/delivery/delivery-loop.d.ts.map +1 -0
- package/dist/delivery/delivery-loop.js +119 -0
- package/dist/delivery/delivery-loop.js.map +1 -0
- package/dist/delivery/delivery-monitor.d.ts +165 -0
- package/dist/delivery/delivery-monitor.d.ts.map +1 -0
- package/dist/delivery/delivery-monitor.js +168 -0
- package/dist/delivery/delivery-monitor.js.map +1 -0
- package/dist/delivery/delivery-ports.d.ts +151 -0
- package/dist/delivery/delivery-ports.d.ts.map +1 -0
- package/dist/delivery/delivery-ports.js +15 -0
- package/dist/delivery/delivery-ports.js.map +1 -0
- package/dist/delivery/delivery-run-control.d.ts +50 -0
- package/dist/delivery/delivery-run-control.d.ts.map +1 -0
- package/dist/delivery/delivery-run-control.js +66 -0
- package/dist/delivery/delivery-run-control.js.map +1 -0
- package/dist/delivery/delivery-run-coordinator.d.ts +218 -0
- package/dist/delivery/delivery-run-coordinator.d.ts.map +1 -0
- package/dist/delivery/delivery-run-coordinator.js +609 -0
- package/dist/delivery/delivery-run-coordinator.js.map +1 -0
- package/dist/delivery/delivery-storage-error.d.ts +13 -0
- package/dist/delivery/delivery-storage-error.d.ts.map +1 -0
- package/dist/delivery/delivery-storage-error.js +30 -0
- package/dist/delivery/delivery-storage-error.js.map +1 -0
- package/dist/delivery/delivery-supervisor.d.ts +175 -0
- package/dist/delivery/delivery-supervisor.d.ts.map +1 -0
- package/dist/delivery/delivery-supervisor.js +469 -0
- package/dist/delivery/delivery-supervisor.js.map +1 -0
- package/dist/delivery/delivery-worker.d.ts +180 -0
- package/dist/delivery/delivery-worker.d.ts.map +1 -0
- package/dist/delivery/delivery-worker.js +232 -0
- package/dist/delivery/delivery-worker.js.map +1 -0
- package/dist/delivery/delivery.d.ts +236 -0
- package/dist/delivery/delivery.d.ts.map +1 -0
- package/dist/delivery/delivery.js +539 -0
- package/dist/delivery/delivery.js.map +1 -0
- package/dist/delivery/inbox-records.d.ts +19 -0
- package/dist/delivery/inbox-records.d.ts.map +1 -0
- package/dist/delivery/inbox-records.js +291 -0
- package/dist/delivery/inbox-records.js.map +1 -0
- package/dist/delivery/inbox-storage.d.ts +83 -0
- package/dist/delivery/inbox-storage.d.ts.map +1 -0
- package/dist/delivery/inbox-storage.js +336 -0
- package/dist/delivery/inbox-storage.js.map +1 -0
- package/dist/delivery/inbox.d.ts +272 -0
- package/dist/delivery/inbox.d.ts.map +1 -0
- package/dist/delivery/inbox.js +183 -0
- package/dist/delivery/inbox.js.map +1 -0
- package/dist/delivery/parked-delivery-obligations.d.ts +182 -0
- package/dist/delivery/parked-delivery-obligations.d.ts.map +1 -0
- package/dist/delivery/parked-delivery-obligations.js +390 -0
- package/dist/delivery/parked-delivery-obligations.js.map +1 -0
- package/dist/delivery/shard-index.d.ts +41 -0
- package/dist/delivery/shard-index.d.ts.map +1 -0
- package/dist/delivery/shard-index.js +67 -0
- package/dist/delivery/shard-index.js.map +1 -0
- package/dist/delivery/sharded-work-registry.d.ts +114 -0
- package/dist/delivery/sharded-work-registry.d.ts.map +1 -0
- package/dist/delivery/sharded-work-registry.js +361 -0
- package/dist/delivery/sharded-work-registry.js.map +1 -0
- package/dist/entity/entity-metadata.d.ts +173 -0
- package/dist/entity/entity-metadata.d.ts.map +1 -0
- package/dist/entity/entity-metadata.js +187 -0
- package/dist/entity/entity-metadata.js.map +1 -0
- package/dist/entity/entity-storage-descriptor.d.ts +64 -0
- package/dist/entity/entity-storage-descriptor.d.ts.map +1 -0
- package/dist/entity/entity-storage-descriptor.js +227 -0
- package/dist/entity/entity-storage-descriptor.js.map +1 -0
- package/dist/entity/entity-transaction.d.ts +372 -0
- package/dist/entity/entity-transaction.d.ts.map +1 -0
- package/dist/entity/entity-transaction.js +413 -0
- package/dist/entity/entity-transaction.js.map +1 -0
- package/dist/entity/entity-transition-validation.d.ts +47 -0
- package/dist/entity/entity-transition-validation.d.ts.map +1 -0
- package/dist/entity/entity-transition-validation.js +327 -0
- package/dist/entity/entity-transition-validation.js.map +1 -0
- package/dist/entity/entity.d.ts +605 -0
- package/dist/entity/entity.d.ts.map +1 -0
- package/dist/entity/entity.js +981 -0
- package/dist/entity/entity.js.map +1 -0
- package/dist/entity/implicit-required-id.d.ts +15 -0
- package/dist/entity/implicit-required-id.d.ts.map +1 -0
- package/dist/entity/implicit-required-id.js +123 -0
- package/dist/entity/implicit-required-id.js.map +1 -0
- package/dist/entity/spec-scanner.d.ts +14 -0
- package/dist/entity/spec-scanner.d.ts.map +1 -0
- package/dist/entity/spec-scanner.js +37 -0
- package/dist/entity/spec-scanner.js.map +1 -0
- package/dist/handler/command-registration-readiness.d.ts +99 -0
- package/dist/handler/command-registration-readiness.d.ts.map +1 -0
- package/dist/handler/command-registration-readiness.js +120 -0
- package/dist/handler/command-registration-readiness.js.map +1 -0
- package/dist/handler/declared-rejections.d.ts +11 -0
- package/dist/handler/declared-rejections.d.ts.map +1 -0
- package/dist/handler/declared-rejections.js +34 -0
- package/dist/handler/declared-rejections.js.map +1 -0
- package/dist/handler/event-handler-filter.d.ts +43 -0
- package/dist/handler/event-handler-filter.d.ts.map +1 -0
- package/dist/handler/event-handler-filter.js +128 -0
- package/dist/handler/event-handler-filter.js.map +1 -0
- package/dist/handler/event-registration-readiness.d.ts +196 -0
- package/dist/handler/event-registration-readiness.d.ts.map +1 -0
- package/dist/handler/event-registration-readiness.js +187 -0
- package/dist/handler/event-registration-readiness.js.map +1 -0
- package/dist/handler/external.d.ts +10 -0
- package/dist/handler/external.d.ts.map +1 -0
- package/dist/handler/external.js +15 -0
- package/dist/handler/external.js.map +1 -0
- package/dist/handler/generated-handler-registry.d.ts +185 -0
- package/dist/handler/generated-handler-registry.d.ts.map +1 -0
- package/dist/handler/generated-handler-registry.js +439 -0
- package/dist/handler/generated-handler-registry.js.map +1 -0
- package/dist/handler/generated-registry-discovery.d.ts +94 -0
- package/dist/handler/generated-registry-discovery.d.ts.map +1 -0
- package/dist/handler/generated-registry-discovery.js +226 -0
- package/dist/handler/generated-registry-discovery.js.map +1 -0
- package/dist/handler/handler-decorators.d.ts +151 -0
- package/dist/handler/handler-decorators.d.ts.map +1 -0
- package/dist/handler/handler-decorators.js +275 -0
- package/dist/handler/handler-decorators.js.map +1 -0
- package/dist/handler/handler-metadata.d.ts +553 -0
- package/dist/handler/handler-metadata.d.ts.map +1 -0
- package/dist/handler/handler-metadata.js +437 -0
- package/dist/handler/handler-metadata.js.map +1 -0
- package/dist/handler/registration-readiness-metadata.d.ts +68 -0
- package/dist/handler/registration-readiness-metadata.d.ts.map +1 -0
- package/dist/handler/registration-readiness-metadata.js +171 -0
- package/dist/handler/registration-readiness-metadata.js.map +1 -0
- package/dist/handler/rejection-source.d.ts +11 -0
- package/dist/handler/rejection-source.d.ts.map +1 -0
- package/dist/handler/rejection-source.js +25 -0
- package/dist/handler/rejection-source.js.map +1 -0
- package/dist/handler/standalone.d.ts +25 -0
- package/dist/handler/standalone.d.ts.map +1 -0
- package/dist/handler/standalone.js +38 -0
- package/dist/handler/standalone.js.map +1 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -0
- package/dist/integration/external-messages.d.ts +49 -0
- package/dist/integration/external-messages.d.ts.map +1 -0
- package/dist/integration/external-messages.js +112 -0
- package/dist/integration/external-messages.js.map +1 -0
- package/dist/integration/integration-broker.d.ts +74 -0
- package/dist/integration/integration-broker.d.ts.map +1 -0
- package/dist/integration/integration-broker.js +444 -0
- package/dist/integration/integration-broker.js.map +1 -0
- package/dist/integration/third-party-context.d.ts +56 -0
- package/dist/integration/third-party-context.d.ts.map +1 -0
- package/dist/integration/third-party-context.js +130 -0
- package/dist/integration/third-party-context.js.map +1 -0
- package/dist/repository/command-errors.d.ts +25 -0
- package/dist/repository/command-errors.d.ts.map +1 -0
- package/dist/repository/command-errors.js +43 -0
- package/dist/repository/command-errors.js.map +1 -0
- package/dist/repository/command-routing.d.ts +72 -0
- package/dist/repository/command-routing.d.ts.map +1 -0
- package/dist/repository/command-routing.js +98 -0
- package/dist/repository/command-routing.js.map +1 -0
- package/dist/repository/commit-fence.d.ts +22 -0
- package/dist/repository/commit-fence.d.ts.map +1 -0
- package/dist/repository/commit-fence.js +37 -0
- package/dist/repository/commit-fence.js.map +1 -0
- package/dist/repository/event-routing.d.ts +71 -0
- package/dist/repository/event-routing.d.ts.map +1 -0
- package/dist/repository/event-routing.js +96 -0
- package/dist/repository/event-routing.js.map +1 -0
- package/dist/repository/primitive-id.d.ts +75 -0
- package/dist/repository/primitive-id.d.ts.map +1 -0
- package/dist/repository/primitive-id.js +85 -0
- package/dist/repository/primitive-id.js.map +1 -0
- package/dist/repository/repository.d.ts +667 -0
- package/dist/repository/repository.d.ts.map +1 -0
- package/dist/repository/repository.js +3510 -0
- package/dist/repository/repository.js.map +1 -0
- package/dist/repository/routing-declarations.d.ts +75 -0
- package/dist/repository/routing-declarations.d.ts.map +1 -0
- package/dist/repository/routing-declarations.js +101 -0
- package/dist/repository/routing-declarations.js.map +1 -0
- package/dist/repository/state-update-routing.d.ts +66 -0
- package/dist/repository/state-update-routing.d.ts.map +1 -0
- package/dist/repository/state-update-routing.js +91 -0
- package/dist/repository/state-update-routing.js.map +1 -0
- package/dist/runtime/runtime.d.ts +156 -0
- package/dist/runtime/runtime.d.ts.map +1 -0
- package/dist/runtime/runtime.js +215 -0
- package/dist/runtime/runtime.js.map +1 -0
- package/dist/runtime/signal-intake.d.ts +84 -0
- package/dist/runtime/signal-intake.d.ts.map +1 -0
- package/dist/runtime/signal-intake.js +94 -0
- package/dist/runtime/signal-intake.js.map +1 -0
- package/dist/runtime/signal-metadata.d.ts +217 -0
- package/dist/runtime/signal-metadata.d.ts.map +1 -0
- package/dist/runtime/signal-metadata.js +333 -0
- package/dist/runtime/signal-metadata.js.map +1 -0
- package/dist/runtime/signal-publisher.d.ts +144 -0
- package/dist/runtime/signal-publisher.d.ts.map +1 -0
- package/dist/runtime/signal-publisher.js +248 -0
- package/dist/runtime/signal-publisher.js.map +1 -0
- package/dist/runtime/standalone-handler-runtime.d.ts +114 -0
- package/dist/runtime/standalone-handler-runtime.d.ts.map +1 -0
- package/dist/runtime/standalone-handler-runtime.js +307 -0
- package/dist/runtime/standalone-handler-runtime.js.map +1 -0
- package/dist/server/environment-attachment.d.ts +356 -0
- package/dist/server/environment-attachment.d.ts.map +1 -0
- package/dist/server/environment-attachment.js +2062 -0
- package/dist/server/environment-attachment.js.map +1 -0
- package/dist/server/environment-delivery-records.d.ts +77 -0
- package/dist/server/environment-delivery-records.d.ts.map +1 -0
- package/dist/server/environment-delivery-records.js +282 -0
- package/dist/server/environment-delivery-records.js.map +1 -0
- package/dist/server/environment-delivery-worker.d.ts +161 -0
- package/dist/server/environment-delivery-worker.d.ts.map +1 -0
- package/dist/server/environment-delivery-worker.js +673 -0
- package/dist/server/environment-delivery-worker.js.map +1 -0
- package/dist/server/environment.d.ts +43 -0
- package/dist/server/environment.d.ts.map +1 -0
- package/dist/server/environment.js +90 -0
- package/dist/server/environment.js.map +1 -0
- package/dist/server/managed-child-subscription.d.ts +11 -0
- package/dist/server/managed-child-subscription.d.ts.map +1 -0
- package/dist/server/managed-child-subscription.js +44 -0
- package/dist/server/managed-child-subscription.js.map +1 -0
- package/dist/server/managed-server-application.d.ts +327 -0
- package/dist/server/managed-server-application.d.ts.map +1 -0
- package/dist/server/managed-server-application.js +937 -0
- package/dist/server/managed-server-application.js.map +1 -0
- package/dist/server/node-coordinator.d.ts +191 -0
- package/dist/server/node-coordinator.d.ts.map +1 -0
- package/dist/server/node-coordinator.js +552 -0
- package/dist/server/node-coordinator.js.map +1 -0
- package/dist/server/process-server-coordinator.d.ts +15 -0
- package/dist/server/process-server-coordinator.d.ts.map +1 -0
- package/dist/server/process-server-coordinator.js +112 -0
- package/dist/server/process-server-coordinator.js.map +1 -0
- package/dist/server/reserved-spine-rpc-paths.json +8 -0
- package/dist/server/retryable-close.d.ts +28 -0
- package/dist/server/retryable-close.d.ts.map +1 -0
- package/dist/server/retryable-close.js +129 -0
- package/dist/server/retryable-close.js.map +1 -0
- package/dist/server/server-environment.d.ts +180 -0
- package/dist/server/server-environment.d.ts.map +1 -0
- package/dist/server/server-environment.js +418 -0
- package/dist/server/server-environment.js.map +1 -0
- package/dist/server/server-log.d.ts +18 -0
- package/dist/server/server-log.d.ts.map +1 -0
- package/dist/server/server-log.js +100 -0
- package/dist/server/server-log.js.map +1 -0
- package/dist/server/server.d.ts +221 -0
- package/dist/server/server.d.ts.map +1 -0
- package/dist/server/server.js +704 -0
- package/dist/server/server.js.map +1 -0
- package/dist/services/query-reader.d.ts +19 -0
- package/dist/services/query-reader.d.ts.map +1 -0
- package/dist/services/query-reader.js +43 -0
- package/dist/services/query-reader.js.map +1 -0
- package/dist/services/spine-services.d.ts +88 -0
- package/dist/services/spine-services.d.ts.map +1 -0
- package/dist/services/spine-services.js +1582 -0
- package/dist/services/spine-services.js.map +1 -0
- package/dist/spi/delivery.d.ts +5 -0
- package/dist/spi/delivery.d.ts.map +1 -0
- package/dist/spi/delivery.js +18 -0
- package/dist/spi/delivery.js.map +1 -0
- package/dist/spi/handler-registry.d.ts +8 -0
- package/dist/spi/handler-registry.d.ts.map +1 -0
- package/dist/spi/handler-registry.js +15 -0
- package/dist/spi/handler-registry.js.map +1 -0
- package/dist/stand/stand.d.ts +294 -0
- package/dist/stand/stand.d.ts.map +1 -0
- package/dist/stand/stand.js +681 -0
- package/dist/stand/stand.js.map +1 -0
- package/dist/stand/subscription-observer.d.ts +53 -0
- package/dist/stand/subscription-observer.d.ts.map +1 -0
- package/dist/stand/subscription-observer.js +444 -0
- package/dist/stand/subscription-observer.js.map +1 -0
- package/dist/stand/subscription-records.d.ts +12 -0
- package/dist/stand/subscription-records.d.ts.map +1 -0
- package/dist/stand/subscription-records.js +99 -0
- package/dist/stand/subscription-records.js.map +1 -0
- package/dist/stand/subscription-registry.d.ts +285 -0
- package/dist/stand/subscription-registry.d.ts.map +1 -0
- package/dist/stand/subscription-registry.js +403 -0
- package/dist/stand/subscription-registry.js.map +1 -0
- package/dist/stand/subscription-runtime.d.ts +102 -0
- package/dist/stand/subscription-runtime.d.ts.map +1 -0
- package/dist/stand/subscription-runtime.js +380 -0
- package/dist/stand/subscription-runtime.js.map +1 -0
- package/dist/testing/index.d.ts +36 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +54 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +76 -0
|
@@ -0,0 +1,704 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026, CodeMatters. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
5
|
+
* in compliance with the License. You may obtain a copy of the License at
|
|
6
|
+
*
|
|
7
|
+
* https://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
*
|
|
9
|
+
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
10
|
+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
11
|
+
* or implied. See the License for the specific language governing permissions and limitations under
|
|
12
|
+
* the License.
|
|
13
|
+
*/
|
|
14
|
+
import * as http2 from "node:http2";
|
|
15
|
+
import { connectNodeAdapter } from "@connectrpc/connect-node";
|
|
16
|
+
import { BoundedContext, BoundedContextBuilder, boundedContextAccess, } from "../context/bounded-context.js";
|
|
17
|
+
import { SpineServices, spineServicesAccess, } from "../services/spine-services.js";
|
|
18
|
+
import { ProcessServerCoordinator } from "./process-server-coordinator.js";
|
|
19
|
+
import { CloseErrors, RetryableCloseGroup } from "./retryable-close.js";
|
|
20
|
+
import { ServerEnvironment, serverEnvironmentAccess } from "./server-environment.js";
|
|
21
|
+
const defaultHost = "127.0.0.1";
|
|
22
|
+
const defaultPort = 0;
|
|
23
|
+
const defaultMessageMaxBytes = 4_194_304;
|
|
24
|
+
const maximumMessageMaxBytes = 0xffff_ffff;
|
|
25
|
+
const gracefulSessionDrainMs = 100;
|
|
26
|
+
const runningContexts = new WeakMap();
|
|
27
|
+
const serverHosts = new WeakMap();
|
|
28
|
+
/**
|
|
29
|
+
* Configures and starts local Spine Connect/gRPC-compatible services.
|
|
30
|
+
*
|
|
31
|
+
* A server assembles its bounded contexts, completes finite environment
|
|
32
|
+
* delivery recovery, and opens its generated services before accepting network
|
|
33
|
+
* requests. It also owns the ordered cleanup of contexts and resources added
|
|
34
|
+
* to this assembly.
|
|
35
|
+
*/
|
|
36
|
+
export class Server {
|
|
37
|
+
#host;
|
|
38
|
+
#port;
|
|
39
|
+
#readMaxBytes;
|
|
40
|
+
#writeMaxBytes;
|
|
41
|
+
#contexts = [];
|
|
42
|
+
#resources = [];
|
|
43
|
+
#listenerLifecycles = [];
|
|
44
|
+
#services;
|
|
45
|
+
#environment;
|
|
46
|
+
#starting;
|
|
47
|
+
#startingOwnership;
|
|
48
|
+
#run;
|
|
49
|
+
#failedStartCleanup;
|
|
50
|
+
#failedListenerLifecycle;
|
|
51
|
+
#failedStartConsumed = false;
|
|
52
|
+
/**
|
|
53
|
+
* Creates a server builder.
|
|
54
|
+
*
|
|
55
|
+
* @param options Configures local network, contexts, resources, and services.
|
|
56
|
+
*/
|
|
57
|
+
constructor(options = {}) {
|
|
58
|
+
this.#host = ServerValues.normalizeHost(options.host);
|
|
59
|
+
this.#port = options.port ?? defaultPort;
|
|
60
|
+
this.#readMaxBytes = ServerValues.normalizeMessageMaxBytes(options.readMaxBytes ?? defaultMessageMaxBytes, "readMaxBytes");
|
|
61
|
+
this.#writeMaxBytes = ServerValues.normalizeMessageMaxBytes(options.writeMaxBytes ?? defaultMessageMaxBytes, "writeMaxBytes");
|
|
62
|
+
this.#contexts.push(...(options.contexts ?? []));
|
|
63
|
+
this.#resources.push(...(options.resources ?? []));
|
|
64
|
+
this.#services = options.services ?? {};
|
|
65
|
+
this.#environment = ServerEnvironment.instance();
|
|
66
|
+
serverHosts.set(this, this.#host);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Creates a local-only server builder for one port.
|
|
70
|
+
*
|
|
71
|
+
* @param port Selects the listener port, or zero for an ephemeral port.
|
|
72
|
+
* @param options Supplies all server options except the port.
|
|
73
|
+
* @returns A configured server builder.
|
|
74
|
+
*/
|
|
75
|
+
static atPort(port, options = {}) {
|
|
76
|
+
return new Server({ ...options, port });
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Adds one bounded context or builder to the assembly.
|
|
80
|
+
*
|
|
81
|
+
* Builders assemble during {@link start} before recovery and listener open.
|
|
82
|
+
* They use {@link ServerEnvironment.storageFactory} unless a more specific
|
|
83
|
+
* `withStorageFactory(...)` factory is selected. The running server owns and
|
|
84
|
+
* closes added contexts only after services, sessions, and active work stop.
|
|
85
|
+
*
|
|
86
|
+
* @param context Supplies the context or builder to expose.
|
|
87
|
+
* @returns This server builder.
|
|
88
|
+
*/
|
|
89
|
+
add(context) {
|
|
90
|
+
this.#contexts.push(context);
|
|
91
|
+
return this;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Adds a framework closeable owned by this server assembly.
|
|
95
|
+
*
|
|
96
|
+
* @param resource Supplies the resource to close after contexts.
|
|
97
|
+
* @returns This server builder.
|
|
98
|
+
*/
|
|
99
|
+
addResource(resource) {
|
|
100
|
+
this.#resources.push(resource);
|
|
101
|
+
return this;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Adds work that starts after listener readiness and closes before network intake stops.
|
|
105
|
+
*
|
|
106
|
+
* Failed starts roll back admitted lifecycles in reverse admission order. A
|
|
107
|
+
* failed close remains retryable and prevents network shutdown until it settles.
|
|
108
|
+
*
|
|
109
|
+
* @param lifecycle Supplies listener-coupled lifecycle work, such as GCE registration.
|
|
110
|
+
* @returns This server builder.
|
|
111
|
+
*/
|
|
112
|
+
addListenerLifecycle(lifecycle) {
|
|
113
|
+
this.#listenerLifecycles.push(lifecycle);
|
|
114
|
+
return this;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Starts the server after completing assembly and delivery recovery.
|
|
118
|
+
*
|
|
119
|
+
* Built contexts attach to delivery in deterministic input order before the
|
|
120
|
+
* generated services and listener open. A failed assembly or listener open
|
|
121
|
+
* leaves no listener and closes acquired resources. Network cleanup is a hard
|
|
122
|
+
* gate before delivery or dependencies close.
|
|
123
|
+
* It shares only a caller-managed active environment generation, rejects
|
|
124
|
+
* while run-managed ownership is active, installs no signal handlers, and
|
|
125
|
+
* never closes the environment.
|
|
126
|
+
* A later call after incomplete cleanup retries only that cleanup and leaves
|
|
127
|
+
* this server terminal. A fresh server may reuse the singleton environment.
|
|
128
|
+
* Concurrent callers share one start or cleanup attempt.
|
|
129
|
+
*
|
|
130
|
+
* @returns The running server once its listener accepts requests.
|
|
131
|
+
*/
|
|
132
|
+
start() {
|
|
133
|
+
return this.#start("caller");
|
|
134
|
+
}
|
|
135
|
+
#start(ownership) {
|
|
136
|
+
const current = this.#starting;
|
|
137
|
+
if (current !== undefined) {
|
|
138
|
+
if (this.#startingOwnership !== ownership) {
|
|
139
|
+
return Promise.reject(new Error("Server cannot mix caller-managed and run-managed startup attempts."));
|
|
140
|
+
}
|
|
141
|
+
return current;
|
|
142
|
+
}
|
|
143
|
+
if (this.#failedStartConsumed) {
|
|
144
|
+
return Promise.reject(new Error("Server cannot restart after failed-start cleanup has completed."));
|
|
145
|
+
}
|
|
146
|
+
const cleanup = this.#failedStartCleanup;
|
|
147
|
+
const lifecycle = this.#failedListenerLifecycle;
|
|
148
|
+
const starting = lifecycle !== undefined
|
|
149
|
+
? this.#retryFailedListenerLifecycle(lifecycle)
|
|
150
|
+
: cleanup === undefined
|
|
151
|
+
? this.#startOnce(ownership)
|
|
152
|
+
: this.#retryFailedStartCleanup(cleanup);
|
|
153
|
+
this.#starting = starting;
|
|
154
|
+
this.#startingOwnership = ownership;
|
|
155
|
+
void starting.then(() => {
|
|
156
|
+
this.#finishStart(starting);
|
|
157
|
+
}, () => {
|
|
158
|
+
this.#finishStart(starting);
|
|
159
|
+
});
|
|
160
|
+
return starting;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Starts this server with process-owned `SIGINT` and `SIGTERM` shutdown.
|
|
164
|
+
*
|
|
165
|
+
* This is the normal application entry point. Embedded applications should
|
|
166
|
+
* use {@link start} and keep ownership of process signals themselves.
|
|
167
|
+
* Concurrent calls on one builder return one managed handle. Run-managed
|
|
168
|
+
* siblings share an active generation but reject while caller-managed
|
|
169
|
+
* ownership is active. The final local environment-owning run retirement
|
|
170
|
+
* permanently closes its environment. A failed final
|
|
171
|
+
* close stays retryable through `close()` or a later process signal.
|
|
172
|
+
* Caller-managed servers never close their environment.
|
|
173
|
+
*
|
|
174
|
+
* @returns The running server after its listener accepts requests.
|
|
175
|
+
*/
|
|
176
|
+
run() {
|
|
177
|
+
const current = this.#run;
|
|
178
|
+
if (current !== undefined)
|
|
179
|
+
return current;
|
|
180
|
+
const environment = this.#environment;
|
|
181
|
+
const running = this.#start("server").then((server) => ProcessServerCoordinator.add(server, environment, serverEnvironmentAccess.loggerFor(environment), () => {
|
|
182
|
+
if (this.#run === running) {
|
|
183
|
+
this.#run = undefined;
|
|
184
|
+
}
|
|
185
|
+
}));
|
|
186
|
+
this.#run = running;
|
|
187
|
+
void running.catch(() => {
|
|
188
|
+
if (this.#run === running) {
|
|
189
|
+
this.#run = undefined;
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
return running;
|
|
193
|
+
}
|
|
194
|
+
async #startOnce(ownership) {
|
|
195
|
+
const contexts = await ServerValues.buildContexts(this.#contexts, this.#environment.storageFactory);
|
|
196
|
+
const logger = serverEnvironmentAccess.loggerFor(this.#environment);
|
|
197
|
+
for (const context of contexts) {
|
|
198
|
+
boundedContextAccess.installLogger(context, logger);
|
|
199
|
+
serverEnvironmentAccess.warnVolatileRegistry(this.#environment, context);
|
|
200
|
+
}
|
|
201
|
+
let attachment;
|
|
202
|
+
try {
|
|
203
|
+
attachment = await serverEnvironmentAccess.attach(this.#environment, {
|
|
204
|
+
ownership,
|
|
205
|
+
descriptors: contexts.map((context) => boundedContextAccess.delivery(context)),
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
const closeGroup = new RetryableCloseGroup([...contexts, ...this.#resources], "Server start cleanup failed while closing owned contexts/resources.");
|
|
210
|
+
if (serverEnvironmentAccess.failedStartRetryPending(this.#environment, error)) {
|
|
211
|
+
this.#failedStartCleanup = {
|
|
212
|
+
closeGroup,
|
|
213
|
+
failedStartRollback: { rejection: error },
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
try {
|
|
218
|
+
await closeGroup.close();
|
|
219
|
+
}
|
|
220
|
+
catch (cleanupError) {
|
|
221
|
+
this.#failedStartCleanup = {
|
|
222
|
+
closeGroup,
|
|
223
|
+
failedStartRollback: undefined,
|
|
224
|
+
};
|
|
225
|
+
throw ServerValues.attachmentCleanupError(error, cleanupError);
|
|
226
|
+
}
|
|
227
|
+
this.#failedStartConsumed = true;
|
|
228
|
+
}
|
|
229
|
+
throw error;
|
|
230
|
+
}
|
|
231
|
+
const closeables = [...contexts, ...this.#resources];
|
|
232
|
+
const services = new SpineServices({
|
|
233
|
+
contexts,
|
|
234
|
+
...this.#services,
|
|
235
|
+
});
|
|
236
|
+
spineServicesAccess.installLogger(services, logger);
|
|
237
|
+
const sessions = new Set();
|
|
238
|
+
const httpServer = ServerValues.createHttpServer(services, sessions, this.#readMaxBytes, this.#writeMaxBytes);
|
|
239
|
+
const listener = { host: this.#host, port: this.#port };
|
|
240
|
+
const address = await ServerValues.listen(httpServer, listener.host, listener.port).catch(async (error) => {
|
|
241
|
+
const cleanup = {
|
|
242
|
+
closeGroup: new RetryableCloseGroup(closeables, "Server start cleanup failed while closing owned contexts/resources."),
|
|
243
|
+
network: { server: httpServer, sessions },
|
|
244
|
+
attachment,
|
|
245
|
+
failedStartRollback: undefined,
|
|
246
|
+
};
|
|
247
|
+
this.#failedStartCleanup = cleanup;
|
|
248
|
+
return this.#cleanupFailedListenerStart(cleanup, error);
|
|
249
|
+
});
|
|
250
|
+
const host = typeof address.address === "string" ? address.address : this.#host;
|
|
251
|
+
const running = new RunningHttp2Server({
|
|
252
|
+
server: httpServer,
|
|
253
|
+
sessions,
|
|
254
|
+
environment: this.#environment,
|
|
255
|
+
attachment,
|
|
256
|
+
services,
|
|
257
|
+
host,
|
|
258
|
+
port: address.port,
|
|
259
|
+
closeables,
|
|
260
|
+
listenerLifecycles: this.#listenerLifecycles,
|
|
261
|
+
});
|
|
262
|
+
runningContexts.set(running, contexts);
|
|
263
|
+
try {
|
|
264
|
+
await running.startLifecycles();
|
|
265
|
+
}
|
|
266
|
+
catch (error) {
|
|
267
|
+
if (running.hasPendingClose())
|
|
268
|
+
this.#failedListenerLifecycle = running;
|
|
269
|
+
else
|
|
270
|
+
this.#failedStartConsumed = true;
|
|
271
|
+
throw error;
|
|
272
|
+
}
|
|
273
|
+
return running;
|
|
274
|
+
}
|
|
275
|
+
async #retryFailedStartCleanup(cleanup) {
|
|
276
|
+
const errors = [];
|
|
277
|
+
if (!(await this.#closeFailedStartNetwork(cleanup, errors))) {
|
|
278
|
+
ServerValues.throwCleanupErrors(errors);
|
|
279
|
+
}
|
|
280
|
+
await this.#advanceFailedStartCleanup(cleanup, errors);
|
|
281
|
+
if (errors.length > 0) {
|
|
282
|
+
ServerValues.throwCleanupErrors(errors);
|
|
283
|
+
}
|
|
284
|
+
throw new Error("Server deferred cleanup completed after an earlier failed start.");
|
|
285
|
+
}
|
|
286
|
+
async #retryFailedListenerLifecycle(running) {
|
|
287
|
+
await running.close();
|
|
288
|
+
this.#failedListenerLifecycle = undefined;
|
|
289
|
+
this.#failedStartConsumed = true;
|
|
290
|
+
throw new Error("Server deferred cleanup completed after an earlier failed start.");
|
|
291
|
+
}
|
|
292
|
+
async #cleanupFailedListenerStart(cleanup, startError) {
|
|
293
|
+
const errors = [];
|
|
294
|
+
if (!(await this.#closeFailedStartNetwork(cleanup, errors))) {
|
|
295
|
+
return ServerValues.throwListenerStartError(startError, errors);
|
|
296
|
+
}
|
|
297
|
+
await this.#advanceFailedStartCleanup(cleanup, errors);
|
|
298
|
+
return ServerValues.throwListenerStartError(startError, errors);
|
|
299
|
+
}
|
|
300
|
+
async #advanceFailedStartCleanup(cleanup, errors) {
|
|
301
|
+
if (!(await this.#advanceFailedStartAttachment(cleanup, errors))) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
const failedStartRollback = cleanup.failedStartRollback;
|
|
305
|
+
if (failedStartRollback !== undefined &&
|
|
306
|
+
serverEnvironmentAccess.failedStartRetryPending(this.#environment, failedStartRollback.rejection)) {
|
|
307
|
+
try {
|
|
308
|
+
await serverEnvironmentAccess.retryFailedStart(this.#environment);
|
|
309
|
+
}
|
|
310
|
+
catch (error) {
|
|
311
|
+
if (serverEnvironmentAccess.failedStartRetryPending(this.#environment, failedStartRollback.rejection)) {
|
|
312
|
+
throw error;
|
|
313
|
+
}
|
|
314
|
+
CloseErrors.collect(error, errors);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
let closeFailed = false;
|
|
318
|
+
try {
|
|
319
|
+
await cleanup.closeGroup.close();
|
|
320
|
+
}
|
|
321
|
+
catch (error) {
|
|
322
|
+
closeFailed = true;
|
|
323
|
+
CloseErrors.collect(error, errors);
|
|
324
|
+
}
|
|
325
|
+
if (!closeFailed && cleanup.attachment === undefined && this.#failedStartCleanup === cleanup) {
|
|
326
|
+
this.#failedStartCleanup = undefined;
|
|
327
|
+
this.#failedStartConsumed = true;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
async #closeFailedStartNetwork(cleanup, errors) {
|
|
331
|
+
const network = cleanup.network;
|
|
332
|
+
if (network === undefined) {
|
|
333
|
+
return true;
|
|
334
|
+
}
|
|
335
|
+
try {
|
|
336
|
+
await ServerValues.closeNetwork(network.server, network.sessions);
|
|
337
|
+
delete cleanup.network;
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
catch (error) {
|
|
341
|
+
CloseErrors.collect(error, errors);
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
async #advanceFailedStartAttachment(cleanup, errors) {
|
|
346
|
+
const attachment = cleanup.attachment;
|
|
347
|
+
if (attachment === undefined) {
|
|
348
|
+
return true;
|
|
349
|
+
}
|
|
350
|
+
try {
|
|
351
|
+
if (serverEnvironmentAccess.detachRetryPending(this.#environment, attachment)) {
|
|
352
|
+
await serverEnvironmentAccess.retryDetach(this.#environment, attachment);
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
await serverEnvironmentAccess.detach(this.#environment, attachment);
|
|
356
|
+
}
|
|
357
|
+
delete cleanup.attachment;
|
|
358
|
+
return true;
|
|
359
|
+
}
|
|
360
|
+
catch (error) {
|
|
361
|
+
CloseErrors.collect(error, errors);
|
|
362
|
+
}
|
|
363
|
+
try {
|
|
364
|
+
if (serverEnvironmentAccess.endpointSafe(this.#environment, attachment)) {
|
|
365
|
+
return true;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
catch (error) {
|
|
369
|
+
CloseErrors.collect(error, errors);
|
|
370
|
+
}
|
|
371
|
+
return false;
|
|
372
|
+
}
|
|
373
|
+
#finishStart(starting) {
|
|
374
|
+
if (this.#starting === starting) {
|
|
375
|
+
this.#starting = undefined;
|
|
376
|
+
this.#startingOwnership = undefined;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Checks whether browser composition may start a private native listener.
|
|
382
|
+
*
|
|
383
|
+
* @internal
|
|
384
|
+
*/
|
|
385
|
+
export const serverBuilderAccess = Object.freeze({
|
|
386
|
+
isLoopback(server) {
|
|
387
|
+
const host = serverHosts.get(server);
|
|
388
|
+
return host !== undefined && isLoopbackHost(host);
|
|
389
|
+
},
|
|
390
|
+
});
|
|
391
|
+
function isLoopbackHost(host) {
|
|
392
|
+
if (host === "::1" || host === "::ffff:127.0.0.1")
|
|
393
|
+
return true;
|
|
394
|
+
const match = /^127\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/u.exec(host);
|
|
395
|
+
return match?.slice(1).every((part) => Number(part) <= 255) === true;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Provides framework-only `RunningServer` context facts.
|
|
399
|
+
*
|
|
400
|
+
* @internal
|
|
401
|
+
*/
|
|
402
|
+
export const runningServerAccess = Object.freeze({
|
|
403
|
+
subscriptionRegistries(server) {
|
|
404
|
+
return runningContexts
|
|
405
|
+
.get(server)
|
|
406
|
+
?.map((context) => boundedContextAccess.subscriptionRegistry(context));
|
|
407
|
+
},
|
|
408
|
+
drainDelivery(server) {
|
|
409
|
+
return server instanceof RunningHttp2Server ? server.drainDelivery() : Promise.resolve();
|
|
410
|
+
},
|
|
411
|
+
});
|
|
412
|
+
class RunningHttp2Server {
|
|
413
|
+
#server;
|
|
414
|
+
#sessions;
|
|
415
|
+
#closeables;
|
|
416
|
+
#listenerLifecycles;
|
|
417
|
+
#startedLifecycles = [];
|
|
418
|
+
#environment;
|
|
419
|
+
#attachment;
|
|
420
|
+
#services;
|
|
421
|
+
host;
|
|
422
|
+
port;
|
|
423
|
+
baseUrl;
|
|
424
|
+
#closed;
|
|
425
|
+
#networkClosed = false;
|
|
426
|
+
#attachmentDetached = false;
|
|
427
|
+
#closeGroup;
|
|
428
|
+
constructor(options) {
|
|
429
|
+
this.#server = options.server;
|
|
430
|
+
this.#sessions = options.sessions;
|
|
431
|
+
this.#closeables = options.closeables;
|
|
432
|
+
this.#listenerLifecycles = options.listenerLifecycles;
|
|
433
|
+
this.#environment = options.environment;
|
|
434
|
+
this.#attachment = options.attachment;
|
|
435
|
+
this.#services = options.services;
|
|
436
|
+
this.host = options.host;
|
|
437
|
+
this.port = options.port;
|
|
438
|
+
this.baseUrl = `http://${ServerValues.formatHostForUrl(options.host)}:${options.port.toString()}`;
|
|
439
|
+
this.#closeGroup = new RetryableCloseGroup(this.#closeables, "Server close failed while closing owned contexts/resources.");
|
|
440
|
+
}
|
|
441
|
+
close() {
|
|
442
|
+
this.#closed ??= this.#closeOnce().catch((error) => {
|
|
443
|
+
this.#closed = undefined;
|
|
444
|
+
throw error;
|
|
445
|
+
});
|
|
446
|
+
return this.#closed;
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Starts listener-ready attachments after the native listener accepts connections.
|
|
450
|
+
*
|
|
451
|
+
* @returns Completes after all attachments start or their admitted rollback settles.
|
|
452
|
+
*/
|
|
453
|
+
async startLifecycles() {
|
|
454
|
+
try {
|
|
455
|
+
for (const lifecycle of this.#listenerLifecycles) {
|
|
456
|
+
await lifecycle.start();
|
|
457
|
+
this.#startedLifecycles.push(lifecycle);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
catch (error) {
|
|
461
|
+
try {
|
|
462
|
+
await this.close();
|
|
463
|
+
}
|
|
464
|
+
catch (rollback) {
|
|
465
|
+
throw new AggregateError([error, rollback], "Server listener lifecycle start and rollback failed.");
|
|
466
|
+
}
|
|
467
|
+
throw error;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
hasPendingClose() {
|
|
471
|
+
return this.#closed === undefined;
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Drains the server-owned Delivery attachment while network sessions remain available.
|
|
475
|
+
*
|
|
476
|
+
* @returns Completion after the attachment drains.
|
|
477
|
+
*/
|
|
478
|
+
async drainDelivery() {
|
|
479
|
+
if (this.#attachmentDetached)
|
|
480
|
+
return;
|
|
481
|
+
if (serverEnvironmentAccess.detachRetryPending(this.#environment, this.#attachment)) {
|
|
482
|
+
await serverEnvironmentAccess.retryDetach(this.#environment, this.#attachment);
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
await serverEnvironmentAccess.detach(this.#environment, this.#attachment);
|
|
486
|
+
}
|
|
487
|
+
this.#attachmentDetached = true;
|
|
488
|
+
}
|
|
489
|
+
async #closeOnce() {
|
|
490
|
+
while (this.#startedLifecycles.length > 0) {
|
|
491
|
+
const lifecycle = this.#startedLifecycles.at(-1);
|
|
492
|
+
if (lifecycle === undefined)
|
|
493
|
+
break;
|
|
494
|
+
await lifecycle.close();
|
|
495
|
+
this.#startedLifecycles.pop();
|
|
496
|
+
}
|
|
497
|
+
if (!this.#networkClosed) {
|
|
498
|
+
await ServerValues.closeNetwork(this.#server, this.#sessions);
|
|
499
|
+
this.#networkClosed = true;
|
|
500
|
+
}
|
|
501
|
+
const detachErrors = [];
|
|
502
|
+
let detachRejected = false;
|
|
503
|
+
if (!this.#attachmentDetached) {
|
|
504
|
+
try {
|
|
505
|
+
if (serverEnvironmentAccess.detachRetryPending(this.#environment, this.#attachment)) {
|
|
506
|
+
await serverEnvironmentAccess.retryDetach(this.#environment, this.#attachment);
|
|
507
|
+
}
|
|
508
|
+
else {
|
|
509
|
+
await serverEnvironmentAccess.detach(this.#environment, this.#attachment);
|
|
510
|
+
}
|
|
511
|
+
this.#attachmentDetached = true;
|
|
512
|
+
}
|
|
513
|
+
catch (error) {
|
|
514
|
+
detachRejected = true;
|
|
515
|
+
CloseErrors.collect(error, detachErrors);
|
|
516
|
+
}
|
|
517
|
+
if (detachRejected) {
|
|
518
|
+
let endpointSafe = false;
|
|
519
|
+
try {
|
|
520
|
+
endpointSafe = serverEnvironmentAccess.endpointSafe(this.#environment, this.#attachment);
|
|
521
|
+
}
|
|
522
|
+
catch (error) {
|
|
523
|
+
CloseErrors.collect(error, detachErrors);
|
|
524
|
+
}
|
|
525
|
+
if (!endpointSafe) {
|
|
526
|
+
ServerValues.throwRunningDetachErrors(detachErrors);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
try {
|
|
531
|
+
await this.#closeGroup.close();
|
|
532
|
+
}
|
|
533
|
+
catch (error) {
|
|
534
|
+
if (!detachRejected) {
|
|
535
|
+
throw error;
|
|
536
|
+
}
|
|
537
|
+
CloseErrors.collect(error, detachErrors);
|
|
538
|
+
throw new AggregateError(detachErrors, "Server close failed while detaching delivery and closing owned contexts/resources.");
|
|
539
|
+
}
|
|
540
|
+
if (detachRejected) {
|
|
541
|
+
ServerValues.throwRunningDetachErrors(detachErrors);
|
|
542
|
+
}
|
|
543
|
+
spineServicesAccess.clearLogger(this.#services);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
*
|
|
548
|
+
* @internal Groups private server assembly, network, and shutdown operations.
|
|
549
|
+
*/
|
|
550
|
+
const ServerValues = Object.freeze({
|
|
551
|
+
async buildContexts(entries, defaultStorageFactory) {
|
|
552
|
+
const contexts = [];
|
|
553
|
+
try {
|
|
554
|
+
for (const entry of entries) {
|
|
555
|
+
contexts.push(boundedContextAccess.isBuilder(entry)
|
|
556
|
+
? await boundedContextAccess.build(entry, defaultStorageFactory)
|
|
557
|
+
: entry);
|
|
558
|
+
}
|
|
559
|
+
return contexts;
|
|
560
|
+
}
|
|
561
|
+
catch (error) {
|
|
562
|
+
await ServerValues.cleanupBuiltContexts(contexts, error);
|
|
563
|
+
throw error;
|
|
564
|
+
}
|
|
565
|
+
},
|
|
566
|
+
createHttpServer(services, sessions, readMaxBytes, writeMaxBytes) {
|
|
567
|
+
const server = http2.createServer(connectNodeAdapter({
|
|
568
|
+
routes: (router) => {
|
|
569
|
+
services.register(router);
|
|
570
|
+
},
|
|
571
|
+
readMaxBytes,
|
|
572
|
+
writeMaxBytes,
|
|
573
|
+
}));
|
|
574
|
+
server.on("session", (session) => {
|
|
575
|
+
sessions.add(session);
|
|
576
|
+
session.on("close", () => sessions.delete(session));
|
|
577
|
+
});
|
|
578
|
+
return server;
|
|
579
|
+
},
|
|
580
|
+
listen(server, host, port) {
|
|
581
|
+
return new Promise((resolve, reject) => {
|
|
582
|
+
const cleanup = () => {
|
|
583
|
+
server.off("error", onError);
|
|
584
|
+
server.off("listening", onListening);
|
|
585
|
+
};
|
|
586
|
+
const onError = (error) => {
|
|
587
|
+
cleanup();
|
|
588
|
+
reject(error);
|
|
589
|
+
};
|
|
590
|
+
const onListening = () => {
|
|
591
|
+
cleanup();
|
|
592
|
+
resolve(server.address());
|
|
593
|
+
};
|
|
594
|
+
server.once("error", onError);
|
|
595
|
+
server.once("listening", onListening);
|
|
596
|
+
server.listen(port, host);
|
|
597
|
+
});
|
|
598
|
+
},
|
|
599
|
+
async cleanupBuiltContexts(contexts, startError) {
|
|
600
|
+
try {
|
|
601
|
+
await new RetryableCloseGroup(contexts, "Server start cleanup failed while closing owned contexts/resources.").close();
|
|
602
|
+
}
|
|
603
|
+
catch (error) {
|
|
604
|
+
throw new AggregateError([startError, ...ServerValues.toCleanupErrors(error)], "Server start failed while building bounded contexts.");
|
|
605
|
+
}
|
|
606
|
+
},
|
|
607
|
+
toCleanupErrors(error) {
|
|
608
|
+
if (error instanceof AggregateError) {
|
|
609
|
+
return error.errors;
|
|
610
|
+
}
|
|
611
|
+
return [error];
|
|
612
|
+
},
|
|
613
|
+
attachmentCleanupError(startError, cleanupError) {
|
|
614
|
+
const errors = [];
|
|
615
|
+
CloseErrors.collect(startError, errors);
|
|
616
|
+
CloseErrors.collect(cleanupError, errors);
|
|
617
|
+
return new AggregateError(errors, "Server attachment failed and immediate dependency cleanup also failed.");
|
|
618
|
+
},
|
|
619
|
+
throwCleanupErrors(errors) {
|
|
620
|
+
if (errors.length === 1) {
|
|
621
|
+
throw errors[0];
|
|
622
|
+
}
|
|
623
|
+
throw new AggregateError(errors, "Server deferred failed-start cleanup failed.");
|
|
624
|
+
},
|
|
625
|
+
throwListenerStartError(startError, cleanupErrors) {
|
|
626
|
+
if (cleanupErrors.length === 0) {
|
|
627
|
+
throw startError;
|
|
628
|
+
}
|
|
629
|
+
const errors = [];
|
|
630
|
+
CloseErrors.collect(startError, errors);
|
|
631
|
+
for (const error of cleanupErrors) {
|
|
632
|
+
CloseErrors.collect(error, errors);
|
|
633
|
+
}
|
|
634
|
+
throw new AggregateError(errors, "Server start failed while opening listener and cleanup also failed.");
|
|
635
|
+
},
|
|
636
|
+
throwRunningDetachErrors(errors) {
|
|
637
|
+
if (errors.length === 1) {
|
|
638
|
+
throw errors[0];
|
|
639
|
+
}
|
|
640
|
+
throw new AggregateError(errors, "Server close failed while detaching delivery.");
|
|
641
|
+
},
|
|
642
|
+
async closeNetwork(server, sessions) {
|
|
643
|
+
const closed = ServerValues.closeHttpServer(server);
|
|
644
|
+
await ServerValues.closeSessions(sessions);
|
|
645
|
+
await closed;
|
|
646
|
+
await ServerValues.nextTurn();
|
|
647
|
+
},
|
|
648
|
+
closeHttpServer(server) {
|
|
649
|
+
return new Promise((resolve, reject) => {
|
|
650
|
+
if (!server.listening) {
|
|
651
|
+
resolve();
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
server.close((error) => {
|
|
655
|
+
if (error) {
|
|
656
|
+
reject(error);
|
|
657
|
+
}
|
|
658
|
+
else {
|
|
659
|
+
resolve();
|
|
660
|
+
}
|
|
661
|
+
});
|
|
662
|
+
});
|
|
663
|
+
},
|
|
664
|
+
async closeSessions(sessions) {
|
|
665
|
+
await Promise.all([...sessions].map((session) => ServerValues.closeSession(session)));
|
|
666
|
+
},
|
|
667
|
+
closeSession(session) {
|
|
668
|
+
return new Promise((resolve) => {
|
|
669
|
+
const timer = setTimeout(() => {
|
|
670
|
+
session.destroy();
|
|
671
|
+
resolve();
|
|
672
|
+
}, gracefulSessionDrainMs);
|
|
673
|
+
const finishGracefulClose = () => {
|
|
674
|
+
clearTimeout(timer);
|
|
675
|
+
resolve();
|
|
676
|
+
};
|
|
677
|
+
timer.unref();
|
|
678
|
+
session.once("close", finishGracefulClose);
|
|
679
|
+
session.close();
|
|
680
|
+
});
|
|
681
|
+
},
|
|
682
|
+
nextTurn() {
|
|
683
|
+
return new Promise((resolve) => {
|
|
684
|
+
setImmediate(resolve);
|
|
685
|
+
});
|
|
686
|
+
},
|
|
687
|
+
formatHostForUrl(host) {
|
|
688
|
+
return host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
|
|
689
|
+
},
|
|
690
|
+
normalizeHost(host) {
|
|
691
|
+
const normalized = host?.trim() ?? defaultHost;
|
|
692
|
+
if (normalized.length === 0) {
|
|
693
|
+
throw new Error("Server host must not be blank.");
|
|
694
|
+
}
|
|
695
|
+
return normalized;
|
|
696
|
+
},
|
|
697
|
+
normalizeMessageMaxBytes(value, name) {
|
|
698
|
+
if (!Number.isInteger(value) || value < 1 || value > maximumMessageMaxBytes) {
|
|
699
|
+
throw new Error(`Server ${name} must be an integer from 1 through 4294967295.`);
|
|
700
|
+
}
|
|
701
|
+
return value;
|
|
702
|
+
},
|
|
703
|
+
});
|
|
704
|
+
//# sourceMappingURL=server.js.map
|