@cosmicdrift/kumiko-framework 0.1.0
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 +159 -0
- package/package.json +91 -0
- package/src/__tests__/anonymous-access.integration.ts +325 -0
- package/src/__tests__/error-contract.integration.ts +435 -0
- package/src/__tests__/field-access.integration.ts +269 -0
- package/src/__tests__/full-stack.integration.ts +914 -0
- package/src/__tests__/ownership.integration.ts +449 -0
- package/src/__tests__/reference-data.integration.ts +198 -0
- package/src/__tests__/transition-guard.integration.ts +340 -0
- package/src/api/__tests__/api.test.ts +337 -0
- package/src/api/__tests__/auth-middleware-transport.test.ts +80 -0
- package/src/api/__tests__/auth-routes-cookie.test.ts +179 -0
- package/src/api/__tests__/batch.integration.ts +404 -0
- package/src/api/__tests__/body-limit.test.ts +88 -0
- package/src/api/__tests__/csrf-middleware.test.ts +97 -0
- package/src/api/__tests__/dispatcher-live.integration.ts +216 -0
- package/src/api/__tests__/metrics-endpoint.test.ts +126 -0
- package/src/api/__tests__/nested-write.integration.ts +213 -0
- package/src/api/__tests__/readiness.test.ts +76 -0
- package/src/api/__tests__/request-id-middleware.test.ts +72 -0
- package/src/api/__tests__/sse-broker.test.ts +58 -0
- package/src/api/__tests__/sse-route.test.ts +112 -0
- package/src/api/anonymous-cookie.ts +60 -0
- package/src/api/api-constants.ts +64 -0
- package/src/api/auth-middleware.ts +418 -0
- package/src/api/auth-routes.ts +982 -0
- package/src/api/csrf-middleware.ts +77 -0
- package/src/api/index.ts +31 -0
- package/src/api/jwt.ts +66 -0
- package/src/api/observability-middleware.ts +89 -0
- package/src/api/readiness.ts +132 -0
- package/src/api/request-context.ts +49 -0
- package/src/api/request-id-middleware.ts +50 -0
- package/src/api/route-registrars.ts +195 -0
- package/src/api/routes.ts +135 -0
- package/src/api/server.ts +640 -0
- package/src/api/sse-broker.ts +71 -0
- package/src/api/sse-route.ts +62 -0
- package/src/api/tokens.ts +16 -0
- package/src/db/__tests__/apply-entity-event-tenant.integration.ts +159 -0
- package/src/db/__tests__/compound-types.test.ts +114 -0
- package/src/db/__tests__/connection-options.test.ts +68 -0
- package/src/db/__tests__/cursor.test.ts +41 -0
- package/src/db/__tests__/db-helpers.test.ts +369 -0
- package/src/db/__tests__/dialect-instant.test.ts +50 -0
- package/src/db/__tests__/drizzle-helpers.integration.ts +186 -0
- package/src/db/__tests__/drizzle-table-types.test.ts +162 -0
- package/src/db/__tests__/encryption.test.ts +39 -0
- package/src/db/__tests__/event-store-executor-list.integration.ts +313 -0
- package/src/db/__tests__/event-store-executor.integration.ts +235 -0
- package/src/db/__tests__/implicit-projection-equivalence.integration.ts +304 -0
- package/src/db/__tests__/located-timestamp.test.ts +184 -0
- package/src/db/__tests__/money.test.ts +199 -0
- package/src/db/__tests__/multi-row-insert.integration.ts +76 -0
- package/src/db/__tests__/parse-auto-verb.test.ts +70 -0
- package/src/db/__tests__/required-not-null-migration-safety.integration.ts +105 -0
- package/src/db/__tests__/row-helpers.test.ts +59 -0
- package/src/db/__tests__/schema-migration.integration.ts +273 -0
- package/src/db/__tests__/table-builder-indexes.test.ts +153 -0
- package/src/db/__tests__/table-builder-required.test.ts +216 -0
- package/src/db/__tests__/tenant-db.integration.ts +606 -0
- package/src/db/__tests__/unique-violation-mapping.integration.ts +166 -0
- package/src/db/apply-entity-event.ts +188 -0
- package/src/db/assert-exists-in.ts +59 -0
- package/src/db/compound-types.ts +47 -0
- package/src/db/connection.ts +104 -0
- package/src/db/cursor.ts +83 -0
- package/src/db/dialect.ts +109 -0
- package/src/db/eagerload.ts +174 -0
- package/src/db/encryption.ts +39 -0
- package/src/db/event-store-executor.ts +906 -0
- package/src/db/index.ts +55 -0
- package/src/db/located-timestamp.ts +114 -0
- package/src/db/money.ts +120 -0
- package/src/db/pg-error.ts +46 -0
- package/src/db/reference-data.ts +77 -0
- package/src/db/row-helpers.ts +53 -0
- package/src/db/schema-inspection.ts +25 -0
- package/src/db/table-builder.ts +475 -0
- package/src/db/tenant-db.ts +434 -0
- package/src/engine/__tests__/auth-claims-registrar.test.ts +74 -0
- package/src/engine/__tests__/boot-validator-located-timestamps.test.ts +108 -0
- package/src/engine/__tests__/boot-validator.test.ts +1865 -0
- package/src/engine/__tests__/build-app-schema.test.ts +154 -0
- package/src/engine/__tests__/claim-keys.test.ts +274 -0
- package/src/engine/__tests__/config-helpers.test.ts +236 -0
- package/src/engine/__tests__/effective-features.test.ts +86 -0
- package/src/engine/__tests__/engine.test.ts +1461 -0
- package/src/engine/__tests__/entity-handlers.test.ts +274 -0
- package/src/engine/__tests__/event-helpers.test.ts +68 -0
- package/src/engine/__tests__/extends-registrar.test.ts +159 -0
- package/src/engine/__tests__/factories-long-text.test.ts +84 -0
- package/src/engine/__tests__/factories-time.test.ts +158 -0
- package/src/engine/__tests__/field-predicates.test.ts +48 -0
- package/src/engine/__tests__/hook-phases.test.ts +132 -0
- package/src/engine/__tests__/identifiers.test.ts +35 -0
- package/src/engine/__tests__/lifecycle-hooks.test.ts +237 -0
- package/src/engine/__tests__/nav.test.ts +267 -0
- package/src/engine/__tests__/ownership.test.ts +421 -0
- package/src/engine/__tests__/parse-ref-target.test.ts +43 -0
- package/src/engine/__tests__/projection-helpers.test.ts +62 -0
- package/src/engine/__tests__/projection.test.ts +191 -0
- package/src/engine/__tests__/qualified-name.test.ts +264 -0
- package/src/engine/__tests__/resolve-config-or-param.test.ts +315 -0
- package/src/engine/__tests__/run-in.test.ts +38 -0
- package/src/engine/__tests__/schema-builder.test.ts +380 -0
- package/src/engine/__tests__/screen.test.ts +408 -0
- package/src/engine/__tests__/state-machine.test.ts +148 -0
- package/src/engine/__tests__/system-user.test.ts +57 -0
- package/src/engine/__tests__/validation-hooks.test.ts +71 -0
- package/src/engine/access.ts +23 -0
- package/src/engine/boot-validator.ts +1528 -0
- package/src/engine/build-app-schema.ts +125 -0
- package/src/engine/config-helpers.ts +115 -0
- package/src/engine/constants.ts +85 -0
- package/src/engine/create-app.ts +98 -0
- package/src/engine/define-feature.ts +702 -0
- package/src/engine/define-handler.ts +78 -0
- package/src/engine/define-roles.ts +19 -0
- package/src/engine/effective-features.ts +87 -0
- package/src/engine/entity-handlers.ts +364 -0
- package/src/engine/event-helpers.ts +73 -0
- package/src/engine/factories.ts +328 -0
- package/src/engine/feature-ast/__tests__/canonical-form.test.ts +416 -0
- package/src/engine/feature-ast/__tests__/parse-happy-path.test.ts +197 -0
- package/src/engine/feature-ast/__tests__/parse-real-features.test.ts +128 -0
- package/src/engine/feature-ast/__tests__/parse.test.ts +888 -0
- package/src/engine/feature-ast/__tests__/patch.test.ts +360 -0
- package/src/engine/feature-ast/__tests__/patcher.test.ts +469 -0
- package/src/engine/feature-ast/__tests__/render-roundtrip.test.ts +287 -0
- package/src/engine/feature-ast/extractors.ts +2562 -0
- package/src/engine/feature-ast/index.ts +105 -0
- package/src/engine/feature-ast/parse.ts +369 -0
- package/src/engine/feature-ast/patch.ts +525 -0
- package/src/engine/feature-ast/patcher.ts +518 -0
- package/src/engine/feature-ast/patterns.ts +434 -0
- package/src/engine/feature-ast/render.ts +602 -0
- package/src/engine/feature-ast/source-location.ts +45 -0
- package/src/engine/field-access.ts +120 -0
- package/src/engine/index.ts +254 -0
- package/src/engine/ownership.ts +337 -0
- package/src/engine/parse-ref-target.ts +22 -0
- package/src/engine/pattern-library/__tests__/library.test.ts +351 -0
- package/src/engine/pattern-library/index.ts +24 -0
- package/src/engine/pattern-library/library.ts +1117 -0
- package/src/engine/pattern-library/types.ts +255 -0
- package/src/engine/projection-helpers.ts +85 -0
- package/src/engine/qualified-name.ts +122 -0
- package/src/engine/read-claim.ts +31 -0
- package/src/engine/registry.ts +1325 -0
- package/src/engine/resolve-config-or-param.ts +153 -0
- package/src/engine/run-in.ts +29 -0
- package/src/engine/schema-builder.ts +175 -0
- package/src/engine/screen-filter-ops.ts +51 -0
- package/src/engine/state-machine.ts +70 -0
- package/src/engine/system-user.ts +32 -0
- package/src/engine/types/config.ts +306 -0
- package/src/engine/types/event-type-map.ts +37 -0
- package/src/engine/types/feature.ts +574 -0
- package/src/engine/types/fields.ts +422 -0
- package/src/engine/types/handlers.ts +742 -0
- package/src/engine/types/hooks.ts +142 -0
- package/src/engine/types/http-route.ts +54 -0
- package/src/engine/types/identifiers.ts +47 -0
- package/src/engine/types/index.ts +208 -0
- package/src/engine/types/nav.ts +46 -0
- package/src/engine/types/projection.ts +132 -0
- package/src/engine/types/relations.ts +51 -0
- package/src/engine/types/screen.ts +452 -0
- package/src/engine/types/workspace.ts +42 -0
- package/src/engine/validation.ts +33 -0
- package/src/entrypoint/__tests__/entrypoint-job-wiring.integration.ts +173 -0
- package/src/entrypoint/__tests__/split-deploy.integration.ts +297 -0
- package/src/entrypoint/index.ts +442 -0
- package/src/errors/__tests__/classes.test.ts +371 -0
- package/src/errors/__tests__/write-failures.test.ts +109 -0
- package/src/errors/classes.ts +249 -0
- package/src/errors/i18n/de.yaml +83 -0
- package/src/errors/i18n/en.yaml +80 -0
- package/src/errors/index.ts +41 -0
- package/src/errors/kumiko-error.ts +67 -0
- package/src/errors/reasons.ts +36 -0
- package/src/errors/serialize.ts +136 -0
- package/src/errors/transition-details.ts +30 -0
- package/src/errors/write-error-info.ts +123 -0
- package/src/errors/zod-bridge.ts +49 -0
- package/src/event-store/__tests__/admin-api.integration.ts +361 -0
- package/src/event-store/__tests__/event-store.integration.ts +584 -0
- package/src/event-store/__tests__/get-stream-version-perf.integration.ts +83 -0
- package/src/event-store/__tests__/perf.integration.ts +255 -0
- package/src/event-store/__tests__/snapshot.integration.ts +267 -0
- package/src/event-store/__tests__/upcaster-dead-letter.integration.ts +204 -0
- package/src/event-store/__tests__/upcaster.integration.ts +460 -0
- package/src/event-store/admin-api.ts +257 -0
- package/src/event-store/archive.ts +106 -0
- package/src/event-store/errors.ts +35 -0
- package/src/event-store/event-store.ts +405 -0
- package/src/event-store/events-schema.ts +90 -0
- package/src/event-store/index.ts +50 -0
- package/src/event-store/snapshot.ts +210 -0
- package/src/event-store/upcaster-dead-letter.ts +119 -0
- package/src/event-store/upcaster.ts +147 -0
- package/src/files/__tests__/content-disposition.test.ts +123 -0
- package/src/files/__tests__/file-field-column.integration.ts +103 -0
- package/src/files/__tests__/file-field-pipeline.integration.ts +211 -0
- package/src/files/__tests__/file-handle.test.ts +122 -0
- package/src/files/__tests__/files.integration.ts +830 -0
- package/src/files/__tests__/storage-tracking.integration.ts +153 -0
- package/src/files/content-disposition.ts +55 -0
- package/src/files/file-handle.ts +63 -0
- package/src/files/file-ref-table.ts +22 -0
- package/src/files/file-routes.ts +353 -0
- package/src/files/in-memory-provider.ts +62 -0
- package/src/files/index.ts +29 -0
- package/src/files/local-provider.ts +35 -0
- package/src/files/storage-tracking.ts +60 -0
- package/src/files/types.ts +118 -0
- package/src/i18n/__tests__/i18n.test.ts +72 -0
- package/src/i18n/index.ts +29 -0
- package/src/jobs/__tests__/job-event-trigger.integration.ts +172 -0
- package/src/jobs/__tests__/job-multi-trigger.integration.ts +144 -0
- package/src/jobs/__tests__/jobs.integration.ts +566 -0
- package/src/jobs/index.ts +2 -0
- package/src/jobs/job-runner.ts +574 -0
- package/src/lifecycle/__tests__/create-test-lifecycle.ts +19 -0
- package/src/lifecycle/__tests__/lifecycle-server.integration.ts +108 -0
- package/src/lifecycle/__tests__/lifecycle.test.ts +212 -0
- package/src/lifecycle/__tests__/signal-handlers.test.ts +106 -0
- package/src/lifecycle/index.ts +13 -0
- package/src/lifecycle/lifecycle.ts +160 -0
- package/src/lifecycle/signal-handlers.ts +62 -0
- package/src/logging/__tests__/pino-trace-bridge.test.ts +50 -0
- package/src/logging/index.ts +3 -0
- package/src/logging/pino-logger.ts +64 -0
- package/src/logging/types.ts +7 -0
- package/src/migrations/__tests__/compare-snapshots.test.ts +150 -0
- package/src/migrations/__tests__/detect-drift.integration.ts +320 -0
- package/src/migrations/__tests__/detect-projections-to-rebuild.integration.ts +134 -0
- package/src/migrations/__tests__/rebuild-marker.test.ts +79 -0
- package/src/migrations/index.ts +28 -0
- package/src/migrations/projection-detection.ts +149 -0
- package/src/migrations/rebuild-marker.ts +64 -0
- package/src/migrations/schema-drift.ts +395 -0
- package/src/observability/__tests__/console-provider.test.ts +67 -0
- package/src/observability/__tests__/metric-validator.test.ts +87 -0
- package/src/observability/__tests__/noop-provider.test.ts +82 -0
- package/src/observability/__tests__/observability.integration.ts +559 -0
- package/src/observability/__tests__/prometheus-meter.test.ts +144 -0
- package/src/observability/__tests__/recording-meter.test.ts +101 -0
- package/src/observability/__tests__/recording-tracer.test.ts +110 -0
- package/src/observability/__tests__/sensitive-filter.test.ts +98 -0
- package/src/observability/console-provider.ts +130 -0
- package/src/observability/context.ts +26 -0
- package/src/observability/fallback.ts +34 -0
- package/src/observability/ids.ts +25 -0
- package/src/observability/index.ts +79 -0
- package/src/observability/metric-validator.ts +86 -0
- package/src/observability/metrics-handle.ts +56 -0
- package/src/observability/noop-provider.ts +146 -0
- package/src/observability/prometheus-meter.ts +284 -0
- package/src/observability/recording-meter.ts +156 -0
- package/src/observability/recording-tracer.ts +198 -0
- package/src/observability/redis-wrapper.ts +132 -0
- package/src/observability/sensitive-filter.ts +108 -0
- package/src/observability/standard-metrics.ts +213 -0
- package/src/observability/types/index.ts +29 -0
- package/src/observability/types/metric.ts +56 -0
- package/src/observability/types/provider.ts +32 -0
- package/src/observability/types/span.ts +64 -0
- package/src/pipeline/__tests__/archive-stream.integration.ts +220 -0
- package/src/pipeline/__tests__/auth-claims-resolver.test.ts +279 -0
- package/src/pipeline/__tests__/cascade-handler.integration.ts +419 -0
- package/src/pipeline/__tests__/cascade-handler.test.ts +52 -0
- package/src/pipeline/__tests__/causation-chain.integration.ts +206 -0
- package/src/pipeline/__tests__/ctx-bridge.integration.ts +234 -0
- package/src/pipeline/__tests__/dispatcher.test.ts +379 -0
- package/src/pipeline/__tests__/distributed-lock.integration.ts +67 -0
- package/src/pipeline/__tests__/domain-events-projections.integration.ts +323 -0
- package/src/pipeline/__tests__/event-dedup.integration.ts +153 -0
- package/src/pipeline/__tests__/event-define-event-strict.integration.ts +202 -0
- package/src/pipeline/__tests__/event-dispatcher-lifecycle.integration.ts +220 -0
- package/src/pipeline/__tests__/event-dispatcher-multi-instance.integration.ts +423 -0
- package/src/pipeline/__tests__/event-dispatcher-pg-listen.integration.ts +123 -0
- package/src/pipeline/__tests__/event-dispatcher-recovery.integration.ts +202 -0
- package/src/pipeline/__tests__/event-dispatcher-second-audit.integration.ts +290 -0
- package/src/pipeline/__tests__/event-dispatcher-strict.test.ts +65 -0
- package/src/pipeline/__tests__/event-dispatcher.integration.ts +287 -0
- package/src/pipeline/__tests__/event-retention.integration.ts +239 -0
- package/src/pipeline/__tests__/fetch-for-writing.integration.ts +281 -0
- package/src/pipeline/__tests__/lifecycle-pipeline.test.ts +430 -0
- package/src/pipeline/__tests__/load-aggregate-query.integration.ts +266 -0
- package/src/pipeline/__tests__/msp-error-mode.integration.ts +149 -0
- package/src/pipeline/__tests__/msp-multi-hop.integration.ts +228 -0
- package/src/pipeline/__tests__/msp-rebuild.integration.ts +368 -0
- package/src/pipeline/__tests__/multi-stream-projection.integration.ts +341 -0
- package/src/pipeline/__tests__/perf-rebuild.integration.ts +147 -0
- package/src/pipeline/__tests__/projection-rebuild.integration.ts +551 -0
- package/src/pipeline/__tests__/query-projection.integration.ts +201 -0
- package/src/pipeline/__tests__/redis-pipeline.integration.ts +306 -0
- package/src/pipeline/append-event-core.ts +117 -0
- package/src/pipeline/auth-claims-resolver.ts +103 -0
- package/src/pipeline/cascade-handler.ts +113 -0
- package/src/pipeline/dispatcher.ts +1585 -0
- package/src/pipeline/distributed-lock.ts +37 -0
- package/src/pipeline/entity-cache.ts +113 -0
- package/src/pipeline/event-consumer-state.ts +108 -0
- package/src/pipeline/event-dedup.ts +23 -0
- package/src/pipeline/event-dispatcher.ts +1016 -0
- package/src/pipeline/event-retention.ts +154 -0
- package/src/pipeline/idempotency.ts +76 -0
- package/src/pipeline/index.ts +66 -0
- package/src/pipeline/lifecycle-pipeline.ts +409 -0
- package/src/pipeline/msp-rebuild.ts +242 -0
- package/src/pipeline/multi-stream-apply-context.ts +115 -0
- package/src/pipeline/projection-rebuild.ts +334 -0
- package/src/pipeline/projection-state.ts +72 -0
- package/src/pipeline/projections-runner.ts +56 -0
- package/src/pipeline/redis-keys.ts +11 -0
- package/src/pipeline/system-hooks.ts +190 -0
- package/src/random/__tests__/generate.test.ts +149 -0
- package/src/random/generate.ts +141 -0
- package/src/random/index.ts +8 -0
- package/src/random/words.ts +392 -0
- package/src/rate-limit/__tests__/dispatcher-l3.integration.ts +111 -0
- package/src/rate-limit/__tests__/middleware.integration.ts +189 -0
- package/src/rate-limit/__tests__/resolver.integration.ts +189 -0
- package/src/rate-limit/bucket.ts +36 -0
- package/src/rate-limit/index.ts +14 -0
- package/src/rate-limit/middleware.ts +152 -0
- package/src/rate-limit/resolver.ts +267 -0
- package/src/redis/__tests__/redis-options.test.ts +54 -0
- package/src/redis/index.ts +74 -0
- package/src/search/__tests__/meilisearch-adapter.integration.ts +236 -0
- package/src/search/__tests__/search-adapter.test.ts +256 -0
- package/src/search/in-memory-adapter.ts +123 -0
- package/src/search/index.ts +12 -0
- package/src/search/meilisearch-adapter.ts +106 -0
- package/src/search/types.ts +39 -0
- package/src/secrets/__tests__/dek-cache.test.ts +213 -0
- package/src/secrets/__tests__/env-master-key-provider.test.ts +119 -0
- package/src/secrets/__tests__/envelope.test.ts +74 -0
- package/src/secrets/__tests__/leak-guard.test.ts +92 -0
- package/src/secrets/__tests__/rotation.test.ts +149 -0
- package/src/secrets/dek-cache.ts +116 -0
- package/src/secrets/env-master-key-provider.ts +162 -0
- package/src/secrets/envelope.ts +55 -0
- package/src/secrets/index.ts +19 -0
- package/src/secrets/leak-guard.ts +87 -0
- package/src/secrets/rotation.ts +34 -0
- package/src/secrets/types.ts +107 -0
- package/src/stack/db.ts +104 -0
- package/src/stack/event-collector.ts +23 -0
- package/src/stack/index.ts +32 -0
- package/src/stack/redis.ts +44 -0
- package/src/stack/request-helper.ts +168 -0
- package/src/stack/table-helpers.ts +104 -0
- package/src/stack/test-stack.ts +357 -0
- package/src/stack/test-users.ts +37 -0
- package/src/testing/__tests__/e2e-generator.test.ts +230 -0
- package/src/testing/__tests__/ensure-entity-table.integration.ts +54 -0
- package/src/testing/access-assertions.ts +15 -0
- package/src/testing/assertions.ts +35 -0
- package/src/testing/e2e-generator.ts +465 -0
- package/src/testing/expect-error.ts +25 -0
- package/src/testing/handler-context.ts +125 -0
- package/src/testing/http-cookies.ts +52 -0
- package/src/testing/index.ts +41 -0
- package/src/testing/late-bound.ts +39 -0
- package/src/testing/mutable-master-key-provider.ts +31 -0
- package/src/testing/observability-recorder.ts +54 -0
- package/src/testing/shared-entities.ts +49 -0
- package/src/testing/utils.ts +1 -0
- package/src/testing/wait-for.ts +31 -0
- package/src/time/__tests__/polyfill.test.ts +73 -0
- package/src/time/__tests__/tz-context.test.ts +121 -0
- package/src/time/index.ts +21 -0
- package/src/time/polyfill.ts +70 -0
- package/src/time/tz-context.ts +107 -0
- package/src/ui-types/app-schema.ts +57 -0
- package/src/ui-types/index.ts +65 -0
- package/src/utils/__tests__/assert.test.ts +17 -0
- package/src/utils/__tests__/env-parse.test.ts +54 -0
- package/src/utils/assert.ts +18 -0
- package/src/utils/env-parse.ts +16 -0
- package/src/utils/ids.ts +16 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/safe-json.ts +30 -0
- package/src/utils/serialization.ts +7 -0
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
// Canonical entrypoint factories for the three deploy shapes:
|
|
2
|
+
//
|
|
3
|
+
// - `createApiEntrypoint` — HTTP + SSE receiver. Does NOT start the
|
|
4
|
+
// event-dispatcher or job-runner. One or more instances behind a load
|
|
5
|
+
// balancer handle user requests.
|
|
6
|
+
// - `createWorkerEntrypoint` — Event-dispatcher + job-runner, no HTTP.
|
|
7
|
+
// Single instance (or few, SKIP LOCKED serialises them) drains events
|
|
8
|
+
// post-commit and runs scheduled/triggered jobs.
|
|
9
|
+
// - `createAllInOneEntrypoint` — both in one process. Convenient for
|
|
10
|
+
// dev, samples, single-tenant self-hosts; NOT recommended for scaled
|
|
11
|
+
// prod deploys because CPU-intensive jobs would block request
|
|
12
|
+
// handling.
|
|
13
|
+
//
|
|
14
|
+
// Each factory returns a unified `{ lifecycle, start, stop }` so `main.ts`
|
|
15
|
+
// wiring stays identical regardless of mode:
|
|
16
|
+
//
|
|
17
|
+
// const entry = createApiEntrypoint(opts);
|
|
18
|
+
// attachSignalHandlers(entry.lifecycle);
|
|
19
|
+
// await entry.start();
|
|
20
|
+
// serve({ fetch: entry.app.fetch, port: 3000 });
|
|
21
|
+
//
|
|
22
|
+
// The `lifecycle` handle drives graceful-shutdown LIFO; the framework
|
|
23
|
+
// registers its own shutdown hooks (eventDispatcher.stop, jobRunner.stop)
|
|
24
|
+
// in the order they were built.
|
|
25
|
+
//
|
|
26
|
+
// Known limitation (tracked in uebersicht.md Offene Follow-Ups): the
|
|
27
|
+
// built-in SSE broker is in-memory per process. In a split api/worker
|
|
28
|
+
// deploy, system-consumers that push to SSE (new-row broadcasts) run on
|
|
29
|
+
// the worker and therefore can't reach clients connected to the API
|
|
30
|
+
// instances. Either run all-in-one, put the SSE consumer on the API
|
|
31
|
+
// side explicitly, or wait for the Redis-Pub/Sub bridge.
|
|
32
|
+
|
|
33
|
+
import type { Hono } from "hono";
|
|
34
|
+
import type { AuthRoutesConfig } from "../api/auth-routes";
|
|
35
|
+
import type { JwtHelper } from "../api/jwt";
|
|
36
|
+
import type { KumikoServer, ServerOptions } from "../api/server";
|
|
37
|
+
import { buildServer } from "../api/server";
|
|
38
|
+
import type { SseBroker } from "../api/sse-broker";
|
|
39
|
+
import type { PgClient } from "../db/connection";
|
|
40
|
+
import type { AppContext, JobRunIn, Registry, RunIn } from "../engine/types";
|
|
41
|
+
import type { FileRoutesOptions } from "../files/file-routes";
|
|
42
|
+
import type { JobRunner, JobRunnerOptions } from "../jobs/job-runner";
|
|
43
|
+
import { createJobRunner } from "../jobs/job-runner";
|
|
44
|
+
import type { Lifecycle } from "../lifecycle";
|
|
45
|
+
import { createLifecycle } from "../lifecycle";
|
|
46
|
+
import type { ObservabilityOptions, ObservabilityProvider } from "../observability";
|
|
47
|
+
import type { EventDedup, EventDispatcher } from "../pipeline";
|
|
48
|
+
import type { DispatcherOptions } from "../pipeline/dispatcher";
|
|
49
|
+
import type { SystemHooks } from "../pipeline/lifecycle-pipeline";
|
|
50
|
+
|
|
51
|
+
// Shared fields across all three modes. A caller that swaps between
|
|
52
|
+
// modes can reuse the same options object.
|
|
53
|
+
export type BaseEntrypointOptions = {
|
|
54
|
+
readonly registry: Registry;
|
|
55
|
+
readonly context: AppContext;
|
|
56
|
+
readonly jwtSecret: string;
|
|
57
|
+
readonly jwtIssuer?: string;
|
|
58
|
+
readonly observability?: ObservabilityProvider;
|
|
59
|
+
readonly observabilityOptions?: ObservabilityOptions;
|
|
60
|
+
readonly dispatcherOptions?: Omit<DispatcherOptions, "lifecycle">;
|
|
61
|
+
readonly systemHooks?: SystemHooks;
|
|
62
|
+
readonly eventDedup?: EventDedup;
|
|
63
|
+
// Optional pre-built lifecycle. If omitted, each factory builds its own.
|
|
64
|
+
// Pass one in when you want to register caller-specific shutdown hooks
|
|
65
|
+
// alongside the framework's.
|
|
66
|
+
readonly lifecycle?: Lifecycle;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Shape the JobRunner block takes in every entrypoint mode. Extracted so
|
|
70
|
+
// adding a new JobRunnerOption doesn't need three parallel changes.
|
|
71
|
+
type JobsBlock = {
|
|
72
|
+
readonly redisUrl: string;
|
|
73
|
+
readonly queueNamePrefix?: string;
|
|
74
|
+
readonly getActiveTenantIds?: JobRunnerOptions["getActiveTenantIds"];
|
|
75
|
+
readonly onJobStart?: JobRunnerOptions["onJobStart"];
|
|
76
|
+
readonly onJobComplete?: JobRunnerOptions["onJobComplete"];
|
|
77
|
+
readonly onJobFailed?: JobRunnerOptions["onJobFailed"];
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export type ApiEntrypointOptions = BaseEntrypointOptions & {
|
|
81
|
+
readonly auth?: AuthRoutesConfig;
|
|
82
|
+
readonly anonymousAccess?: ServerOptions["anonymousAccess"];
|
|
83
|
+
readonly sseBroker?: SseBroker;
|
|
84
|
+
readonly files?: Omit<FileRoutesOptions, "db"> & { db?: FileRoutesOptions["db"] };
|
|
85
|
+
readonly rateLimit?: ServerOptions["rateLimit"];
|
|
86
|
+
readonly maxRequestBytes?: ServerOptions["maxRequestBytes"];
|
|
87
|
+
readonly readiness?: ServerOptions["readiness"];
|
|
88
|
+
readonly metrics?: ServerOptions["metrics"];
|
|
89
|
+
// Job-enqueue surface for the API process. Required whenever the registry
|
|
90
|
+
// defines event-triggered jobs: command-dispatcher fires handleEvent as
|
|
91
|
+
// an afterCommit-hook — without a jobRunner the enqueue silently drops.
|
|
92
|
+
//
|
|
93
|
+
// `runLocalJobs: true` additionally starts a BullMQ worker for the "api"
|
|
94
|
+
// lane inside this API process. Only useful for short, CPU-light jobs —
|
|
95
|
+
// a long-running handler on the API lane will starve request handlers.
|
|
96
|
+
readonly jobs?: JobsBlock & {
|
|
97
|
+
readonly runLocalJobs?: boolean;
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export type WorkerEntrypointOptions = BaseEntrypointOptions &
|
|
102
|
+
JobsBlock & {
|
|
103
|
+
// Tuning knobs for the event-dispatcher loop. Workers typically set a
|
|
104
|
+
// pgClient so LISTEN/NOTIFY drops the poll latency from seconds to TCP
|
|
105
|
+
// round-trip.
|
|
106
|
+
readonly eventDispatcher?: ServerOptions["eventDispatcher"];
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export type AllInOneEntrypointOptions = ApiEntrypointOptions & WorkerEntrypointOptions;
|
|
110
|
+
|
|
111
|
+
export type ApiEntrypoint = {
|
|
112
|
+
readonly app: Hono;
|
|
113
|
+
readonly jwt: JwtHelper;
|
|
114
|
+
readonly sseBroker: SseBroker;
|
|
115
|
+
readonly lifecycle: Lifecycle;
|
|
116
|
+
readonly observability: ObservabilityProvider;
|
|
117
|
+
readonly mode: "api";
|
|
118
|
+
// No-op on API mode — dispatcher isn't built, job-runner doesn't exist.
|
|
119
|
+
// Kept for a uniform call-site so `main.ts` doesn't branch on mode.
|
|
120
|
+
start(): Promise<void>;
|
|
121
|
+
stop(): Promise<void>;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export type WorkerEntrypoint = {
|
|
125
|
+
readonly lifecycle: Lifecycle;
|
|
126
|
+
readonly eventDispatcher: EventDispatcher;
|
|
127
|
+
readonly jobRunner: JobRunner;
|
|
128
|
+
readonly observability: ObservabilityProvider;
|
|
129
|
+
readonly mode: "worker";
|
|
130
|
+
// Starts event-dispatcher poll + BullMQ worker. SIGTERM triggers
|
|
131
|
+
// `lifecycle.drain()`, which stops both via registered hooks.
|
|
132
|
+
start(): Promise<void>;
|
|
133
|
+
stop(): Promise<void>;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export type AllInOneEntrypoint = Omit<ApiEntrypoint, "mode"> &
|
|
137
|
+
Omit<WorkerEntrypoint, "mode"> & {
|
|
138
|
+
readonly mode: "all-in-one";
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// --- Shared builders ------------------------------------------------------
|
|
142
|
+
//
|
|
143
|
+
// Three factories, three near-identical buildServer() + createJobRunner()
|
|
144
|
+
// blocks. Extract once so adding a new ServerOptions field doesn't need
|
|
145
|
+
// three parallel edits — one helper, one place to maintain.
|
|
146
|
+
|
|
147
|
+
// Merge an internally-built jobRunner into the caller's dispatcherOptions
|
|
148
|
+
// so the command-dispatcher fires handleEvent as an afterCommit-hook for
|
|
149
|
+
// event-triggered jobs (dispatcher.ts:997). Without this plumbing,
|
|
150
|
+
// `r.job({ trigger: { on: … } })` silently drops on every write — that
|
|
151
|
+
// was the hidden Welle-2.5 gap.
|
|
152
|
+
//
|
|
153
|
+
// Caller-supplied `dispatcherOptions.jobRunner` wins (tests sometimes
|
|
154
|
+
// inject a mock runner directly).
|
|
155
|
+
function mergeDispatcherOptions(
|
|
156
|
+
caller: Omit<DispatcherOptions, "lifecycle"> | undefined,
|
|
157
|
+
jobRunner: JobRunner | undefined,
|
|
158
|
+
): Omit<DispatcherOptions, "lifecycle"> | undefined {
|
|
159
|
+
if (!jobRunner) return caller;
|
|
160
|
+
if (caller?.jobRunner) return caller;
|
|
161
|
+
return { ...(caller ?? {}), jobRunner };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// buildApiServer shapes ServerOptions from API-mode caller-options.
|
|
165
|
+
// AllInOneEntrypointOptions extends ApiEntrypointOptions, so structural
|
|
166
|
+
// subtyping makes the all-in-one path a valid caller without an explicit
|
|
167
|
+
// union. `dispatcherOverride` lets API-mode slam `{disabled:true}` while
|
|
168
|
+
// All-in-one passes the caller's real config through. `jobRunner`, when
|
|
169
|
+
// present, is merged into dispatcherOptions so the command-dispatcher can
|
|
170
|
+
// fire event-triggered jobs.
|
|
171
|
+
function buildApiServer(
|
|
172
|
+
opts: ApiEntrypointOptions,
|
|
173
|
+
lifecycle: Lifecycle,
|
|
174
|
+
dispatcherOverride: ServerOptions["eventDispatcher"] | undefined,
|
|
175
|
+
jobRunner: JobRunner | undefined,
|
|
176
|
+
processLane: RunIn,
|
|
177
|
+
): KumikoServer {
|
|
178
|
+
const dispatcherOptions = mergeDispatcherOptions(opts.dispatcherOptions, jobRunner);
|
|
179
|
+
return buildServer({
|
|
180
|
+
registry: opts.registry,
|
|
181
|
+
context: opts.context,
|
|
182
|
+
jwtSecret: opts.jwtSecret,
|
|
183
|
+
lifecycle,
|
|
184
|
+
processLane,
|
|
185
|
+
jwtIssuer: opts.jwtIssuer,
|
|
186
|
+
auth: opts.auth,
|
|
187
|
+
anonymousAccess: opts.anonymousAccess,
|
|
188
|
+
files: opts.files,
|
|
189
|
+
sseBroker: opts.sseBroker,
|
|
190
|
+
rateLimit: opts.rateLimit,
|
|
191
|
+
maxRequestBytes: opts.maxRequestBytes,
|
|
192
|
+
readiness: opts.readiness,
|
|
193
|
+
metrics: opts.metrics,
|
|
194
|
+
observability: opts.observability,
|
|
195
|
+
observabilityOptions: opts.observabilityOptions,
|
|
196
|
+
dispatcherOptions,
|
|
197
|
+
systemHooks: opts.systemHooks,
|
|
198
|
+
eventDedup: opts.eventDedup,
|
|
199
|
+
eventDispatcher: dispatcherOverride,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Worker path is narrower — no HTTP-specific options. `eventDispatcher`
|
|
204
|
+
// comes straight from the caller (LISTEN/NOTIFY wiring, pollIntervalMs).
|
|
205
|
+
// `processLane` is "worker" — any MSP with runIn="api" gets filtered out
|
|
206
|
+
// of this process's dispatcher.
|
|
207
|
+
function buildWorkerServer(
|
|
208
|
+
opts: WorkerEntrypointOptions,
|
|
209
|
+
lifecycle: Lifecycle,
|
|
210
|
+
jobRunner: JobRunner,
|
|
211
|
+
): KumikoServer {
|
|
212
|
+
const dispatcherOptions = mergeDispatcherOptions(opts.dispatcherOptions, jobRunner);
|
|
213
|
+
return buildServer({
|
|
214
|
+
registry: opts.registry,
|
|
215
|
+
context: opts.context,
|
|
216
|
+
jwtSecret: opts.jwtSecret,
|
|
217
|
+
lifecycle,
|
|
218
|
+
processLane: "worker",
|
|
219
|
+
observability: opts.observability,
|
|
220
|
+
observabilityOptions: opts.observabilityOptions,
|
|
221
|
+
dispatcherOptions,
|
|
222
|
+
systemHooks: opts.systemHooks,
|
|
223
|
+
eventDedup: opts.eventDedup,
|
|
224
|
+
eventDispatcher: opts.eventDispatcher,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Build a lane-scoped JobRunner AND register its stop-hook on the lifecycle.
|
|
229
|
+
// Hook order (LIFO): jobRunner runs BEFORE eventDispatcher so no in-flight
|
|
230
|
+
// job tries to enqueue an event to an already-torn-down dispatcher.
|
|
231
|
+
// buildServer registers the dispatcher hook earlier in the factory, so
|
|
232
|
+
// this one lands later in registration order → runs first on drain.
|
|
233
|
+
//
|
|
234
|
+
// `consumerLane` = "api" | "worker" starts a BullMQ worker for that lane's
|
|
235
|
+
// queue plus cron/boot scheduling for lane-matching jobs. `undefined`
|
|
236
|
+
// builds an enqueuer-only runner: holds queue-clients for both lanes so
|
|
237
|
+
// dispatch()/handleEvent() route per jobDef.runIn, but starts no local
|
|
238
|
+
// consumer. Used by the API process when `runLocalJobs` is false.
|
|
239
|
+
function buildJobRunnerWithHook(
|
|
240
|
+
registry: Registry,
|
|
241
|
+
context: AppContext,
|
|
242
|
+
jobs: JobsBlock,
|
|
243
|
+
consumerLane: JobRunIn | undefined,
|
|
244
|
+
lifecycle: Lifecycle,
|
|
245
|
+
hookName: string,
|
|
246
|
+
): JobRunner {
|
|
247
|
+
const jobRunner = createJobRunner({
|
|
248
|
+
registry,
|
|
249
|
+
context,
|
|
250
|
+
redisUrl: jobs.redisUrl,
|
|
251
|
+
consumerLane,
|
|
252
|
+
queueNamePrefix: jobs.queueNamePrefix,
|
|
253
|
+
getActiveTenantIds: jobs.getActiveTenantIds,
|
|
254
|
+
onJobStart: jobs.onJobStart,
|
|
255
|
+
onJobComplete: jobs.onJobComplete,
|
|
256
|
+
onJobFailed: jobs.onJobFailed,
|
|
257
|
+
});
|
|
258
|
+
lifecycle.registerShutdownHook(hookName, async () => {
|
|
259
|
+
await jobRunner.stop();
|
|
260
|
+
});
|
|
261
|
+
return jobRunner;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// A worker-shaped process with no consumers (no SSE, no search adapter,
|
|
265
|
+
// no MSPs) has nothing to drain — that's a caller-config bug, not a
|
|
266
|
+
// usable process shape. Fail loud so ops sees it before prod takes
|
|
267
|
+
// traffic from an API that enqueues events nobody consumes.
|
|
268
|
+
function requireDispatcher(server: KumikoServer, mode: string): EventDispatcher {
|
|
269
|
+
if (!server.eventDispatcher) {
|
|
270
|
+
throw new Error(
|
|
271
|
+
`[entrypoint] ${mode} mode requires at least one event consumer (SSE broker, search adapter, or r.multiStreamProjection)`,
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
return server.eventDispatcher;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// --- API entrypoint -------------------------------------------------------
|
|
278
|
+
|
|
279
|
+
export function createApiEntrypoint(options: ApiEntrypointOptions): ApiEntrypoint {
|
|
280
|
+
const lifecycle = options.lifecycle ?? createLifecycle({ startReady: true });
|
|
281
|
+
|
|
282
|
+
// Boot-validation (Welle 2.6.c) — fail loud before traffic arrives:
|
|
283
|
+
// (a) Any jobs declared + no jobs-block → command-dispatcher would
|
|
284
|
+
// silently drop every event-triggered enqueue. Fix: add jobs:
|
|
285
|
+
// { redisUrl } so the API holds lane-queue-clients.
|
|
286
|
+
// (b) A job with runIn="api" + runLocalJobs !== true → the API
|
|
287
|
+
// process is the ONLY container that can consume "api"-lane
|
|
288
|
+
// queues (workers only consume "worker"). Without runLocalJobs,
|
|
289
|
+
// the job would enqueue and stay pending forever.
|
|
290
|
+
const allJobs = [...options.registry.getAllJobs().values()];
|
|
291
|
+
if (allJobs.length > 0 && !options.jobs) {
|
|
292
|
+
throw new Error(
|
|
293
|
+
`[entrypoint] createApiEntrypoint: registry declares ${allJobs.length} job(s) but no \`jobs\` block was passed. ` +
|
|
294
|
+
`Event-triggered writes would silently drop their enqueue. Add \`jobs: { redisUrl: ... }\` to createApiEntrypoint options.`,
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
if (options.jobs && !options.jobs.runLocalJobs) {
|
|
298
|
+
const apiOnlyJobs = allJobs.filter((j) => j.runIn === "api").map((j) => j.name);
|
|
299
|
+
if (apiOnlyJobs.length > 0) {
|
|
300
|
+
throw new Error(
|
|
301
|
+
`[entrypoint] createApiEntrypoint: ${apiOnlyJobs.length} job(s) declared runIn="api" but runLocalJobs is not set — these jobs would have no consumer. ` +
|
|
302
|
+
`Set \`jobs: { runLocalJobs: true, ... }\` or change the jobs' runIn to "worker". Affected: ${apiOnlyJobs.join(", ")}`,
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// When the app declares any jobs, the API process needs a job-enqueuer
|
|
308
|
+
// so event-triggered jobs fired as afterCommit-hooks of a write reach
|
|
309
|
+
// the queue at all. `runLocalJobs: true` upgrades the enqueuer to a full
|
|
310
|
+
// runner that also consumes the "api" lane's queue in-process.
|
|
311
|
+
const apiJobRunner = options.jobs
|
|
312
|
+
? buildJobRunnerWithHook(
|
|
313
|
+
options.registry,
|
|
314
|
+
options.context,
|
|
315
|
+
options.jobs,
|
|
316
|
+
options.jobs.runLocalJobs ? "api" : undefined,
|
|
317
|
+
lifecycle,
|
|
318
|
+
"jobRunner",
|
|
319
|
+
)
|
|
320
|
+
: undefined;
|
|
321
|
+
|
|
322
|
+
// `{disabled:true}` skips dispatcher creation entirely — an API process
|
|
323
|
+
// doesn't hold an idle poller.
|
|
324
|
+
const server = buildApiServer(options, lifecycle, { disabled: true }, apiJobRunner, "api");
|
|
325
|
+
|
|
326
|
+
return {
|
|
327
|
+
app: server.app,
|
|
328
|
+
jwt: server.jwt,
|
|
329
|
+
sseBroker: server.sseBroker,
|
|
330
|
+
lifecycle,
|
|
331
|
+
observability: server.observability,
|
|
332
|
+
mode: "api",
|
|
333
|
+
async start() {
|
|
334
|
+
// Start the local BullMQ worker when runLocalJobs=true; enqueuer-only
|
|
335
|
+
// runners have a no-op .start() by design (JobRunner skips worker
|
|
336
|
+
// creation when consumerLane is undefined).
|
|
337
|
+
if (apiJobRunner) await apiJobRunner.start();
|
|
338
|
+
},
|
|
339
|
+
async stop() {
|
|
340
|
+
await lifecycle.drain();
|
|
341
|
+
},
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// --- Worker entrypoint ----------------------------------------------------
|
|
346
|
+
|
|
347
|
+
export function createWorkerEntrypoint(options: WorkerEntrypointOptions): WorkerEntrypoint {
|
|
348
|
+
const lifecycle = options.lifecycle ?? createLifecycle({ startReady: true });
|
|
349
|
+
const jobRunner = buildJobRunnerWithHook(
|
|
350
|
+
options.registry,
|
|
351
|
+
options.context,
|
|
352
|
+
options,
|
|
353
|
+
"worker",
|
|
354
|
+
lifecycle,
|
|
355
|
+
"jobRunner",
|
|
356
|
+
);
|
|
357
|
+
const server = buildWorkerServer(options, lifecycle, jobRunner);
|
|
358
|
+
const eventDispatcher = requireDispatcher(server, "worker");
|
|
359
|
+
|
|
360
|
+
return {
|
|
361
|
+
lifecycle,
|
|
362
|
+
eventDispatcher,
|
|
363
|
+
jobRunner,
|
|
364
|
+
observability: server.observability,
|
|
365
|
+
mode: "worker",
|
|
366
|
+
async start() {
|
|
367
|
+
await eventDispatcher.start();
|
|
368
|
+
await jobRunner.start();
|
|
369
|
+
},
|
|
370
|
+
async stop() {
|
|
371
|
+
await lifecycle.drain();
|
|
372
|
+
},
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// --- All-in-one entrypoint ------------------------------------------------
|
|
377
|
+
|
|
378
|
+
export function createAllInOneEntrypoint(options: AllInOneEntrypointOptions): AllInOneEntrypoint {
|
|
379
|
+
const lifecycle = options.lifecycle ?? createLifecycle({ startReady: true });
|
|
380
|
+
|
|
381
|
+
// All-in-one consumes BOTH lanes: two runners, each with a BullMQ worker
|
|
382
|
+
// for its own lane's queue. Both runners hold queue-clients for both
|
|
383
|
+
// lanes, so dispatch()/handleEvent() always route per jobDef.runIn —
|
|
384
|
+
// picking either runner as the dispatcher's enqueuer surface would work.
|
|
385
|
+
// The worker runner wins the dispatcherOptions slot by convention (that's
|
|
386
|
+
// where the majority of jobs live). Each runner handles cron/boot for
|
|
387
|
+
// its own lane in its own .start().
|
|
388
|
+
const workerJobRunner = buildJobRunnerWithHook(
|
|
389
|
+
options.registry,
|
|
390
|
+
options.context,
|
|
391
|
+
options,
|
|
392
|
+
"worker",
|
|
393
|
+
lifecycle,
|
|
394
|
+
"jobRunner",
|
|
395
|
+
);
|
|
396
|
+
const apiJobRunner = buildJobRunnerWithHook(
|
|
397
|
+
options.registry,
|
|
398
|
+
options.context,
|
|
399
|
+
options,
|
|
400
|
+
"api",
|
|
401
|
+
lifecycle,
|
|
402
|
+
"jobRunnerApi",
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
// Same builder as the API path — but WITH the caller's eventDispatcher
|
|
406
|
+
// config instead of `{disabled:true}`, so buildServer wires the poller
|
|
407
|
+
// alongside the HTTP app. processLane "both" disables MSP lane-filter
|
|
408
|
+
// entirely: all-in-one is a single process that fills every role, so
|
|
409
|
+
// every MSP (api-only, worker-only, both) must run here.
|
|
410
|
+
const server = buildApiServer(
|
|
411
|
+
options,
|
|
412
|
+
lifecycle,
|
|
413
|
+
options.eventDispatcher,
|
|
414
|
+
workerJobRunner,
|
|
415
|
+
"both",
|
|
416
|
+
);
|
|
417
|
+
const eventDispatcher = requireDispatcher(server, "all-in-one");
|
|
418
|
+
|
|
419
|
+
return {
|
|
420
|
+
app: server.app,
|
|
421
|
+
jwt: server.jwt,
|
|
422
|
+
sseBroker: server.sseBroker,
|
|
423
|
+
lifecycle,
|
|
424
|
+
eventDispatcher,
|
|
425
|
+
jobRunner: workerJobRunner,
|
|
426
|
+
observability: server.observability,
|
|
427
|
+
mode: "all-in-one",
|
|
428
|
+
async start() {
|
|
429
|
+
await eventDispatcher.start();
|
|
430
|
+
await workerJobRunner.start();
|
|
431
|
+
await apiJobRunner.start();
|
|
432
|
+
},
|
|
433
|
+
async stop() {
|
|
434
|
+
await lifecycle.drain();
|
|
435
|
+
},
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Keep PgClient imported so TS sees the import as used when callers take
|
|
440
|
+
// our re-exported ServerOptions.eventDispatcher type (which references it).
|
|
441
|
+
// Pure re-export of the concrete type is enough to anchor it.
|
|
442
|
+
export type { PgClient };
|