@alneas/eaos-server 0.0.0-stage → 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/CHANGELOG.md +21 -0
- package/LICENSE +21 -0
- package/README.ja.md +39 -0
- package/README.md +40 -2
- package/dist/agentic/agent-jobs.d.ts +329 -0
- package/dist/agentic/agent-jobs.js +15 -0
- package/dist/agentic/agent-jobs.js.map +1 -0
- package/dist/agentic/agent-node.d.ts +40 -0
- package/dist/agentic/agent-node.js +7 -0
- package/dist/agentic/agent-node.js.map +1 -0
- package/dist/agentic/agent-runner.d.ts +33 -0
- package/dist/agentic/agent-runner.js +7 -0
- package/dist/agentic/agent-runner.js.map +1 -0
- package/dist/agentic/ai-broker.d.ts +169 -0
- package/dist/agentic/ai-broker.js +8 -0
- package/dist/agentic/ai-broker.js.map +1 -0
- package/dist/agentic/atomic-checkpointer.d.ts +137 -0
- package/dist/agentic/atomic-checkpointer.js +9 -0
- package/dist/agentic/atomic-checkpointer.js.map +1 -0
- package/dist/agentic/autonomous-worker.d.ts +95 -0
- package/dist/agentic/autonomous-worker.js +9 -0
- package/dist/agentic/autonomous-worker.js.map +1 -0
- package/dist/agentic/event-bridge.d.ts +344 -0
- package/dist/agentic/event-bridge.js +9 -0
- package/dist/agentic/event-bridge.js.map +1 -0
- package/dist/agentic/executor.d.ts +91 -0
- package/dist/agentic/executor.js +12 -0
- package/dist/agentic/executor.js.map +1 -0
- package/dist/agentic/graph-projection.d.ts +119 -0
- package/dist/agentic/graph-projection.js +7 -0
- package/dist/agentic/graph-projection.js.map +1 -0
- package/dist/agentic/graph.d.ts +524 -0
- package/dist/agentic/graph.js +7 -0
- package/dist/agentic/graph.js.map +1 -0
- package/dist/agentic/index.d.ts +24 -0
- package/dist/agentic/index.js +86 -0
- package/dist/agentic/index.js.map +1 -0
- package/dist/agentic/local-runner.d.ts +102 -0
- package/dist/agentic/local-runner.js +7 -0
- package/dist/agentic/local-runner.js.map +1 -0
- package/dist/agentic/remote-executor.d.ts +67 -0
- package/dist/agentic/remote-executor.js +8 -0
- package/dist/agentic/remote-executor.js.map +1 -0
- package/dist/agentic/types.d.ts +157 -0
- package/dist/agentic/types.js +7 -0
- package/dist/agentic/types.js.map +1 -0
- package/dist/agentic/workflow-catalog.d.ts +152 -0
- package/dist/agentic/workflow-catalog.js +7 -0
- package/dist/agentic/workflow-catalog.js.map +1 -0
- package/dist/agentic/workflow-compiler.d.ts +44 -0
- package/dist/agentic/workflow-compiler.js +8 -0
- package/dist/agentic/workflow-compiler.js.map +1 -0
- package/dist/agentic/workflow-coordinator.d.ts +170 -0
- package/dist/agentic/workflow-coordinator.js +8 -0
- package/dist/agentic/workflow-coordinator.js.map +1 -0
- package/dist/agentic/workflow-manager.d.ts +91 -0
- package/dist/agentic/workflow-manager.js +7 -0
- package/dist/agentic/workflow-manager.js.map +1 -0
- package/dist/agentic/workflow-registry.d.ts +334 -0
- package/dist/agentic/workflow-registry.js +7 -0
- package/dist/agentic/workflow-registry.js.map +1 -0
- package/dist/artifacts-CteHmCMI.d.ts +614 -0
- package/dist/auth-hooks/api-key.d.ts +75 -0
- package/dist/auth-hooks/api-key.js +7 -0
- package/dist/auth-hooks/api-key.js.map +1 -0
- package/dist/auth-hooks/index.d.ts +80 -0
- package/dist/auth-hooks/index.js +28 -0
- package/dist/auth-hooks/index.js.map +1 -0
- package/dist/browser-auth/account-memberships.d.ts +213 -0
- package/dist/browser-auth/account-memberships.js +13 -0
- package/dist/browser-auth/account-memberships.js.map +1 -0
- package/dist/browser-auth/index.d.ts +8 -0
- package/dist/browser-auth/index.js +59 -0
- package/dist/browser-auth/index.js.map +1 -0
- package/dist/browser-auth/kratos-session.d.ts +37 -0
- package/dist/browser-auth/kratos-session.js +7 -0
- package/dist/browser-auth/kratos-session.js.map +1 -0
- package/dist/browser-auth/platform-session.d.ts +120 -0
- package/dist/browser-auth/platform-session.js +7 -0
- package/dist/browser-auth/platform-session.js.map +1 -0
- package/dist/browser-auth/public-memberships.d.ts +22 -0
- package/dist/browser-auth/public-memberships.js +7 -0
- package/dist/browser-auth/public-memberships.js.map +1 -0
- package/dist/cache/index.d.ts +181 -0
- package/dist/cache/index.js +197 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/chunk-32746UQZ.js +131 -0
- package/dist/chunk-32746UQZ.js.map +1 -0
- package/dist/chunk-3NLSWP2Y.js +223 -0
- package/dist/chunk-3NLSWP2Y.js.map +1 -0
- package/dist/chunk-3P4XTTQH.js +346 -0
- package/dist/chunk-3P4XTTQH.js.map +1 -0
- package/dist/chunk-3VITSHN3.js +15 -0
- package/dist/chunk-3VITSHN3.js.map +1 -0
- package/dist/chunk-46UWPEW2.js +226 -0
- package/dist/chunk-46UWPEW2.js.map +1 -0
- package/dist/chunk-4VORUFKR.js +45 -0
- package/dist/chunk-4VORUFKR.js.map +1 -0
- package/dist/chunk-55D4ERWO.js +1 -0
- package/dist/chunk-55D4ERWO.js.map +1 -0
- package/dist/chunk-5TBBZIND.js +18 -0
- package/dist/chunk-5TBBZIND.js.map +1 -0
- package/dist/chunk-5WOZWPZA.js +211 -0
- package/dist/chunk-5WOZWPZA.js.map +1 -0
- package/dist/chunk-6CBVZ6CT.js +168 -0
- package/dist/chunk-6CBVZ6CT.js.map +1 -0
- package/dist/chunk-6KV5CJBW.js +221 -0
- package/dist/chunk-6KV5CJBW.js.map +1 -0
- package/dist/chunk-6XZXYNJR.js +74 -0
- package/dist/chunk-6XZXYNJR.js.map +1 -0
- package/dist/chunk-753HWDSC.js +222 -0
- package/dist/chunk-753HWDSC.js.map +1 -0
- package/dist/chunk-7AHSS7SO.js +81 -0
- package/dist/chunk-7AHSS7SO.js.map +1 -0
- package/dist/chunk-7FTJN4SA.js +1 -0
- package/dist/chunk-7FTJN4SA.js.map +1 -0
- package/dist/chunk-AVDMLTPF.js +24 -0
- package/dist/chunk-AVDMLTPF.js.map +1 -0
- package/dist/chunk-BKAHUEIT.js +95 -0
- package/dist/chunk-BKAHUEIT.js.map +1 -0
- package/dist/chunk-CJ7OFEF7.js +134 -0
- package/dist/chunk-CJ7OFEF7.js.map +1 -0
- package/dist/chunk-DHQGNP4T.js +770 -0
- package/dist/chunk-DHQGNP4T.js.map +1 -0
- package/dist/chunk-EJKWDZIU.js +111 -0
- package/dist/chunk-EJKWDZIU.js.map +1 -0
- package/dist/chunk-F3O7CELI.js +23 -0
- package/dist/chunk-F3O7CELI.js.map +1 -0
- package/dist/chunk-FD6VC2NA.js +66 -0
- package/dist/chunk-FD6VC2NA.js.map +1 -0
- package/dist/chunk-FRRRWAHO.js +14 -0
- package/dist/chunk-FRRRWAHO.js.map +1 -0
- package/dist/chunk-HCKAGLLB.js +17 -0
- package/dist/chunk-HCKAGLLB.js.map +1 -0
- package/dist/chunk-HVC7FG6B.js +191 -0
- package/dist/chunk-HVC7FG6B.js.map +1 -0
- package/dist/chunk-HXFVOR7Z.js +496 -0
- package/dist/chunk-HXFVOR7Z.js.map +1 -0
- package/dist/chunk-IJWYS2PF.js +122 -0
- package/dist/chunk-IJWYS2PF.js.map +1 -0
- package/dist/chunk-INCHXAFK.js +1395 -0
- package/dist/chunk-INCHXAFK.js.map +1 -0
- package/dist/chunk-JT6BRGQM.js +1 -0
- package/dist/chunk-JT6BRGQM.js.map +1 -0
- package/dist/chunk-L6PMAEMB.js +115 -0
- package/dist/chunk-L6PMAEMB.js.map +1 -0
- package/dist/chunk-LOUGW6MU.js +126 -0
- package/dist/chunk-LOUGW6MU.js.map +1 -0
- package/dist/chunk-LYPZPE53.js +129 -0
- package/dist/chunk-LYPZPE53.js.map +1 -0
- package/dist/chunk-NNCCN7JP.js +186 -0
- package/dist/chunk-NNCCN7JP.js.map +1 -0
- package/dist/chunk-PBC3MZUL.js +212 -0
- package/dist/chunk-PBC3MZUL.js.map +1 -0
- package/dist/chunk-R4ADP2DC.js +20 -0
- package/dist/chunk-R4ADP2DC.js.map +1 -0
- package/dist/chunk-RHN4Y6VS.js +44 -0
- package/dist/chunk-RHN4Y6VS.js.map +1 -0
- package/dist/chunk-THYUY5ZZ.js +204 -0
- package/dist/chunk-THYUY5ZZ.js.map +1 -0
- package/dist/chunk-UGNTCOVR.js +28 -0
- package/dist/chunk-UGNTCOVR.js.map +1 -0
- package/dist/chunk-VC2PCK2S.js +31 -0
- package/dist/chunk-VC2PCK2S.js.map +1 -0
- package/dist/chunk-VF5YDZJC.js +305 -0
- package/dist/chunk-VF5YDZJC.js.map +1 -0
- package/dist/chunk-VISRDVTK.js +675 -0
- package/dist/chunk-VISRDVTK.js.map +1 -0
- package/dist/chunk-W6O3LVBY.js +102 -0
- package/dist/chunk-W6O3LVBY.js.map +1 -0
- package/dist/chunk-WFEAKJLR.js +47 -0
- package/dist/chunk-WFEAKJLR.js.map +1 -0
- package/dist/chunk-XIEY2OF4.js +67 -0
- package/dist/chunk-XIEY2OF4.js.map +1 -0
- package/dist/chunk-XITLHDG3.js +37 -0
- package/dist/chunk-XITLHDG3.js.map +1 -0
- package/dist/chunk-XMWPYZWZ.js +61 -0
- package/dist/chunk-XMWPYZWZ.js.map +1 -0
- package/dist/chunk-XUP6CNOM.js +34 -0
- package/dist/chunk-XUP6CNOM.js.map +1 -0
- package/dist/chunk-YABTQZDJ.js +25 -0
- package/dist/chunk-YABTQZDJ.js.map +1 -0
- package/dist/chunk-YMJ7BRKU.js +510 -0
- package/dist/chunk-YMJ7BRKU.js.map +1 -0
- package/dist/chunk-ZC3XWU7B.js +28 -0
- package/dist/chunk-ZC3XWU7B.js.map +1 -0
- package/dist/chunk-ZHMTD5KV.js +90 -0
- package/dist/chunk-ZHMTD5KV.js.map +1 -0
- package/dist/chunk-ZWZDLOE7.js +160 -0
- package/dist/chunk-ZWZDLOE7.js.map +1 -0
- package/dist/db-package/db/local-first-sqlite-adapter.d.ts +432 -0
- package/dist/db-package/db/local-first-sqlite-adapter.js +7 -0
- package/dist/db-package/db/local-first-sqlite-adapter.js.map +1 -0
- package/dist/db-package/index.d.ts +7 -0
- package/dist/db-package/index.js +16 -0
- package/dist/db-package/index.js.map +1 -0
- package/dist/db-package/migration/aggregator.d.ts +86 -0
- package/dist/db-package/migration/aggregator.js +7 -0
- package/dist/db-package/migration/aggregator.js.map +1 -0
- package/dist/db-package/migration/index.d.ts +3 -0
- package/dist/db-package/migration/index.js +8 -0
- package/dist/db-package/migration/index.js.map +1 -0
- package/dist/engine.d.ts +205 -0
- package/dist/engine.js +20 -0
- package/dist/engine.js.map +1 -0
- package/dist/entitlements/index.d.ts +313 -0
- package/dist/entitlements/index.js +23 -0
- package/dist/entitlements/index.js.map +1 -0
- package/dist/execution/index.d.ts +50 -0
- package/dist/execution/index.js +57 -0
- package/dist/execution/index.js.map +1 -0
- package/dist/extensions/index.d.ts +172 -0
- package/dist/extensions/index.js +95 -0
- package/dist/extensions/index.js.map +1 -0
- package/dist/health/index.d.ts +35 -0
- package/dist/health/index.js +7 -0
- package/dist/health/index.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.js +160 -0
- package/dist/index.js.map +1 -0
- package/dist/lifecycle/index.d.ts +133 -0
- package/dist/lifecycle/index.js +13 -0
- package/dist/lifecycle/index.js.map +1 -0
- package/dist/lifecycle-engine/backend-migration.d.ts +2 -0
- package/dist/lifecycle-engine/backend-migration.js +11 -0
- package/dist/lifecycle-engine/backend-migration.js.map +1 -0
- package/dist/lifecycle-engine/baseline.d.ts +2 -0
- package/dist/lifecycle-engine/baseline.js +9 -0
- package/dist/lifecycle-engine/baseline.js.map +1 -0
- package/dist/lifecycle-engine/index.d.ts +1497 -0
- package/dist/lifecycle-engine/index.js +41 -0
- package/dist/lifecycle-engine/index.js.map +1 -0
- package/dist/lifecycle-engine/platform/artifacts.d.ts +4 -0
- package/dist/lifecycle-engine/platform/artifacts.js +7 -0
- package/dist/lifecycle-engine/platform/artifacts.js.map +1 -0
- package/dist/lifecycle-engine/platform/control-plane.d.ts +12 -0
- package/dist/lifecycle-engine/platform/control-plane.js +2 -0
- package/dist/lifecycle-engine/platform/control-plane.js.map +1 -0
- package/dist/lifecycle-engine/platform/database-router.d.ts +118 -0
- package/dist/lifecycle-engine/platform/database-router.js +7 -0
- package/dist/lifecycle-engine/platform/database-router.js.map +1 -0
- package/dist/lifecycle-engine/platform/deployment-placements.d.ts +464 -0
- package/dist/lifecycle-engine/platform/deployment-placements.js +16 -0
- package/dist/lifecycle-engine/platform/deployment-placements.js.map +1 -0
- package/dist/lifecycle-engine/platform/deployment.d.ts +4 -0
- package/dist/lifecycle-engine/platform/deployment.js +17 -0
- package/dist/lifecycle-engine/platform/deployment.js.map +1 -0
- package/dist/lifecycle-engine/platform/index.d.ts +737 -0
- package/dist/lifecycle-engine/platform/index.js +60 -0
- package/dist/lifecycle-engine/platform/index.js.map +1 -0
- package/dist/lifecycle-engine/platform/runtime.d.ts +80 -0
- package/dist/lifecycle-engine/platform/runtime.js +11 -0
- package/dist/lifecycle-engine/platform/runtime.js.map +1 -0
- package/dist/lifecycle-engine/platform/site-publication.d.ts +102 -0
- package/dist/lifecycle-engine/platform/site-publication.js +7 -0
- package/dist/lifecycle-engine/platform/site-publication.js.map +1 -0
- package/dist/lifecycle-engine/platform/user-directory.d.ts +139 -0
- package/dist/lifecycle-engine/platform/user-directory.js +13 -0
- package/dist/lifecycle-engine/platform/user-directory.js.map +1 -0
- package/dist/mcp.d.ts +92 -0
- package/dist/mcp.js +10 -0
- package/dist/mcp.js.map +1 -0
- package/dist/middleware/auth.d.ts +118 -0
- package/dist/middleware/auth.js +7 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/middleware/error-handler.d.ts +35 -0
- package/dist/middleware/error-handler.js +7 -0
- package/dist/middleware/error-handler.js.map +1 -0
- package/dist/middleware/module-guard.d.ts +33 -0
- package/dist/middleware/module-guard.js +7 -0
- package/dist/middleware/module-guard.js.map +1 -0
- package/dist/platform-admin/index.d.ts +37 -0
- package/dist/platform-admin/index.js +11 -0
- package/dist/platform-admin/index.js.map +1 -0
- package/dist/platform-admin/store.d.ts +346 -0
- package/dist/platform-admin/store.js +7 -0
- package/dist/platform-admin/store.js.map +1 -0
- package/dist/plugin-data/annotations.d.ts +6 -0
- package/dist/plugin-data/annotations.js +12 -0
- package/dist/plugin-data/annotations.js.map +1 -0
- package/dist/plugin-data/atomic-context.d.ts +41 -0
- package/dist/plugin-data/atomic-context.js +9 -0
- package/dist/plugin-data/atomic-context.js.map +1 -0
- package/dist/plugin-data/atomic.d.ts +6 -0
- package/dist/plugin-data/atomic.js +26 -0
- package/dist/plugin-data/atomic.js.map +1 -0
- package/dist/plugin-data/audit.d.ts +6 -0
- package/dist/plugin-data/audit.js +12 -0
- package/dist/plugin-data/audit.js.map +1 -0
- package/dist/plugin-data/commands.d.ts +6 -0
- package/dist/plugin-data/commands.js +8 -0
- package/dist/plugin-data/commands.js.map +1 -0
- package/dist/plugin-data/composite.d.ts +6 -0
- package/dist/plugin-data/composite.js +8 -0
- package/dist/plugin-data/composite.js.map +1 -0
- package/dist/plugin-data/delivery.d.ts +6 -0
- package/dist/plugin-data/delivery.js +16 -0
- package/dist/plugin-data/delivery.js.map +1 -0
- package/dist/plugin-data/index.d.ts +2798 -0
- package/dist/plugin-data/index.js +102 -0
- package/dist/plugin-data/index.js.map +1 -0
- package/dist/plugin-data/json-documents.d.ts +6 -0
- package/dist/plugin-data/json-documents.js +16 -0
- package/dist/plugin-data/json-documents.js.map +1 -0
- package/dist/plugin-data/outbox.d.ts +6 -0
- package/dist/plugin-data/outbox.js +16 -0
- package/dist/plugin-data/outbox.js.map +1 -0
- package/dist/plugin-data/scoped-records.d.ts +6 -0
- package/dist/plugin-data/scoped-records.js +10 -0
- package/dist/plugin-data/scoped-records.js.map +1 -0
- package/dist/plugin-sdk.d.ts +41 -0
- package/dist/plugin-sdk.js +10 -0
- package/dist/plugin-sdk.js.map +1 -0
- package/dist/sql-lifecycle/index.d.ts +138 -0
- package/dist/sql-lifecycle/index.js +167 -0
- package/dist/sql-lifecycle/index.js.map +1 -0
- package/dist/storage/index.d.ts +2 -0
- package/dist/storage/index.js +13 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/s3-compatible.d.ts +139 -0
- package/dist/storage/s3-compatible.js +11 -0
- package/dist/storage/s3-compatible.js.map +1 -0
- package/dist/tenant.d.ts +108 -0
- package/dist/tenant.js +9 -0
- package/dist/tenant.js.map +1 -0
- package/dist/workspace-context.d.ts +119 -0
- package/dist/workspace-context.js +9 -0
- package/dist/workspace-context.js.map +1 -0
- package/docs/api.md +29753 -0
- package/docs/db/README.md +49 -0
- package/docs/db/docs/api.md +1613 -0
- package/docs/db/docs/guide.md +47 -0
- package/docs/entitlements.md +60 -0
- package/docs/guide.md +48 -0
- package/docs/index.md +53 -0
- package/docs/ja/db/README.md +46 -0
- package/docs/ja/db/docs/guide.md +53 -0
- package/docs/ja/guide.md +46 -0
- package/docs/ja/lifecycle/README.md +46 -0
- package/docs/ja/lifecycle/docs/guide.md +45 -0
- package/docs/ja/storage/README.md +46 -0
- package/docs/ja/storage/docs/guide.md +43 -0
- package/docs/lifecycle/README.md +49 -0
- package/docs/lifecycle/docs/api.md +3770 -0
- package/docs/lifecycle/docs/baseline.md +50 -0
- package/docs/lifecycle/docs/guide.md +47 -0
- package/docs/storage/README.md +49 -0
- package/docs/storage/docs/api.md +470 -0
- package/docs/storage/docs/guide.md +47 -0
- package/package.json +345 -4
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createAuthMiddleware
|
|
3
|
+
} from "./chunk-XIEY2OF4.js";
|
|
4
|
+
import {
|
|
5
|
+
createErrorHandler
|
|
6
|
+
} from "./chunk-AVDMLTPF.js";
|
|
7
|
+
import {
|
|
8
|
+
createModuleGuard
|
|
9
|
+
} from "./chunk-VC2PCK2S.js";
|
|
10
|
+
import {
|
|
11
|
+
createHealthRouter
|
|
12
|
+
} from "./chunk-R4ADP2DC.js";
|
|
13
|
+
import {
|
|
14
|
+
createLifecycleGuard,
|
|
15
|
+
resolveLifecycleBackend
|
|
16
|
+
} from "./chunk-L6PMAEMB.js";
|
|
17
|
+
import {
|
|
18
|
+
createMcpRouter
|
|
19
|
+
} from "./chunk-VF5YDZJC.js";
|
|
20
|
+
import {
|
|
21
|
+
createPluginEntitlementGuard,
|
|
22
|
+
resolveEngineEntitlementPrincipal
|
|
23
|
+
} from "./chunk-46UWPEW2.js";
|
|
24
|
+
|
|
25
|
+
// src/engine.ts
|
|
26
|
+
import { Hono } from "hono";
|
|
27
|
+
import { cors } from "hono/cors";
|
|
28
|
+
import { PluginRegistry } from "@alneas/eaos-core";
|
|
29
|
+
import { McpGatekeeper } from "@alneas/eaos-core";
|
|
30
|
+
import { SecretResolver } from "@alneas/eaos-core";
|
|
31
|
+
function defineConfig(config) {
|
|
32
|
+
return config;
|
|
33
|
+
}
|
|
34
|
+
var ErpEngine = class {
|
|
35
|
+
/** Public plugin registry populated during initialize; external mutation affects subsequently composed apps. */
|
|
36
|
+
registry = new PluginRegistry();
|
|
37
|
+
/** Shared MCP policy registry populated from plugin manifests during initialize. */
|
|
38
|
+
gatekeeper = new McpGatekeeper();
|
|
39
|
+
initialized = false;
|
|
40
|
+
config;
|
|
41
|
+
/**
|
|
42
|
+
* Retains host composition configuration for registration and future app creation.
|
|
43
|
+
* @param config - App label, plugin manifests, and optional host composition settings.
|
|
44
|
+
*/
|
|
45
|
+
constructor(config) {
|
|
46
|
+
this.config = config;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Registers manifests and gatekeeper policies and validates declared plugin secrets by default.
|
|
50
|
+
* @returns No value; resolves after registration and validation, or immediately after a prior successful initialization.
|
|
51
|
+
* @throws Rejects duplicate plugin IDs, registry failures, or secret validation failures.
|
|
52
|
+
* @remarks Registration occurs before secret validation, so failure can leave partial registry state. Concurrent initialization is not serialized and retrying a failed initialization may encounter already-registered IDs. Create a new engine after correcting failed setup. No migrations or plugin activation are performed.
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* import { createErpEngine } from "@alneas/eaos-server/engine";
|
|
56
|
+
* const engine = createErpEngine({ appName: "example-service", plugins: [] });
|
|
57
|
+
* await engine.initialize();
|
|
58
|
+
* console.log(engine.getRegisteredPlugins().length); // 0
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
async initialize() {
|
|
62
|
+
if (this.initialized) return;
|
|
63
|
+
console.log(`[ErpEngine] Initializing ${this.config.appName}...`);
|
|
64
|
+
for (const manifest of this.config.plugins) {
|
|
65
|
+
if (this.registry.get(manifest.id)) throw new Error(`Duplicate plugin: ${manifest.id}`);
|
|
66
|
+
this.registry.register(manifest);
|
|
67
|
+
if (manifest.agentCapabilities?.gatekeeperPolicies) {
|
|
68
|
+
for (const [toolName, policy] of Object.entries(
|
|
69
|
+
manifest.agentCapabilities.gatekeeperPolicies
|
|
70
|
+
)) {
|
|
71
|
+
this.gatekeeper.registerPolicy(toolName, policy);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (this.config.validateSecrets !== false && manifest.secrets && manifest.secrets.length > 0) {
|
|
75
|
+
await SecretResolver.validatePluginSecrets(manifest.id, manifest.secrets);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
this.initialized = true;
|
|
79
|
+
console.log(
|
|
80
|
+
`[ErpEngine] Successfully loaded ${this.registry.getAll().length} plugins.`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Composes registered plugin routes, shared middleware, optional MCP/custom routes, and public health endpoints.
|
|
85
|
+
* @param options - Live host adapters and route settings; see {@link CreateAppOptions}.
|
|
86
|
+
* @returns A new Hono app sharing this engine registry, gatekeeper, and configured adapters; it does not start a server.
|
|
87
|
+
* @throws Before initialization, or for synchronous middleware, plugin route factory, or health setup failures. Request-time adapter errors pass through the app error handler.
|
|
88
|
+
* @remarks Module guarding defaults on. Lifecycle enforcement is installed only when supplied, while declared plugin entitlements require their corresponding runtime checks. CORS uses configured origins with credentials enabled; unknown origins receive the first configured allow-origin value. Repeated calls create separate routers but may reuse host dependencies.
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* import { createErpEngine } from "@alneas/eaos-server/engine";
|
|
92
|
+
* const engine = createErpEngine({ appName: "example-service", plugins: [] });
|
|
93
|
+
* await engine.initialize();
|
|
94
|
+
* const app = engine.createApp();
|
|
95
|
+
* console.log((await app.request("/health/live")).status);
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
createApp(options) {
|
|
99
|
+
if (!this.initialized) throw new Error("Call initialize() before createApp()");
|
|
100
|
+
const app = new Hono();
|
|
101
|
+
app.onError(createErrorHandler());
|
|
102
|
+
if (this.config.cors?.allowOrigins && this.config.cors.allowOrigins.length > 0) {
|
|
103
|
+
const allowed = this.config.cors.allowOrigins;
|
|
104
|
+
app.use(
|
|
105
|
+
"*",
|
|
106
|
+
cors({
|
|
107
|
+
origin: (origin) => allowed.includes(origin) ? origin : allowed[0],
|
|
108
|
+
allowMethods: ["POST", "GET", "PUT", "PATCH", "DELETE", "OPTIONS"],
|
|
109
|
+
credentials: true
|
|
110
|
+
})
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
const verifier = options?.verifier || this.config.auth?.verifier;
|
|
114
|
+
if (verifier) {
|
|
115
|
+
app.use("*", createAuthMiddleware({ verifier, skipPaths: this.config.auth?.skipPaths }));
|
|
116
|
+
}
|
|
117
|
+
if (this.config.middleware) {
|
|
118
|
+
for (const mw of this.config.middleware) {
|
|
119
|
+
mw(app);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
for (const plugin of this.registry.getAll()) {
|
|
123
|
+
if (plugin.entitlement?.allowedTenants) {
|
|
124
|
+
const conceal = async (c, next) => {
|
|
125
|
+
const principal = await (options?.resolveEntitlementPrincipal ?? resolveEngineEntitlementPrincipal)(c);
|
|
126
|
+
if (!principal) return c.json({ error: "Unauthorized" }, 401);
|
|
127
|
+
if (!plugin.entitlement.allowedTenants.includes(principal.tenantId)) return c.json({ error: "Plugin unavailable" }, 404);
|
|
128
|
+
await next();
|
|
129
|
+
};
|
|
130
|
+
app.use(`${plugin.api.prefix}/*`, conceal);
|
|
131
|
+
}
|
|
132
|
+
if (options?.lifecycle) {
|
|
133
|
+
const guard = createLifecycleGuard(options.lifecycle, plugin.id);
|
|
134
|
+
app.use(plugin.api.prefix, guard);
|
|
135
|
+
app.use(`${plugin.api.prefix}/*`, guard);
|
|
136
|
+
}
|
|
137
|
+
if (options?.enableModuleGuard !== false) {
|
|
138
|
+
const guard = options?.requireModule ? options.requireModule(plugin.id) : createModuleGuard(plugin.id);
|
|
139
|
+
app.use(`${plugin.api.prefix}/*`, guard);
|
|
140
|
+
if (plugin.extensions) {
|
|
141
|
+
for (const ext of plugin.extensions) {
|
|
142
|
+
const requiredKey = ext.industry ? `industry_${ext.industry}` : ext.id;
|
|
143
|
+
const extGuard = options?.requireModule ? options.requireModule(requiredKey) : createModuleGuard(requiredKey);
|
|
144
|
+
app.use(`${plugin.api.prefix}/${ext.id}/*`, extGuard);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (plugin.entitlement) {
|
|
149
|
+
const guard = createPluginEntitlementGuard(plugin.id, plugin.entitlement, options?.entitlements, options?.resolveEntitlementPrincipal);
|
|
150
|
+
app.use(`${plugin.api.prefix}/*`, guard);
|
|
151
|
+
}
|
|
152
|
+
if (plugin.createRoutes) {
|
|
153
|
+
app.route(plugin.api.prefix, plugin.createRoutes(options?.pluginOptions?.[plugin.id]));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (options?.mcp) app.route(options.mcp.prefix ?? "/api/mcp", createMcpRouter(this, {
|
|
157
|
+
...options.mcp,
|
|
158
|
+
entitlements: options.entitlements ?? options.mcp.entitlements,
|
|
159
|
+
isPluginEnabled: async (principal, id) => (!options.lifecycle || await options.lifecycle.lifecycle.isEnabled(await resolveLifecycleBackend(options.lifecycle, principal.tenantId), principal.tenantId, id)) && (!options.mcp?.isPluginEnabled || await options.mcp.isPluginEnabled(principal, id))
|
|
160
|
+
}));
|
|
161
|
+
if (options?.customRoutes) {
|
|
162
|
+
for (const { prefix, router } of options.customRoutes) {
|
|
163
|
+
app.route(prefix, router);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
app.route("/", createHealthRouter({ appName: this.config.appName, ...options?.health }));
|
|
167
|
+
return app;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Reads the manifests currently registered in this engine.
|
|
171
|
+
* @returns Registry manifest list, empty before registration or with no configured plugins; objects are not deep-cloned by this method.
|
|
172
|
+
* @example
|
|
173
|
+
* ```typescript
|
|
174
|
+
* import { createErpEngine } from "@alneas/eaos-server/engine";
|
|
175
|
+
* const engine = createErpEngine({ appName: "example-service", plugins: [] });
|
|
176
|
+
* await engine.initialize();
|
|
177
|
+
* console.log(engine.getRegisteredPlugins()); // []
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
getRegisteredPlugins() {
|
|
181
|
+
return this.registry.getAll();
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Collects MCP tool definitions from all currently registered manifests.
|
|
185
|
+
* @returns Registry tool definitions, or an empty array when none exist; this list is not filtered for a request principal or tenant.
|
|
186
|
+
* @example
|
|
187
|
+
* ```typescript
|
|
188
|
+
* import { createErpEngine } from "@alneas/eaos-server/engine";
|
|
189
|
+
* const engine = createErpEngine({ appName: "example-service", plugins: [] });
|
|
190
|
+
* await engine.initialize();
|
|
191
|
+
* console.log(engine.getAllMcpTools()); // []
|
|
192
|
+
* ```
|
|
193
|
+
*/
|
|
194
|
+
getAllMcpTools() {
|
|
195
|
+
return this.registry.getAllMcpTools();
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Reads the host configuration retained at construction.
|
|
199
|
+
* @returns The original mutable configuration object; no cloning occurs.
|
|
200
|
+
* @example
|
|
201
|
+
* ```typescript
|
|
202
|
+
* import { createErpEngine } from "@alneas/eaos-server/engine";
|
|
203
|
+
* const engine = createErpEngine({ appName: "example-service", plugins: [] });
|
|
204
|
+
* await engine.initialize();
|
|
205
|
+
* console.log(engine.getConfig().appName);
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
getConfig() {
|
|
209
|
+
return this.config;
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
function createErpEngine(config) {
|
|
213
|
+
return new ErpEngine(config);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export {
|
|
217
|
+
defineConfig,
|
|
218
|
+
ErpEngine,
|
|
219
|
+
createErpEngine
|
|
220
|
+
};
|
|
221
|
+
//# sourceMappingURL=chunk-6KV5CJBW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/engine.ts"],"sourcesContent":["import { resolveLifecycleBackend, createLifecycleGuard, type LifecycleRuntime } from './lifecycle/index'\nimport { createMcpRouter, type McpRouterOptions } from './mcp'\nimport { Hono } from 'hono'\nimport { cors } from 'hono/cors'\nimport { PluginRegistry } from '@alneas/eaos-core'\nimport { McpGatekeeper } from '@alneas/eaos-core'\nimport { SecretResolver } from '@alneas/eaos-core'\nimport { createModuleGuard } from './middleware/module-guard'\nimport { createAuthMiddleware, type AuthSessionVerifier } from './middleware/auth'\nimport { createErrorHandler } from './middleware/error-handler'\nimport type { PluginManifest } from '@alneas/eaos-core'\nimport type { EaosEnv } from '@alneas/eaos-core'\nimport { createHealthRouter, type HealthRouterOptions } from './health/index'\nimport { createPluginEntitlementGuard, resolveEngineEntitlementPrincipal, type PluginEntitlementRuntime, type EntitlementPrincipalResolver } from './entitlements/index'\n\n// ---------- Config 型 ----------\n\n/**\n * Engine composition settings retained by {@link ErpEngine}; host adapters own authentication and persistence.\n */\nexport interface EaosConfig {\n /** Nonblank application label used by public health responses. */\n appName: string\n /** Trusted plugin manifests registered sequentially during initialize. */\n plugins: PluginManifest[]\n /** Optional host UI theme metadata retained in config; the server engine does not apply it. */\n theme?: {\n /** Optional host UI accent color; not interpreted by this engine. */\n primaryColor?: string\n /** Optional host UI logo URL; not fetched by this engine. */\n logoUrl?: string\n }\n /** Optional host driver metadata retained in config; this engine does not create a database connection. */\n database?: {\n /** Selected host database dialect; does not create or migrate a connection. */\n driver: 'oracle' | 'supabase' | 'postgres'\n }\n /** Optional exact browser allowOrigins list; empty/absent disables CORS middleware. */\n cors?: {\n /** Exact allowed browser origins; credentials are enabled for configured CORS. */\n allowOrigins: string[]\n }\n /** Optional verifier and skipped path prefixes; see AuthMiddlewareOptions. */\n auth?: {\n /** Optional verified session/API-key adapter; omission installs no authentication. */\n verifier?: AuthSessionVerifier\n /** Authentication-exempt path prefixes; defaults follow createAuthMiddleware. */\n skipPaths?: string[]\n }\n /** Validate each manifest's declared secrets unless exactly false. Defaults to true. */\n validateSecrets?: boolean\n /** Host composition callbacks invoked synchronously after shared authentication and before plugin route guards; each receives the app and returns no value. */\n middleware?: Array<(app: Hono<EaosEnv>) => void>\n}\n\n/**\n * Returns an engine configuration unchanged while checking its TypeScript shape.\n * @param config - Configuration to retain; no runtime validation or cloning occurs.\n * @returns The same object reference.\n * @example\n * ```typescript\n * import { defineConfig } from \"@alneas/eaos-server/engine\";\n * const config = defineConfig({ appName: \"example-service\", plugins: [] });\n * console.log(config.appName);\n * ```\n */\nexport function defineConfig(config: EaosConfig): EaosConfig {\n return config\n}\n\n// ---------- Engine ----------\n\n/**\n * Per-application host authorization, route, and health adapters for {@link ErpEngine.createApp}.\n */\nexport interface CreateAppOptions {\n /** Optional shared runtime for declared commercial/usage entitlement admission. */\n entitlements?: PluginEntitlementRuntime\n /** Optional verified principal resolver; defaults to resolveEngineEntitlementPrincipal. */\n resolveEntitlementPrincipal?: EntitlementPrincipalResolver\n /** Optional current lifecycle/tenant/backend admission for plugin routes and MCP tools. */\n lifecycle?: LifecycleRuntime\n /** Optional module middleware factory called at composition for each plugin/extension requirement; defaults to createModuleGuard. */\n requireModule?: (moduleId: string) => any\n /** Optional authentication verifier overriding config.auth.verifier. */\n verifier?: AuthSessionVerifier\n /** Install module guards unless exactly false. Defaults to true. */\n enableModuleGuard?: boolean\n /** Per-plugin dependencies passed to the route factory. */\n pluginOptions?: Record<string, unknown>\n /** Optional MCP adapter configuration; prefix defaults to /api/mcp and shared entitlements take precedence. */\n mcp?: McpRouterOptions & { \n /**\n * Optional mount path for the shared MCP router; defaults to /api/mcp when the engine composes routes.\n */\n prefix?: string }\n /** Additional host routers mounted after plugin/MCP routes; no plugin-specific guard is automatically added. */\n customRoutes?: Array<{\n /** Host-selected mount prefix passed directly to Hono route composition; this entry receives no automatic plugin/module-specific guard. */\n prefix: string\n /** Trusted Hono child router; host composition must install its route-specific authorization before exposing handlers. */\n router: Hono<any>\n }>\n /** Optional dependency readiness checks and clock; engine appName is supplied automatically. */\n health?: Omit<HealthRouterOptions, 'appName'>\n}\n\n/**\n * Registers plugin manifests and composes Hono routes with host authentication, entitlement, and lifecycle adapters.\n * @remarks Constructing the engine creates no HTTP listener or persistent store. Initialize once before composing apps. Configuration is retained by reference. Authentication is installed only when a verifier is supplied; custom routes need their own authorization policies beyond the shared middleware.\n * @example\n * ```typescript\n * import { createErpEngine } from \"@alneas/eaos-server/engine\";\n * const engine = createErpEngine({ appName: \"example-service\", plugins: [] });\n * await engine.initialize();\n * const app = engine.createApp();\n * console.log((await app.request(\"/health/live\")).status); // 200\n * ```\n */\nexport class ErpEngine {\n /** Public plugin registry populated during initialize; external mutation affects subsequently composed apps. */\n readonly registry = new PluginRegistry()\n /** Shared MCP policy registry populated from plugin manifests during initialize. */\n readonly gatekeeper = new McpGatekeeper()\n private initialized = false\n private config: EaosConfig\n\n /**\n * Retains host composition configuration for registration and future app creation.\n * @param config - App label, plugin manifests, and optional host composition settings.\n */\n constructor(config: EaosConfig) {\n this.config = config\n }\n\n /**\n * Registers manifests and gatekeeper policies and validates declared plugin secrets by default.\n * @returns No value; resolves after registration and validation, or immediately after a prior successful initialization.\n * @throws Rejects duplicate plugin IDs, registry failures, or secret validation failures.\n * @remarks Registration occurs before secret validation, so failure can leave partial registry state. Concurrent initialization is not serialized and retrying a failed initialization may encounter already-registered IDs. Create a new engine after correcting failed setup. No migrations or plugin activation are performed.\n * @example\n * ```typescript\n * import { createErpEngine } from \"@alneas/eaos-server/engine\";\n * const engine = createErpEngine({ appName: \"example-service\", plugins: [] });\n * await engine.initialize();\n * console.log(engine.getRegisteredPlugins().length); // 0\n * ```\n */\n async initialize(): Promise<void> {\n if (this.initialized) return\n console.log(`[ErpEngine] Initializing ${this.config.appName}...`)\n\n for (const manifest of this.config.plugins) {\n if (this.registry.get(manifest.id)) throw new Error(`Duplicate plugin: ${manifest.id}`)\n this.registry.register(manifest)\n\n if (manifest.agentCapabilities?.gatekeeperPolicies) {\n for (const [toolName, policy] of Object.entries(\n manifest.agentCapabilities.gatekeeperPolicies\n )) {\n this.gatekeeper.registerPolicy(toolName, policy)\n }\n }\n\n if (\n this.config.validateSecrets !== false &&\n manifest.secrets &&\n manifest.secrets.length > 0\n ) {\n await SecretResolver.validatePluginSecrets(manifest.id, manifest.secrets)\n }\n }\n\n this.initialized = true\n console.log(\n `[ErpEngine] Successfully loaded ${this.registry.getAll().length} plugins.`\n )\n }\n\n /**\n * Composes registered plugin routes, shared middleware, optional MCP/custom routes, and public health endpoints.\n * @param options - Live host adapters and route settings; see {@link CreateAppOptions}.\n * @returns A new Hono app sharing this engine registry, gatekeeper, and configured adapters; it does not start a server.\n * @throws Before initialization, or for synchronous middleware, plugin route factory, or health setup failures. Request-time adapter errors pass through the app error handler.\n * @remarks Module guarding defaults on. Lifecycle enforcement is installed only when supplied, while declared plugin entitlements require their corresponding runtime checks. CORS uses configured origins with credentials enabled; unknown origins receive the first configured allow-origin value. Repeated calls create separate routers but may reuse host dependencies.\n * @example\n * ```typescript\n * import { createErpEngine } from \"@alneas/eaos-server/engine\";\n * const engine = createErpEngine({ appName: \"example-service\", plugins: [] });\n * await engine.initialize();\n * const app = engine.createApp();\n * console.log((await app.request(\"/health/live\")).status);\n * ```\n */\n createApp(options?: CreateAppOptions): Hono<EaosEnv> {\n if (!this.initialized) throw new Error(\"Call initialize() before createApp()\")\n const app = new Hono<EaosEnv>()\n\n // 1. エラーハンドラ登録\n app.onError(createErrorHandler())\n\n // 2. CORS\n if (this.config.cors?.allowOrigins && this.config.cors.allowOrigins.length > 0) {\n const allowed = this.config.cors.allowOrigins\n app.use(\n '*',\n cors({\n origin: (origin) =>\n allowed.includes(origin) ? origin : allowed[0],\n allowMethods: ['POST', 'GET', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],\n credentials: true,\n })\n )\n }\n\n // 3. 認証ミドルウェア (Ory Kratos / API Key / Bearer)\n const verifier = options?.verifier || this.config.auth?.verifier\n if (verifier) {\n app.use('*', createAuthMiddleware({ verifier, skipPaths: this.config.auth?.skipPaths }))\n }\n\n // 4. Config 層から注入された独自ミドルウェア\n if (this.config.middleware) {\n for (const mw of this.config.middleware) {\n mw(app)\n }\n }\n\n // 5. Plugin 層のルートを動的マウント & ライセンス認可ガード (requireModule)\n for (const plugin of this.registry.getAll()) {\n if (plugin.entitlement?.allowedTenants) {\n const conceal = async (c: any, next: () => Promise<void>) => {\n const principal = await (options?.resolveEntitlementPrincipal ?? resolveEngineEntitlementPrincipal)(c)\n if (!principal) return c.json({ error: 'Unauthorized' }, 401)\n if (!plugin.entitlement!.allowedTenants!.includes(principal.tenantId)) return c.json({ error: 'Plugin unavailable' }, 404)\n await next()\n }\n app.use(`${plugin.api.prefix}/*`, conceal)\n }\n if (options?.lifecycle) {\n const guard = createLifecycleGuard(options.lifecycle, plugin.id)\n app.use(plugin.api.prefix, guard)\n app.use(`${plugin.api.prefix}/*`, guard)\n }\n if (options?.enableModuleGuard !== false) {\n const guard = options?.requireModule ? options.requireModule(plugin.id) : createModuleGuard(plugin.id)\n app.use(`${plugin.api.prefix}/*`, guard)\n\n if (plugin.extensions) {\n for (const ext of plugin.extensions) {\n const requiredKey = ext.industry ? `industry_${ext.industry}` : ext.id\n const extGuard = options?.requireModule ? options.requireModule(requiredKey) : createModuleGuard(requiredKey)\n app.use(`${plugin.api.prefix}/${ext.id}/*`, extGuard)\n }\n }\n }\n\n if (plugin.entitlement) {\n const guard = createPluginEntitlementGuard(plugin.id, plugin.entitlement, options?.entitlements, options?.resolveEntitlementPrincipal)\n app.use(`${plugin.api.prefix}/*`, guard)\n }\n if (plugin.createRoutes) {\n app.route(plugin.api.prefix, plugin.createRoutes(options?.pluginOptions?.[plugin.id]))\n }\n }\n\n if (options?.mcp) app.route(options.mcp.prefix ?? '/api/mcp', createMcpRouter(this, {\n ...options.mcp,\n entitlements: options.entitlements ?? options.mcp.entitlements,\n isPluginEnabled: async (principal, id) =>\n (!options.lifecycle || await options.lifecycle.lifecycle.isEnabled(await resolveLifecycleBackend(options.lifecycle, principal.tenantId), principal.tenantId, id)) &&\n (!options.mcp?.isPluginEnabled || await options.mcp.isPluginEnabled(principal, id)),\n }))\n\n // 6. カスタムルートのマウント\n if (options?.customRoutes) {\n for (const { prefix, router } of options.customRoutes) {\n app.route(prefix, router)\n }\n }\n\n // 7. Liveness/readiness. Dependency checks are explicit host adapters.\n app.route('/', createHealthRouter({ appName: this.config.appName, ...options?.health }))\n\n return app\n }\n\n /**\n * Reads the manifests currently registered in this engine.\n * @returns Registry manifest list, empty before registration or with no configured plugins; objects are not deep-cloned by this method.\n * @example\n * ```typescript\n * import { createErpEngine } from \"@alneas/eaos-server/engine\";\n * const engine = createErpEngine({ appName: \"example-service\", plugins: [] });\n * await engine.initialize();\n * console.log(engine.getRegisteredPlugins()); // []\n * ```\n */\n getRegisteredPlugins(): PluginManifest[] {\n return this.registry.getAll()\n }\n\n /**\n * Collects MCP tool definitions from all currently registered manifests.\n * @returns Registry tool definitions, or an empty array when none exist; this list is not filtered for a request principal or tenant.\n * @example\n * ```typescript\n * import { createErpEngine } from \"@alneas/eaos-server/engine\";\n * const engine = createErpEngine({ appName: \"example-service\", plugins: [] });\n * await engine.initialize();\n * console.log(engine.getAllMcpTools()); // []\n * ```\n */\n getAllMcpTools() {\n return this.registry.getAllMcpTools()\n }\n\n /**\n * Reads the host configuration retained at construction.\n * @returns The original mutable configuration object; no cloning occurs.\n * @example\n * ```typescript\n * import { createErpEngine } from \"@alneas/eaos-server/engine\";\n * const engine = createErpEngine({ appName: \"example-service\", plugins: [] });\n * await engine.initialize();\n * console.log(engine.getConfig().appName);\n * ```\n */\n getConfig(): EaosConfig {\n return this.config\n }\n}\n\n/**\n * Creates an uninitialized engine retaining the supplied host configuration.\n * @param config - Engine composition settings; see {@link EaosConfig}.\n * @returns A new engine; await initialize before createApp.\n * @example\n * ```typescript\n * import { createErpEngine } from \"@alneas/eaos-server/engine\";\n * const engine = createErpEngine({ appName: \"example-service\", plugins: [] });\n * await engine.initialize();\n * const app = engine.createApp();\n * console.log((await app.request(\"/health/live\")).status);\n * ```\n */\nexport function createErpEngine(config: EaosConfig): ErpEngine {\n return new ErpEngine(config)\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// src/agentic/agent-runner.ts
|
|
2
|
+
import {
|
|
3
|
+
parseWorkflowAgentProposal
|
|
4
|
+
} from "@alneas/eaos-core";
|
|
5
|
+
function createWorkflowAgentRunner(options) {
|
|
6
|
+
if (typeof options?.executor !== "function") throw new Error("Workflow agent executor is required");
|
|
7
|
+
return {
|
|
8
|
+
async run(request) {
|
|
9
|
+
const startedAt = Date.now();
|
|
10
|
+
const task = {
|
|
11
|
+
id: request.taskId,
|
|
12
|
+
tenantId: request.tenantId,
|
|
13
|
+
userId: request.userId,
|
|
14
|
+
title: request.purpose,
|
|
15
|
+
workerType: "custom",
|
|
16
|
+
...request.jobKind === void 0 ? {} : { jobKind: request.jobKind },
|
|
17
|
+
instructions: JSON.stringify({
|
|
18
|
+
schemaVersion: "1.0",
|
|
19
|
+
purpose: request.purpose,
|
|
20
|
+
input: request.input,
|
|
21
|
+
toolScope: request.toolScope,
|
|
22
|
+
output: "Return only a JSON WorkflowAgentProposal with schemaVersion 1.0."
|
|
23
|
+
}),
|
|
24
|
+
executionContext: {
|
|
25
|
+
workflowId: request.workflowId,
|
|
26
|
+
correlationId: request.correlationId,
|
|
27
|
+
idempotencyKey: request.idempotencyKey,
|
|
28
|
+
toolMode: request.toolScope.mode,
|
|
29
|
+
allowedToolNames: request.toolScope.allowedToolNames
|
|
30
|
+
},
|
|
31
|
+
timeoutMs: request.timeoutMs
|
|
32
|
+
};
|
|
33
|
+
let rawOutput;
|
|
34
|
+
try {
|
|
35
|
+
rawOutput = await options.executor(task);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
const failureCode = isAgentFailureCode(error) ? error.failureCode : "RUNTIME_FAILED";
|
|
38
|
+
const retryable = isAgentRetryable(error) ?? (failureCode === "AGENT_UNAVAILABLE" || failureCode === "TIMEOUT" || failureCode === "RUNTIME_FAILED");
|
|
39
|
+
return {
|
|
40
|
+
status: failureCode === "AGENT_UNAVAILABLE" ? "UNAVAILABLE" : "FAILED",
|
|
41
|
+
error: error instanceof Error ? error.message : "Workflow agent execution failed",
|
|
42
|
+
failureCode,
|
|
43
|
+
retryable,
|
|
44
|
+
...options.runtimeId ? { runtimeId: options.runtimeId } : {},
|
|
45
|
+
durationMs: Date.now() - startedAt
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const proposal = parseWorkflowAgentProposal(rawOutput);
|
|
50
|
+
return { status: "COMPLETED", proposal, ...options.runtimeId ? { runtimeId: options.runtimeId } : {}, durationMs: Date.now() - startedAt };
|
|
51
|
+
} catch (error) {
|
|
52
|
+
return {
|
|
53
|
+
status: "FAILED",
|
|
54
|
+
error: error instanceof Error ? error.message : "Invalid workflow agent proposal",
|
|
55
|
+
failureCode: "INVALID_PROPOSAL",
|
|
56
|
+
retryable: false,
|
|
57
|
+
...options.runtimeId ? { runtimeId: options.runtimeId } : {},
|
|
58
|
+
durationMs: Date.now() - startedAt
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function isAgentFailureCode(error) {
|
|
65
|
+
return typeof error === "object" && error !== null && "failureCode" in error && typeof error.failureCode === "string";
|
|
66
|
+
}
|
|
67
|
+
function isAgentRetryable(error) {
|
|
68
|
+
return typeof error === "object" && error !== null && "retryable" in error && typeof error.retryable === "boolean" ? error.retryable : void 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export {
|
|
72
|
+
createWorkflowAgentRunner
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=chunk-6XZXYNJR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/agentic/agent-runner.ts"],"sourcesContent":["import {\n parseWorkflowAgentProposal,\n type WorkflowAgentRequest,\n type WorkflowAgentRunResult,\n type WorkflowAgentRunner,\n} from '@alneas/eaos-core'\nimport type { ServerAgentExecutor, ServerAgentTaskRequest } from './types'\n\n/**\n * Host executor configuration for {@link createWorkflowAgentRunner}.\n */\nexport interface ServerWorkflowAgentRunnerOptions {\n /** Host-owned executor. It may be backed by Goose, Hermes or another runtime. */\n executor: ServerAgentExecutor\n /** Optional host runtime label copied into every normalized run result. */\n runtimeId?: string\n}\n\n/**\n * Bridges the host/server executor contract to the vendor-neutral workflow\n * runner contract. The executor output is parsed as a proposal; it is never\n * treated as an instruction to perform a side effect.\n * @param options - Host-owned executor and optional runtime label.\n * @returns A runner whose generic run method accepts a WorkflowAgentRequest and resolves a parsed proposal or a failure result. Executor errors become FAILED/UNAVAILABLE data; parse errors become nonretryable INVALID_PROPOSAL data.\n * @throws Synchronously when executor is missing. run may reject before execution when request serialization fails.\n * @remarks The runner forwards workflow/correlation/idempotency/tool context but does not independently authorize, retry, deduplicate, execute tools, or enforce timeouts. Those boundaries belong to the host executor. Runtime text must parse as a version 1.0 proposal; domain-specific output still needs plugin validation.\n * @example\n * ```typescript\n * import { createWorkflowAgentRunner } from \"@alneas/eaos-server/agentic/agent-runner\";\n * import type { ServerAgentExecutor } from \"@alneas/eaos-server/agentic/types\";\n * export function workflowRunner(executor: ServerAgentExecutor) {\n * return createWorkflowAgentRunner({ executor, runtimeId: \"host-runtime\" });\n * }\n * ```\n */\nexport function createWorkflowAgentRunner(options: ServerWorkflowAgentRunnerOptions): WorkflowAgentRunner {\n if (typeof options?.executor !== 'function') throw new Error('Workflow agent executor is required')\n\n return {\n async run<TOutput>(request: WorkflowAgentRequest): Promise<WorkflowAgentRunResult<TOutput>> {\n const startedAt = Date.now()\n const task: ServerAgentTaskRequest = {\n id: request.taskId,\n tenantId: request.tenantId,\n userId: request.userId,\n title: request.purpose,\n workerType: 'custom',\n ...(request.jobKind === undefined ? {} : { jobKind: request.jobKind }),\n instructions: JSON.stringify({\n schemaVersion: '1.0',\n purpose: request.purpose,\n input: request.input,\n toolScope: request.toolScope,\n output: 'Return only a JSON WorkflowAgentProposal with schemaVersion 1.0.',\n }),\n executionContext: {\n workflowId: request.workflowId,\n correlationId: request.correlationId,\n idempotencyKey: request.idempotencyKey,\n toolMode: request.toolScope.mode,\n allowedToolNames: request.toolScope.allowedToolNames,\n },\n timeoutMs: request.timeoutMs,\n }\n\n let rawOutput: string\n try {\n rawOutput = await options.executor(task)\n } catch (error) {\n const failureCode = isAgentFailureCode(error) ? error.failureCode : 'RUNTIME_FAILED'\n const retryable = isAgentRetryable(error) ?? (failureCode === 'AGENT_UNAVAILABLE' || failureCode === 'TIMEOUT' || failureCode === 'RUNTIME_FAILED')\n return {\n status: failureCode === 'AGENT_UNAVAILABLE' ? 'UNAVAILABLE' : 'FAILED',\n error: error instanceof Error ? error.message : 'Workflow agent execution failed',\n failureCode,\n retryable,\n ...(options.runtimeId ? { runtimeId: options.runtimeId } : {}),\n durationMs: Date.now() - startedAt,\n }\n }\n\n try {\n const proposal = parseWorkflowAgentProposal<TOutput>(rawOutput)\n return { status: 'COMPLETED', proposal, ...(options.runtimeId ? { runtimeId: options.runtimeId } : {}), durationMs: Date.now() - startedAt }\n } catch (error) {\n return {\n status: 'FAILED',\n error: error instanceof Error ? error.message : 'Invalid workflow agent proposal',\n failureCode: 'INVALID_PROPOSAL',\n retryable: false,\n ...(options.runtimeId ? { runtimeId: options.runtimeId } : {}),\n durationMs: Date.now() - startedAt,\n }\n }\n },\n }\n}\n\nfunction isAgentFailureCode(error: unknown): error is { failureCode: NonNullable<WorkflowAgentRunResult['failureCode']> } {\n return typeof error === 'object' && error !== null && 'failureCode' in error && typeof error.failureCode === 'string'\n}\n\nfunction isAgentRetryable(error: unknown): boolean | undefined {\n return typeof error === 'object' && error !== null && 'retryable' in error && typeof error.retryable === 'boolean'\n ? error.retryable\n : undefined\n}\n"],"mappings":";AAAA;AAAA,EACE;AAAA,OAIK;AA8BA,SAAS,0BAA0B,SAAgE;AACxG,MAAI,OAAO,SAAS,aAAa,WAAY,OAAM,IAAI,MAAM,qCAAqC;AAElG,SAAO;AAAA,IACL,MAAM,IAAa,SAAyE;AAC1F,YAAM,YAAY,KAAK,IAAI;AAC3B,YAAM,OAA+B;AAAA,QACnC,IAAI,QAAQ;AAAA,QACZ,UAAU,QAAQ;AAAA,QAClB,QAAQ,QAAQ;AAAA,QAChB,OAAO,QAAQ;AAAA,QACf,YAAY;AAAA,QACZ,GAAI,QAAQ,YAAY,SAAY,CAAC,IAAI,EAAE,SAAS,QAAQ,QAAQ;AAAA,QACpE,cAAc,KAAK,UAAU;AAAA,UAC3B,eAAe;AAAA,UACf,SAAS,QAAQ;AAAA,UACjB,OAAO,QAAQ;AAAA,UACf,WAAW,QAAQ;AAAA,UACnB,QAAQ;AAAA,QACV,CAAC;AAAA,QACD,kBAAkB;AAAA,UAChB,YAAY,QAAQ;AAAA,UACpB,eAAe,QAAQ;AAAA,UACvB,gBAAgB,QAAQ;AAAA,UACxB,UAAU,QAAQ,UAAU;AAAA,UAC5B,kBAAkB,QAAQ,UAAU;AAAA,QACtC;AAAA,QACA,WAAW,QAAQ;AAAA,MACrB;AAEA,UAAI;AACJ,UAAI;AACF,oBAAY,MAAM,QAAQ,SAAS,IAAI;AAAA,MACzC,SAAS,OAAO;AACd,cAAM,cAAc,mBAAmB,KAAK,IAAI,MAAM,cAAc;AACpE,cAAM,YAAY,iBAAiB,KAAK,MAAM,gBAAgB,uBAAuB,gBAAgB,aAAa,gBAAgB;AAClI,eAAO;AAAA,UACL,QAAQ,gBAAgB,sBAAsB,gBAAgB;AAAA,UAC9D,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,UAChD;AAAA,UACA;AAAA,UACA,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,UAC5D,YAAY,KAAK,IAAI,IAAI;AAAA,QAC3B;AAAA,MACF;AAEA,UAAI;AACF,cAAM,WAAW,2BAAoC,SAAS;AAC9D,eAAO,EAAE,QAAQ,aAAa,UAAU,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC,GAAI,YAAY,KAAK,IAAI,IAAI,UAAU;AAAA,MAC7I,SAAS,OAAO;AACd,eAAO;AAAA,UACL,QAAQ;AAAA,UACR,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,UAChD,aAAa;AAAA,UACb,WAAW;AAAA,UACX,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,UAC5D,YAAY,KAAK,IAAI,IAAI;AAAA,QAC3B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,mBAAmB,OAA8F;AACxH,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,iBAAiB,SAAS,OAAO,MAAM,gBAAgB;AAC/G;AAEA,SAAS,iBAAiB,OAAqC;AAC7D,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,eAAe,SAAS,OAAO,MAAM,cAAc,YACrG,MAAM,YACN;AACN;","names":[]}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
// src/platform-admin/index.ts
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import { assertBackendMigrationCutover, planBackendMigration } from "@alneas/eaos-server/lifecycle-engine";
|
|
4
|
+
function object(value) {
|
|
5
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Request body must be an object");
|
|
6
|
+
return value;
|
|
7
|
+
}
|
|
8
|
+
function string(value, name, max = 256) {
|
|
9
|
+
if (typeof value !== "string" || !value.trim() || value.length > max) throw new Error(`Invalid ${name}`);
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
function stringArray(value, name, max = 128) {
|
|
13
|
+
if (!Array.isArray(value) || value.length === 0 || value.length > max || value.some((item) => typeof item !== "string" || !item.trim())) throw new Error(`Invalid ${name}`);
|
|
14
|
+
return [...value];
|
|
15
|
+
}
|
|
16
|
+
async function body(c) {
|
|
17
|
+
return object(await c.req.json().catch(() => null));
|
|
18
|
+
}
|
|
19
|
+
function publicBackend(backend) {
|
|
20
|
+
return {
|
|
21
|
+
id: backend.id,
|
|
22
|
+
databaseId: backend.databaseId,
|
|
23
|
+
dialect: backend.dialect,
|
|
24
|
+
mode: backend.mode,
|
|
25
|
+
...backend.tenantId === void 0 ? {} : { tenantId: backend.tenantId },
|
|
26
|
+
...backend.label === void 0 ? {} : { label: backend.label },
|
|
27
|
+
...backend.provider === void 0 ? {} : { provider: backend.provider },
|
|
28
|
+
...backend.capabilities === void 0 ? {} : { capabilities: backend.capabilities }
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function createPlatformAdminRouter(options) {
|
|
32
|
+
if (!options?.store || !options.resolvePrincipal || !options.authorize || !options.audit) throw new Error("Platform admin router dependencies are required");
|
|
33
|
+
const app = new Hono();
|
|
34
|
+
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
35
|
+
const access = async (request, action, tenantId) => {
|
|
36
|
+
const principal = await options.resolvePrincipal(request);
|
|
37
|
+
if (!principal) return new Response(JSON.stringify({ error: "Authentication required" }), { status: 401, headers: { "content-type": "application/json" } });
|
|
38
|
+
const allowed = principal.isPlatformAdmin === true && await options.authorize(principal, action, tenantId);
|
|
39
|
+
if (!allowed) {
|
|
40
|
+
await options.audit({ action, actorId: principal.userId, ...tenantId ? { tenantId } : {}, outcome: "denied", occurredAt: now().toISOString() });
|
|
41
|
+
return new Response(JSON.stringify({ error: "Platform administrator access required" }), { status: 403, headers: { "content-type": "application/json" } });
|
|
42
|
+
}
|
|
43
|
+
return { principal };
|
|
44
|
+
};
|
|
45
|
+
const failure = (error, status = 400) => new Response(JSON.stringify({ error: error instanceof Error ? error.message : "Request failed" }), { status, headers: { "content-type": "application/json" } });
|
|
46
|
+
app.get("/tenants", async (c) => {
|
|
47
|
+
const authorized = await access(c.req.raw, "tenant:list");
|
|
48
|
+
if (authorized instanceof Response) return authorized;
|
|
49
|
+
return c.json({ tenants: await options.store.listTenants() });
|
|
50
|
+
});
|
|
51
|
+
app.post("/tenants", async (c) => {
|
|
52
|
+
const authorized = await access(c.req.raw, "tenant:create");
|
|
53
|
+
if (authorized instanceof Response) return authorized;
|
|
54
|
+
try {
|
|
55
|
+
const input = await body(c);
|
|
56
|
+
const tenant = await options.store.createTenant({ id: string(input.id, "tenant id"), name: string(input.name, "tenant name"), domains: stringArray(input.domains, "domains"), backendId: string(input.backendId, "initial backend id") });
|
|
57
|
+
await options.audit({ action: "tenant:create", actorId: authorized.principal.userId, tenantId: tenant.id, outcome: "allowed", occurredAt: now().toISOString() });
|
|
58
|
+
return c.json({ tenant }, 201);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
return failure(error);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
app.patch("/tenants/:tenantId", async (c) => {
|
|
64
|
+
const tenantId = string(c.req.param("tenantId"), "tenant id");
|
|
65
|
+
const authorized = await access(c.req.raw, "tenant:update", tenantId);
|
|
66
|
+
if (authorized instanceof Response) return authorized;
|
|
67
|
+
try {
|
|
68
|
+
const input = await body(c);
|
|
69
|
+
const patch = {
|
|
70
|
+
...input.name === void 0 ? {} : { name: string(input.name, "tenant name") },
|
|
71
|
+
...input.active === void 0 ? {} : { active: input.active === true },
|
|
72
|
+
...input.domains === void 0 ? {} : { domains: stringArray(input.domains, "domains") }
|
|
73
|
+
};
|
|
74
|
+
if (!Object.keys(patch).length) throw new Error("Tenant patch is empty");
|
|
75
|
+
const tenant = await options.store.updateTenant(tenantId, patch);
|
|
76
|
+
await options.audit({ action: "tenant:update", actorId: authorized.principal.userId, tenantId, outcome: "allowed", occurredAt: now().toISOString() });
|
|
77
|
+
return c.json({ tenant });
|
|
78
|
+
} catch (error) {
|
|
79
|
+
return failure(error);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
app.get("/backends", async (c) => {
|
|
83
|
+
const authorized = await access(c.req.raw, "backend:list");
|
|
84
|
+
if (authorized instanceof Response) return authorized;
|
|
85
|
+
return c.json({ backends: (await options.store.listBackends()).map(publicBackend) });
|
|
86
|
+
});
|
|
87
|
+
app.get("/tenants/:tenantId/placement", async (c) => {
|
|
88
|
+
const tenantId = string(c.req.param("tenantId"), "tenant id");
|
|
89
|
+
const authorized = await access(c.req.raw, "placement:read", tenantId);
|
|
90
|
+
if (authorized instanceof Response) return authorized;
|
|
91
|
+
const placement = await options.store.getTenantPlacement(tenantId);
|
|
92
|
+
if (!placement) return failure(new Error("Tenant placement not found"), 404);
|
|
93
|
+
return c.json({ placement: { ...placement, backend: publicBackend(placement.backend) } });
|
|
94
|
+
});
|
|
95
|
+
app.post("/tenants/:tenantId/placement/plan", async (c) => {
|
|
96
|
+
const tenantId = string(c.req.param("tenantId"), "tenant id");
|
|
97
|
+
const authorized = await access(c.req.raw, "placement:plan", tenantId);
|
|
98
|
+
if (authorized instanceof Response) return authorized;
|
|
99
|
+
try {
|
|
100
|
+
const input = await body(c);
|
|
101
|
+
const targetBackendId = string(input.targetBackendId, "target backend id");
|
|
102
|
+
const pluginIds = stringArray(input.pluginIds, "pluginIds");
|
|
103
|
+
const reason = string(input.reason, "migration reason", 1024);
|
|
104
|
+
const current = await options.store.getTenantPlacement(tenantId);
|
|
105
|
+
if (!current) return failure(new Error("Tenant placement not found"), 404);
|
|
106
|
+
const target = await options.store.getBackend(targetBackendId);
|
|
107
|
+
if (!target) return failure(new Error("Target backend not found"), 404);
|
|
108
|
+
const plan = planBackendMigration({
|
|
109
|
+
migrationId: `platform-${crypto.randomUUID()}`,
|
|
110
|
+
source: current.backend,
|
|
111
|
+
target,
|
|
112
|
+
scope: { kind: "tenants", tenantIds: [tenantId] },
|
|
113
|
+
pluginIds,
|
|
114
|
+
requestedAt: now().toISOString(),
|
|
115
|
+
reason
|
|
116
|
+
});
|
|
117
|
+
await options.store.saveMigrationPlan(plan);
|
|
118
|
+
await options.audit({ action: "placement:plan", actorId: authorized.principal.userId, tenantId, sourceBackendId: plan.request.source.id, targetBackendId: plan.request.target.id, migrationId: plan.id, outcome: "allowed", occurredAt: now().toISOString() });
|
|
119
|
+
return c.json({ plan }, 201);
|
|
120
|
+
} catch (error) {
|
|
121
|
+
return failure(error);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
app.post("/tenants/:tenantId/placement/execute", async (c) => {
|
|
125
|
+
const tenantId = string(c.req.param("tenantId"), "tenant id");
|
|
126
|
+
const authorized = await access(c.req.raw, "placement:cutover", tenantId);
|
|
127
|
+
if (authorized instanceof Response) return authorized;
|
|
128
|
+
if (!options.placementExecutor) return failure(new Error("Placement execution is not configured"), 501);
|
|
129
|
+
let migrationId = "";
|
|
130
|
+
let executionId = "";
|
|
131
|
+
try {
|
|
132
|
+
const input = await body(c);
|
|
133
|
+
migrationId = string(input.migrationId, "migration id");
|
|
134
|
+
executionId = string(input.executionId, "execution id");
|
|
135
|
+
const plan = await options.store.getMigrationPlan(migrationId);
|
|
136
|
+
if (!plan) return failure(new Error("Migration plan not found"), 404);
|
|
137
|
+
if (plan.request.scope.kind !== "tenants" || !plan.request.scope.tenantIds.includes(tenantId)) return failure(new Error("Migration plan tenant mismatch"), 409);
|
|
138
|
+
const previous = await options.store.getMigrationStatus(migrationId);
|
|
139
|
+
const current = await options.store.getTenantPlacement(tenantId);
|
|
140
|
+
if (previous?.status === "cutover") return c.json({ status: previous.status, cutover: previous.cutover, placement: current ? { ...current, backend: publicBackend(current.backend) } : null });
|
|
141
|
+
if (!current || current.backend.id !== plan.request.source.id || current.backend.databaseId !== plan.request.source.databaseId) return failure(new Error("Migration plan is stale"), 409);
|
|
142
|
+
const previousStatus = previous?.status;
|
|
143
|
+
const previousExecutionId = previous?.executionId;
|
|
144
|
+
const record = await options.store.beginMigrationExecution({ tenantId, migrationId, executionId });
|
|
145
|
+
if (record.status === "cutover") return c.json({ status: record.status, cutover: record.cutover, placement: { ...current, backend: publicBackend(current.backend) } });
|
|
146
|
+
if (previousStatus === "running" && previousExecutionId === executionId) return c.json({ status: "running", migrationId }, 202);
|
|
147
|
+
if (record.status === "running") {
|
|
148
|
+
const result = await options.placementExecutor.execute(plan);
|
|
149
|
+
const cutover2 = assertBackendMigrationCutover(plan, result.verification, result.cutover);
|
|
150
|
+
await options.store.recordMigrationVerification({ tenantId, plan, executionId, verification: result.verification, cutover: cutover2 });
|
|
151
|
+
} else if (record.status !== "verified" || !record.cutover) {
|
|
152
|
+
return failure(new Error("Migration is not executable"), 409);
|
|
153
|
+
}
|
|
154
|
+
const verified = await options.store.getMigrationStatus(migrationId);
|
|
155
|
+
if (!verified?.cutover) return failure(new Error("Migration verification is missing"), 409);
|
|
156
|
+
const cutover = verified.cutover;
|
|
157
|
+
const placement = await options.store.recordTenantPlacement({ tenantId, plan, cutover });
|
|
158
|
+
await options.audit({ action: "placement:cutover", actorId: authorized.principal.userId, tenantId, sourceBackendId: plan.request.source.id, targetBackendId: plan.request.target.id, migrationId: plan.id, outcome: "allowed", occurredAt: now().toISOString() });
|
|
159
|
+
return c.json({ cutover, placement: { ...placement, backend: publicBackend(placement.backend) } });
|
|
160
|
+
} catch (error) {
|
|
161
|
+
if (migrationId) await options.store.markMigrationFailure({ migrationId, executionId: executionId || void 0, status: "reconciling", message: error instanceof Error ? error.message : "Migration execution failed" }).catch(() => void 0);
|
|
162
|
+
return failure(error, 409);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
app.get("/tenants/:tenantId/placement/migrations/:migrationId", async (c) => {
|
|
166
|
+
const tenantId = string(c.req.param("tenantId"), "tenant id");
|
|
167
|
+
const migrationId = string(c.req.param("migrationId"), "migration id");
|
|
168
|
+
const authorized = await access(c.req.raw, "placement:read", tenantId);
|
|
169
|
+
if (authorized instanceof Response) return authorized;
|
|
170
|
+
const plan = await options.store.getMigrationPlan(migrationId);
|
|
171
|
+
const migration = await options.store.getMigrationStatus(migrationId);
|
|
172
|
+
if (!plan || !migration) return failure(new Error("Migration not found"), 404);
|
|
173
|
+
if (plan.request.scope.kind !== "tenants" || !plan.request.scope.tenantIds.includes(tenantId)) return failure(new Error("Migration plan tenant mismatch"), 409);
|
|
174
|
+
return c.json({ migration: { ...migration, plan } });
|
|
175
|
+
});
|
|
176
|
+
app.post("/tenants/:tenantId/placement/rollback", async (c) => {
|
|
177
|
+
const tenantId = string(c.req.param("tenantId"), "tenant id");
|
|
178
|
+
const authorized = await access(c.req.raw, "placement:rollback", tenantId);
|
|
179
|
+
if (authorized instanceof Response) return authorized;
|
|
180
|
+
try {
|
|
181
|
+
const input = await body(c);
|
|
182
|
+
const migrationId = string(input.migrationId, "migration id");
|
|
183
|
+
const reason = string(input.reason, "rollback reason", 1024);
|
|
184
|
+
const plan = await options.store.createRollbackPlan({ tenantId, migrationId, reason, requestedAt: now().toISOString() });
|
|
185
|
+
await options.audit({ action: "placement:rollback", actorId: authorized.principal.userId, tenantId, sourceBackendId: plan.request.source.id, targetBackendId: plan.request.target.id, migrationId: plan.id, outcome: "allowed", occurredAt: now().toISOString() });
|
|
186
|
+
return c.json({ plan }, 201);
|
|
187
|
+
} catch (error) {
|
|
188
|
+
return failure(error, 409);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
app.post("/tenants/:tenantId/placement/reconcile", async (c) => {
|
|
192
|
+
const tenantId = string(c.req.param("tenantId"), "tenant id");
|
|
193
|
+
const authorized = await access(c.req.raw, "placement:reconcile", tenantId);
|
|
194
|
+
if (authorized instanceof Response) return authorized;
|
|
195
|
+
try {
|
|
196
|
+
const input = await body(c);
|
|
197
|
+
const migrationId = string(input.migrationId, "migration id");
|
|
198
|
+
const action = string(input.action, "reconciliation action");
|
|
199
|
+
const note = string(input.note, "reconciliation note", 2048);
|
|
200
|
+
const plan = await options.store.getMigrationPlan(migrationId);
|
|
201
|
+
if (!plan || plan.request.scope.kind !== "tenants" || !plan.request.scope.tenantIds.includes(tenantId)) return failure(new Error("Migration plan not found"), 404);
|
|
202
|
+
if (action === "commit-verified") {
|
|
203
|
+
const migration2 = await options.store.getMigrationStatus(migrationId);
|
|
204
|
+
if (!migration2?.verification || !migration2.cutover) return failure(new Error("Verified migration data is missing"), 409);
|
|
205
|
+
const placement = await options.store.recordTenantPlacement({ tenantId, plan, cutover: migration2.cutover });
|
|
206
|
+
await options.audit({ action: "placement:reconcile", actorId: authorized.principal.userId, tenantId, sourceBackendId: plan.request.source.id, targetBackendId: plan.request.target.id, migrationId: plan.id, outcome: "allowed", occurredAt: now().toISOString() });
|
|
207
|
+
return c.json({ migration: await options.store.getMigrationStatus(migrationId), placement: { ...placement, backend: publicBackend(placement.backend) } });
|
|
208
|
+
}
|
|
209
|
+
const migration = await options.store.reconcileMigration({ migrationId, action, note });
|
|
210
|
+
await options.audit({ action: "placement:reconcile", actorId: authorized.principal.userId, tenantId, sourceBackendId: plan.request.source.id, targetBackendId: plan.request.target.id, migrationId: plan.id, outcome: "allowed", occurredAt: now().toISOString() });
|
|
211
|
+
return c.json({ migration });
|
|
212
|
+
} catch (error) {
|
|
213
|
+
return failure(error, 409);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
return app;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export {
|
|
220
|
+
createPlatformAdminRouter
|
|
221
|
+
};
|
|
222
|
+
//# sourceMappingURL=chunk-753HWDSC.js.map
|