create-windy 0.2.19 → 0.2.21
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 +5 -1
- package/dist/cli.js +392 -160
- package/package.json +1 -1
- package/template/.windy-template.json +2 -2
- package/template/README.md +1 -0
- package/template/apps/agent-server/Dockerfile +20 -0
- package/template/apps/agent-server/README.md +46 -0
- package/template/apps/agent-server/pyproject.toml +44 -0
- package/template/apps/agent-server/src/southwind_agent_server/__init__.py +5 -0
- package/template/apps/agent-server/src/southwind_agent_server/adk_adapter.py +39 -0
- package/template/apps/agent-server/src/southwind_agent_server/app.py +263 -0
- package/template/apps/agent-server/src/southwind_agent_server/config.py +141 -0
- package/template/apps/agent-server/src/southwind_agent_server/contracts.py +99 -0
- package/template/apps/agent-server/src/southwind_agent_server/deterministic.py +52 -0
- package/template/apps/agent-server/src/southwind_agent_server/engine.py +85 -0
- package/template/apps/agent-server/src/southwind_agent_server/openai_engine.py +197 -0
- package/template/apps/agent-server/src/southwind_agent_server/openai_provider.py +246 -0
- package/template/apps/agent-server/src/southwind_agent_server/service.py +180 -0
- package/template/apps/agent-server/src/southwind_agent_server/sqlite_store.py +317 -0
- package/template/apps/agent-server/src/southwind_agent_server/sse.py +41 -0
- package/template/apps/agent-server/src/southwind_agent_server/store.py +144 -0
- package/template/apps/agent-server/src/southwind_agent_server/tool_host.py +80 -0
- package/template/apps/agent-server/tests/test_api.py +207 -0
- package/template/apps/agent-server/tests/test_config.py +56 -0
- package/template/apps/agent-server/tests/test_openai_provider.py +224 -0
- package/template/apps/agent-server/tests/test_sqlite_store.py +93 -0
- package/template/apps/agent-server/uv.lock +925 -0
- package/template/apps/server/src/agent/execution-grants.ts +89 -0
- package/template/apps/server/src/agent/remote-runtime.ts +128 -0
- package/template/apps/server/src/agent/run-contracts.ts +43 -0
- package/template/apps/server/src/agent/run-facade.test.ts +257 -0
- package/template/apps/server/src/agent/run-facade.ts +190 -0
- package/template/apps/server/src/agent/run-routes.ts +222 -0
- package/template/apps/server/src/agent/runtime-bootstrap.ts +53 -0
- package/template/apps/server/src/agent/tool-host.test.ts +242 -0
- package/template/apps/server/src/agent/tool-host.ts +153 -0
- package/template/apps/server/src/application-services.ts +2 -2
- package/template/apps/server/src/audit/search-summary.ts +15 -8
- package/template/apps/server/src/example-modules.ts +58 -70
- package/template/apps/server/src/foundation.ts +8 -4
- package/template/apps/server/src/guards.test.ts +13 -0
- package/template/apps/server/src/guards.ts +12 -2
- package/template/apps/server/src/index.ts +48 -95
- package/template/apps/server/src/installed-business-modules.ts +23 -4
- package/template/apps/server/src/module-bootstrap.ts +83 -0
- package/template/apps/server/src/module-composition.test.ts +54 -1
- package/template/apps/server/src/module-composition.ts +58 -0
- package/template/apps/server/src/module-host/initialize-contracts.ts +67 -0
- package/template/apps/server/src/module-host/initialize.test.ts +192 -0
- package/template/apps/server/src/module-host/initialize.ts +328 -0
- package/template/apps/server/src/module-host/request-context.test.ts +66 -0
- package/template/apps/server/src/module-host/request-context.ts +156 -0
- package/template/apps/server/src/module-host/role-presets.test.ts +94 -0
- package/template/apps/server/src/module-host/role-presets.ts +76 -0
- package/template/apps/server/src/module-host/route-installer.test.ts +317 -0
- package/template/apps/server/src/module-host/route-installer.ts +97 -0
- package/template/apps/server/src/module-host/route-registration.test.ts +160 -0
- package/template/apps/server/src/module-host/search-providers.ts +31 -0
- package/template/apps/server/src/module-host/storage-port.test.ts +165 -0
- package/template/apps/server/src/module-host/storage-port.ts +59 -0
- package/template/apps/server/src/module-host/task-definitions.ts +41 -0
- package/template/apps/server/src/module-host/test-fixtures.ts +26 -0
- package/template/apps/server/src/module-host/tool-handlers.ts +25 -0
- package/template/apps/server/src/module-host.test.ts +202 -58
- package/template/apps/server/src/module-host.ts +35 -113
- package/template/apps/server/src/module-runtime-validation.ts +40 -0
- package/template/apps/server/src/route-guards.test.ts +112 -1
- package/template/apps/server/src/runtime-feature.ts +66 -31
- package/template/apps/server/src/runtime.test.ts +1 -0
- package/template/apps/server/src/runtime.ts +3 -1
- package/template/apps/server/src/system/built-in-roles.ts +1 -1
- package/template/apps/server/src/work-order/foundation-modules.test.ts +30 -10
- package/template/apps/server/src/work-order/routes.test.ts +30 -18
- package/template/apps/server/src/work-order/routes.ts +104 -135
- package/template/apps/server/src/work-order/search-api.test.ts +14 -3
- package/template/apps/server/src/work-order/search-provider.test.ts +23 -15
- package/template/apps/server/src/work-order/search-provider.ts +17 -12
- package/template/apps/server/src/work-order/task.test.ts +16 -11
- package/template/apps/web/Dockerfile +4 -1
- package/template/apps/web/src/layout/GlobalWatermark.layering.webtest.ts +4 -1
- package/template/apps/web/src/layout/GlobalWatermark.vue +2 -0
- package/template/apps/web/src/layout/GlobalWatermark.webtest.ts +4 -1
- package/template/docker-compose.yml +25 -0
- package/template/docs/architecture/ai-runtime.md +744 -0
- package/template/docs/architecture/object-storage.md +12 -0
- package/template/docs/platform/agent-runtime.md +128 -0
- package/template/docs/platform/agent-tools.md +8 -1
- package/template/package.json +1 -0
- package/template/packages/config/index.test.ts +100 -0
- package/template/packages/config/index.ts +1 -0
- package/template/packages/config/package.json +2 -1
- package/template/packages/config/src/ai-openai-compatible.ts +131 -0
- package/template/packages/config/src/platform.ts +28 -1
- package/template/packages/database/package.json +1 -1
- package/template/packages/database/src/runner.ts +7 -9
- package/template/packages/example-work-order/index.ts +1 -0
- package/template/packages/example-work-order/package.json +2 -0
- package/template/packages/example-work-order/src/server-module.ts +61 -0
- package/template/packages/jobs/package.json +1 -1
- package/template/packages/jobs/src/types.ts +7 -1
- package/template/packages/modules/package.json +1 -1
- package/template/packages/modules/src/catalog-validation.test.ts +212 -0
- package/template/packages/modules/src/catalog-validation.ts +19 -2
- package/template/packages/modules/src/migration-bundle-validation.test.ts +191 -0
- package/template/packages/server-sdk/index.ts +53 -0
- package/template/packages/server-sdk/package.json +18 -3
- package/template/packages/server-sdk/src/actor.ts +15 -0
- package/template/packages/server-sdk/src/ai-operation-registration.ts +31 -0
- package/template/packages/server-sdk/src/audit-port.ts +22 -0
- package/template/packages/server-sdk/src/jobs-port.ts +24 -0
- package/template/packages/server-sdk/src/module-host.ts +41 -1
- package/template/packages/server-sdk/src/namespace.test.ts +26 -0
- package/template/packages/server-sdk/src/namespace.ts +13 -0
- package/template/packages/server-sdk/src/request-context.ts +21 -0
- package/template/packages/server-sdk/src/role-preset.ts +18 -0
- package/template/packages/server-sdk/src/route-definition.ts +26 -0
- package/template/packages/server-sdk/src/search-provider-port.ts +48 -0
- package/template/packages/server-sdk/src/storage-port.ts +25 -0
- package/template/packages/server-sdk/src/task-registration.ts +18 -0
- package/template/packages/server-sdk/src/tool-host-port.ts +22 -0
- package/template/packages/server-sdk/src/tool-registration.ts +29 -0
- package/template/packages/shared/index.ts +1 -0
- package/template/packages/shared/package.json +1 -1
- package/template/packages/shared/src/license-catalog.test.ts +73 -1
- package/template/packages/shared/src/license-catalog.ts +95 -0
- package/template/packages/{database/src/bundle-validation.ts → shared/src/migration-bundle-validation.ts} +2 -1
- package/template/apps/server/src/work-order/task.ts +0 -30
|
@@ -2,13 +2,26 @@ import type { AuditEvent } from "@southwind-ai/shared";
|
|
|
2
2
|
import { randomUUIDv7 } from "bun";
|
|
3
3
|
import type { RequestGuardContext } from "../guards.js";
|
|
4
4
|
|
|
5
|
+
export function searchAuditMetadata(
|
|
6
|
+
query: string,
|
|
7
|
+
matched: number,
|
|
8
|
+
): Record<string, unknown> {
|
|
9
|
+
const normalized = query.trim();
|
|
10
|
+
return {
|
|
11
|
+
queryDigest: new Bun.CryptoHasher("sha256")
|
|
12
|
+
.update(normalized)
|
|
13
|
+
.digest("hex"),
|
|
14
|
+
queryLength: normalized.length,
|
|
15
|
+
matched,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
5
19
|
export function searchAuditEvent(
|
|
6
20
|
context: RequestGuardContext,
|
|
7
21
|
resourceName: string,
|
|
8
22
|
query: string,
|
|
9
23
|
matched: number,
|
|
10
24
|
): AuditEvent {
|
|
11
|
-
const normalized = query.trim();
|
|
12
25
|
return {
|
|
13
26
|
id: randomUUIDv7(),
|
|
14
27
|
action: "data.search",
|
|
@@ -20,13 +33,7 @@ export function searchAuditEvent(
|
|
|
20
33
|
},
|
|
21
34
|
target: { type: resourceName },
|
|
22
35
|
requestId: context.requestId,
|
|
23
|
-
metadata:
|
|
24
|
-
queryDigest: new Bun.CryptoHasher("sha256")
|
|
25
|
-
.update(normalized)
|
|
26
|
-
.digest("hex"),
|
|
27
|
-
queryLength: normalized.length,
|
|
28
|
-
matched,
|
|
29
|
-
},
|
|
36
|
+
metadata: searchAuditMetadata(query, matched),
|
|
30
37
|
occurredAt: new Date().toISOString(),
|
|
31
38
|
};
|
|
32
39
|
}
|
|
@@ -1,86 +1,74 @@
|
|
|
1
|
-
|
|
1
|
+
// @windy-module work-order begin
|
|
2
|
+
import {
|
|
3
|
+
createWorkOrderServerModule,
|
|
4
|
+
type WorkOrder,
|
|
5
|
+
} from "@southwind-ai/example-work-order";
|
|
6
|
+
import type { ModuleManifest } from "@southwind-ai/modules";
|
|
7
|
+
import type {
|
|
8
|
+
InstallableServerModule,
|
|
9
|
+
ModuleInitializer,
|
|
10
|
+
} from "@southwind-ai/server-sdk";
|
|
2
11
|
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
|
|
3
|
-
import
|
|
4
|
-
import type {
|
|
5
|
-
import type { SearchProvider } from "./search/contracts.js";
|
|
12
|
+
import { platformDataActor } from "./data-access/platform-actor.js";
|
|
13
|
+
import type { ScopedEntityRepository } from "./data-access/scoped-repository.js";
|
|
6
14
|
import type { ManagedDepartment } from "./system/entities.js";
|
|
7
15
|
import type { EntityRepository } from "./system/repository.js";
|
|
8
|
-
import type { RouteApp } from "./system/route-types.js";
|
|
9
|
-
// @windy-module work-order begin
|
|
10
|
-
import type { ModuleInitializer } from "@southwind-ai/server-sdk";
|
|
11
16
|
import { createWorkOrderRepository } from "./work-order/repository.js";
|
|
12
17
|
import { createDrizzleWorkOrderRepository } from "./work-order/drizzle-repository.js";
|
|
13
|
-
import {
|
|
14
|
-
import { WorkOrderService } from "./work-order/service.js";
|
|
18
|
+
import { createWorkOrderRouteDefinitions } from "./work-order/routes.js";
|
|
15
19
|
import { WorkOrderSearchProvider } from "./work-order/search-provider.js";
|
|
16
|
-
import {
|
|
17
|
-
// @windy-module work-order end
|
|
18
|
-
|
|
19
|
-
// @windy-module work-order begin
|
|
20
|
-
export const workOrderModuleInitializer: ModuleInitializer = {
|
|
21
|
-
moduleName: "work-order",
|
|
22
|
-
initialize(host) {
|
|
23
|
-
host.registerUploadPolicy({
|
|
24
|
-
purpose: "work-order.ticket.attachment",
|
|
25
|
-
maxByteSize: 20 * 1024 * 1024,
|
|
26
|
-
maxPartByteSize: 4 * 1024 * 1024,
|
|
27
|
-
sessionTtlMs: 2 * 60 * 60_000,
|
|
28
|
-
allowedTypes: {
|
|
29
|
-
"application/pdf": ["pdf"],
|
|
30
|
-
"image/png": ["png"],
|
|
31
|
-
"image/jpeg": ["jpg", "jpeg"],
|
|
32
|
-
"text/plain": ["txt"],
|
|
33
|
-
},
|
|
34
|
-
signature: "none",
|
|
35
|
-
});
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
// @windy-module work-order end
|
|
20
|
+
import { WorkOrderService } from "./work-order/service.js";
|
|
39
21
|
|
|
40
|
-
export interface
|
|
41
|
-
features: FeatureFlagDefinition[];
|
|
22
|
+
export interface WorkOrderModuleDependencies {
|
|
42
23
|
departments: EntityRepository<ManagedDepartment>;
|
|
43
24
|
db?: NodePgDatabase;
|
|
25
|
+
/** 测试可注入预置数据的仓储;默认按 db 选择 Drizzle 或内存实现。 */
|
|
26
|
+
repository?: ScopedEntityRepository<WorkOrder>;
|
|
44
27
|
}
|
|
45
28
|
|
|
46
|
-
export interface
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
29
|
+
export interface WorkOrderModule {
|
|
30
|
+
readonly manifest: ModuleManifest;
|
|
31
|
+
setup: InstallableServerModule<ModuleManifest>["setup"];
|
|
32
|
+
/** @deprecated 测试兼容入口;生产装配使用 manifest + setup。 */
|
|
33
|
+
readonly initializer: ModuleInitializer;
|
|
34
|
+
/** 宿主运行时就绪后挂载模块服务;路由与任务 Handler 延迟解析它。 */
|
|
35
|
+
attach(dependencies: WorkOrderModuleDependencies): void;
|
|
50
36
|
}
|
|
51
37
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
38
|
+
/**
|
|
39
|
+
* 示例工单模块:以 initializer + Host 声明式装配的样板。
|
|
40
|
+
* Manifest 声明 Route/Task/Provider,初始化器注册实现与受限 Port 定义,
|
|
41
|
+
* 不再由宿主手工逐项接线。
|
|
42
|
+
*/
|
|
43
|
+
export function createWorkOrderModule(): WorkOrderModule {
|
|
44
|
+
let service: WorkOrderService | undefined;
|
|
45
|
+
const requireService = () => {
|
|
46
|
+
if (!service) throw new Error("示例工单模块尚未挂载");
|
|
47
|
+
return service;
|
|
48
|
+
};
|
|
49
|
+
const serverModule = createWorkOrderServerModule({
|
|
50
|
+
routes: createWorkOrderRouteDefinitions(requireService),
|
|
51
|
+
snapshot: () =>
|
|
52
|
+
requireService().operationalSnapshot(
|
|
53
|
+
platformDataActor("task_work_order_snapshot", "工单运营快照任务"),
|
|
54
|
+
),
|
|
55
|
+
searchProvider: new WorkOrderSearchProvider(requireService),
|
|
56
|
+
});
|
|
64
57
|
return {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
58
|
+
...serverModule,
|
|
59
|
+
initializer: {
|
|
60
|
+
moduleName: serverModule.manifest.name,
|
|
61
|
+
initialize: serverModule.setup,
|
|
62
|
+
},
|
|
63
|
+
attach(dependencies) {
|
|
64
|
+
service = new WorkOrderService(
|
|
65
|
+
dependencies.repository ??
|
|
66
|
+
(dependencies.db
|
|
67
|
+
? createDrizzleWorkOrderRepository(dependencies.db)
|
|
68
|
+
: createWorkOrderRepository()),
|
|
69
|
+
dependencies.departments,
|
|
70
|
+
);
|
|
71
|
+
},
|
|
68
72
|
};
|
|
69
73
|
}
|
|
70
|
-
|
|
71
|
-
export interface ExampleModuleRouteDependencies {
|
|
72
|
-
app: RouteApp;
|
|
73
|
-
runtime: ReturnType<typeof createServerRuntime>;
|
|
74
|
-
moduleRuntime?: ExampleModuleRuntime;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export function registerExampleModuleRoutes(
|
|
78
|
-
dependencies: ExampleModuleRouteDependencies,
|
|
79
|
-
): void {
|
|
80
|
-
if (!dependencies.moduleRuntime) return;
|
|
81
|
-
registerWorkOrderRoutes(
|
|
82
|
-
dependencies.app,
|
|
83
|
-
dependencies.moduleRuntime.service,
|
|
84
|
-
dependencies.runtime,
|
|
85
|
-
);
|
|
86
|
-
}
|
|
74
|
+
// @windy-module work-order end
|
|
@@ -13,7 +13,8 @@ import type {
|
|
|
13
13
|
MenuNode,
|
|
14
14
|
PermissionDefinition,
|
|
15
15
|
} from "@southwind-ai/shared";
|
|
16
|
-
import {
|
|
16
|
+
import { resolveLicenseCatalog } from "@southwind-ai/shared";
|
|
17
|
+
import { installedBusinessModules } from "./installed-business-modules.js";
|
|
17
18
|
|
|
18
19
|
export interface FoundationSnapshot {
|
|
19
20
|
platform: {
|
|
@@ -38,8 +39,8 @@ export interface FoundationSnapshot {
|
|
|
38
39
|
export function loadFoundationModules(): ModuleManifest[] {
|
|
39
40
|
const registry = createModuleRegistry();
|
|
40
41
|
for (const factory of systemModuleFactories) registry.register(factory);
|
|
41
|
-
for (const
|
|
42
|
-
registry.register(
|
|
42
|
+
for (const module of installedBusinessModules) {
|
|
43
|
+
registry.register(() => module.manifest);
|
|
43
44
|
}
|
|
44
45
|
return registry.list();
|
|
45
46
|
}
|
|
@@ -72,7 +73,10 @@ export function createFoundationSnapshot(
|
|
|
72
73
|
config: PlatformConfig = loadPlatformConfig(),
|
|
73
74
|
): FoundationSnapshot {
|
|
74
75
|
const modules = loadFoundationModules();
|
|
75
|
-
const catalogs = validateCapabilityCatalogs(
|
|
76
|
+
const catalogs = validateCapabilityCatalogs(
|
|
77
|
+
modules,
|
|
78
|
+
resolveLicenseCatalog(config.license.versions),
|
|
79
|
+
);
|
|
76
80
|
|
|
77
81
|
return {
|
|
78
82
|
platform: {
|
|
@@ -71,4 +71,17 @@ describe("guards", () => {
|
|
|
71
71
|
}).reason,
|
|
72
72
|
).toBe("entitlement-not-granted");
|
|
73
73
|
});
|
|
74
|
+
|
|
75
|
+
test("运行时解析出依赖缺失时拒绝并记录 security.denied", () => {
|
|
76
|
+
const denied = evaluateFeatureGuard(context, {
|
|
77
|
+
...feature,
|
|
78
|
+
enabled: false,
|
|
79
|
+
disabledReason: "dependency-missing",
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
expect(denied.allowed).toBe(false);
|
|
83
|
+
expect(denied.reason).toBe("dependency-missing");
|
|
84
|
+
expect(denied.auditEvent?.action).toBe("security.denied");
|
|
85
|
+
expect(denied.auditEvent?.target?.id).toBe(feature.key);
|
|
86
|
+
});
|
|
74
87
|
});
|
|
@@ -3,6 +3,7 @@ import type {
|
|
|
3
3
|
AuditEvent,
|
|
4
4
|
EntitlementKey,
|
|
5
5
|
FeatureFlagDefinition,
|
|
6
|
+
FeatureFlagState,
|
|
6
7
|
LicenseVersionKey,
|
|
7
8
|
} from "@southwind-ai/shared";
|
|
8
9
|
import { correlationId, isLicenseVersionAllowed } from "@southwind-ai/shared";
|
|
@@ -47,6 +48,7 @@ export type GuardDecisionReason =
|
|
|
47
48
|
| "missing-permission"
|
|
48
49
|
| "role-not-allowed"
|
|
49
50
|
| "feature-disabled"
|
|
51
|
+
| "dependency-missing"
|
|
50
52
|
| "license-version-not-allowed"
|
|
51
53
|
| "entitlement-not-granted"
|
|
52
54
|
| "license-restricted";
|
|
@@ -120,13 +122,21 @@ export function evaluateRoleGuard(
|
|
|
120
122
|
|
|
121
123
|
export function evaluateFeatureGuard(
|
|
122
124
|
context: RequestGuardContext,
|
|
123
|
-
feature: FeatureFlagDefinition
|
|
125
|
+
feature: FeatureFlagDefinition & {
|
|
126
|
+
disabledReason?: FeatureFlagState["reason"];
|
|
127
|
+
},
|
|
124
128
|
): GuardDecision {
|
|
125
129
|
if (feature.enabled && feature.visible === "visible") {
|
|
126
130
|
return { allowed: true, reason: "allowed" };
|
|
127
131
|
}
|
|
128
132
|
|
|
129
|
-
return deniedDecision(
|
|
133
|
+
return deniedDecision(
|
|
134
|
+
context,
|
|
135
|
+
feature.disabledReason === "dependency-missing"
|
|
136
|
+
? "dependency-missing"
|
|
137
|
+
: "feature-disabled",
|
|
138
|
+
feature.key,
|
|
139
|
+
);
|
|
130
140
|
}
|
|
131
141
|
|
|
132
142
|
export function evaluateEntitlementGuard(
|
|
@@ -2,10 +2,6 @@ import { loadPlatformConfig } from "@southwind-ai/config";
|
|
|
2
2
|
import pino from "pino";
|
|
3
3
|
import { registerAdminBootstrapRoute } from "./admin/routes.js";
|
|
4
4
|
import { registerSessionContextRoute } from "./session/routes.js";
|
|
5
|
-
import {
|
|
6
|
-
createFoundationSnapshot,
|
|
7
|
-
loadFoundationModules,
|
|
8
|
-
} from "./foundation.js";
|
|
9
5
|
import { registerFoundationRoute } from "./foundation-route.js";
|
|
10
6
|
// @windy-module system.scheduler begin
|
|
11
7
|
import { createApplicationServices } from "./application-services.js";
|
|
@@ -25,6 +21,7 @@ import {
|
|
|
25
21
|
createSystemToolHandlers,
|
|
26
22
|
registerAgentRoutes,
|
|
27
23
|
} from "./agent/routes.js";
|
|
24
|
+
import { registerAgentPlatformRuntime } from "./agent/runtime-bootstrap.js";
|
|
28
25
|
// @windy-module system.agent end
|
|
29
26
|
import { registerAuthRoutes, registerAuthSessionRoute } from "./auth/routes.js";
|
|
30
27
|
import { createAuthRuntime } from "./auth/runtime.js";
|
|
@@ -44,10 +41,6 @@ import { registerSystemOperationRoutes } from "./system/operations.js";
|
|
|
44
41
|
import { createPostgresMonitorProbe } from "./system/postgres-monitoring.js";
|
|
45
42
|
// @windy-module system.operations end
|
|
46
43
|
import { registerSystemRoutes } from "./system/routes.js";
|
|
47
|
-
import {
|
|
48
|
-
createSystemRepositories,
|
|
49
|
-
synchronizeBuiltInRoles,
|
|
50
|
-
} from "./system/seed.js";
|
|
51
44
|
// @windy-module system.scheduler begin
|
|
52
45
|
import { registerSchedulerRoutes } from "./scheduler/routes.js";
|
|
53
46
|
import { SchedulerWorker } from "./scheduler/worker.js";
|
|
@@ -59,25 +52,17 @@ import { registerProfileRoutes } from "./profile/routes.js";
|
|
|
59
52
|
// @windy-module system.notification begin
|
|
60
53
|
import { registerNotificationRoutes } from "./notification/routes.js";
|
|
61
54
|
// @windy-module system.notification end
|
|
62
|
-
// @windy-module work-order begin
|
|
63
|
-
import {
|
|
64
|
-
createExampleModuleRuntime,
|
|
65
|
-
registerExampleModuleRoutes,
|
|
66
|
-
workOrderModuleInitializer,
|
|
67
|
-
} from "./example-modules.js";
|
|
68
|
-
// @windy-module work-order end
|
|
69
|
-
// @windy-module system.configuration begin
|
|
70
|
-
import { bootstrapModuleConfiguration } from "./configuration/bootstrap.js";
|
|
71
|
-
// @windy-module system.configuration end
|
|
72
55
|
// @windy-module system.storage begin
|
|
73
|
-
import {
|
|
74
|
-
createStorageRuntime,
|
|
75
|
-
platformUploadPolicies,
|
|
76
|
-
} from "./storage/runtime.js";
|
|
56
|
+
import { createStorageRuntime } from "./storage/runtime.js";
|
|
77
57
|
import { registerStorageRoutes } from "./storage/routes.js";
|
|
78
58
|
// @windy-module system.storage end
|
|
79
|
-
import {
|
|
80
|
-
import {
|
|
59
|
+
import { validateInstalledRuntime } from "./module-runtime-validation.js";
|
|
60
|
+
import {
|
|
61
|
+
adaptModuleSearchProviders,
|
|
62
|
+
createModuleTaskDefinitions,
|
|
63
|
+
createModuleToolHandlerMap,
|
|
64
|
+
installModuleRoutes,
|
|
65
|
+
} from "./module-host.js";
|
|
81
66
|
// @windy-module system.search begin
|
|
82
67
|
import { createSearchHost } from "./search/host.js";
|
|
83
68
|
// @windy-module system.search end
|
|
@@ -88,6 +73,7 @@ import {
|
|
|
88
73
|
createPlatformObservability,
|
|
89
74
|
logPlatformStartup,
|
|
90
75
|
} from "./observability/bootstrap.js";
|
|
76
|
+
import { bootstrapServerModules } from "./module-bootstrap.js";
|
|
91
77
|
|
|
92
78
|
const logger = pino({ name: "windy-server" });
|
|
93
79
|
const platformConfig = loadPlatformConfig();
|
|
@@ -101,45 +87,16 @@ const persistence = createServerPersistence(
|
|
|
101
87
|
// @windy-module system.audit begin
|
|
102
88
|
await persistence?.auditWriter.recover();
|
|
103
89
|
// @windy-module system.audit end
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const foundationModules = loadFoundationModules();
|
|
115
|
-
const moduleHosts = await initializeModuleHosts({
|
|
116
|
-
modules: foundationModules,
|
|
117
|
-
initializers: [
|
|
118
|
-
// @windy-module work-order begin
|
|
119
|
-
workOrderModuleInitializer,
|
|
120
|
-
// @windy-module work-order end
|
|
121
|
-
],
|
|
122
|
-
baseUploadPolicies: [
|
|
123
|
-
// @windy-module system.storage begin
|
|
124
|
-
...platformUploadPolicies,
|
|
125
|
-
// @windy-module system.storage end
|
|
126
|
-
],
|
|
127
|
-
});
|
|
128
|
-
void moduleHosts;
|
|
129
|
-
const systemRepositories = createSystemRepositories(foundationSnapshot, {
|
|
130
|
-
db: persistence?.db,
|
|
131
|
-
});
|
|
132
|
-
const featureSync = await systemRepositories.features.syncManifest(
|
|
133
|
-
foundationSnapshot.features,
|
|
134
|
-
);
|
|
135
|
-
await systemRepositories.menuRegistry.synchronize({
|
|
136
|
-
id: "system_bootstrap",
|
|
137
|
-
type: "service",
|
|
138
|
-
name: "平台初始化",
|
|
139
|
-
roleCodes: ["system"],
|
|
140
|
-
permissionKeys: ["system.menu.manage"],
|
|
141
|
-
});
|
|
142
|
-
await synchronizeBuiltInRoles(systemRepositories, foundationSnapshot);
|
|
90
|
+
const {
|
|
91
|
+
// @windy-module system.configuration begin
|
|
92
|
+
configurationRuntime,
|
|
93
|
+
// @windy-module system.configuration end
|
|
94
|
+
featureSync,
|
|
95
|
+
foundationModules,
|
|
96
|
+
foundationSnapshot,
|
|
97
|
+
moduleHosts,
|
|
98
|
+
systemRepositories,
|
|
99
|
+
} = await bootstrapServerModules(platformConfig, persistence);
|
|
143
100
|
// @windy-module system.license begin
|
|
144
101
|
const platformLicenseOptions = createPlatformLicenseRuntimeOptions(process.env);
|
|
145
102
|
const platformLicenseRuntime = new PlatformLicenseRuntime(
|
|
@@ -195,33 +152,18 @@ const platformSettings = createPlatformSettingsRuntime(persistence?.db, {
|
|
|
195
152
|
logoUrl: platformConfig.logoUrl,
|
|
196
153
|
});
|
|
197
154
|
// @windy-module system.settings end
|
|
198
|
-
// @windy-module work-order begin
|
|
199
|
-
const exampleModuleRuntime = createExampleModuleRuntime({
|
|
200
|
-
features: foundationSnapshot.features,
|
|
201
|
-
departments: systemRepositories.departments,
|
|
202
|
-
db: persistence?.db,
|
|
203
|
-
});
|
|
204
|
-
// @windy-module work-order end
|
|
205
|
-
// @windy-module system.search begin
|
|
206
|
-
const businessSearchProviders = [
|
|
207
|
-
// @windy-module work-order begin
|
|
208
|
-
...(exampleModuleRuntime?.providers || []),
|
|
209
|
-
// @windy-module work-order end
|
|
210
|
-
];
|
|
211
|
-
// @windy-module system.search end
|
|
212
155
|
// @windy-module system.search begin
|
|
213
156
|
const searchHost = createSearchHost(
|
|
214
157
|
foundationModules,
|
|
215
|
-
{ providers:
|
|
158
|
+
{ providers: adaptModuleSearchProviders(moduleHosts) },
|
|
216
159
|
runtime,
|
|
217
160
|
);
|
|
218
161
|
// @windy-module system.search end
|
|
219
162
|
// @windy-module system.scheduler begin
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
];
|
|
163
|
+
const moduleTaskDefinitions = createModuleTaskDefinitions(
|
|
164
|
+
moduleHosts,
|
|
165
|
+
foundationSnapshot.features,
|
|
166
|
+
);
|
|
225
167
|
const {
|
|
226
168
|
bulkDataService,
|
|
227
169
|
scheduler,
|
|
@@ -229,13 +171,14 @@ const {
|
|
|
229
171
|
notifications: notificationRepository,
|
|
230
172
|
workflow: workflowService,
|
|
231
173
|
governedExportService,
|
|
174
|
+
durable: durableJobRuntime,
|
|
232
175
|
} = await createApplicationServices({
|
|
233
176
|
persistence,
|
|
234
177
|
systemRepositories,
|
|
235
178
|
foundation: foundationSnapshot,
|
|
236
179
|
runtime,
|
|
237
180
|
storage: storageRuntime,
|
|
238
|
-
|
|
181
|
+
moduleTasks: moduleTaskDefinitions,
|
|
239
182
|
bulkRetentionDays: readPositiveInt(process.env.BULK_DATA_RETENTION_DAYS, 7),
|
|
240
183
|
installModuleDurableHandlers: moduleHosts.installDurableHandlers,
|
|
241
184
|
});
|
|
@@ -246,19 +189,15 @@ const schedulerWorker = new SchedulerWorker(
|
|
|
246
189
|
(result) => observability.metrics.observeSchedulerTick(result),
|
|
247
190
|
);
|
|
248
191
|
// @windy-module system.scheduler end
|
|
249
|
-
|
|
250
192
|
await bootstrapAdminPassword({
|
|
251
193
|
authService,
|
|
252
194
|
authRepository: persistence?.authRepository,
|
|
253
195
|
repositories: systemRepositories,
|
|
254
196
|
password: process.env.WINDY_BOOTSTRAP_ADMIN_PASSWORD,
|
|
255
197
|
});
|
|
256
|
-
|
|
257
198
|
const app = createPlatformHttpApp(runtime, observability);
|
|
258
199
|
observability.register(app);
|
|
259
|
-
|
|
260
200
|
registerAuthSessionRoute(app);
|
|
261
|
-
|
|
262
201
|
registerAuthRoutes(app, authService, {
|
|
263
202
|
sessionCookieName: platformConfig.security.sessionCookieName,
|
|
264
203
|
secureCookie: process.env.NODE_ENV === "production",
|
|
@@ -345,8 +284,19 @@ registerSystemOperationRoutes(app, runtime, foundationSnapshot.features, {
|
|
|
345
284
|
});
|
|
346
285
|
// @windy-module system.operations end
|
|
347
286
|
// @windy-module system.agent begin
|
|
348
|
-
const toolHandlers =
|
|
287
|
+
const toolHandlers = new Map([
|
|
288
|
+
...createSystemToolHandlers(systemRepositories, runtime),
|
|
289
|
+
...createModuleToolHandlerMap(moduleHosts),
|
|
290
|
+
]);
|
|
349
291
|
registerAgentRoutes(app, foundationModules, toolHandlers, runtime);
|
|
292
|
+
registerAgentPlatformRuntime({
|
|
293
|
+
app,
|
|
294
|
+
platformConfig,
|
|
295
|
+
modules: foundationModules,
|
|
296
|
+
hosts: moduleHosts,
|
|
297
|
+
runtime,
|
|
298
|
+
toolHandlers,
|
|
299
|
+
});
|
|
350
300
|
// @windy-module system.agent end
|
|
351
301
|
// @windy-module system.scheduler begin
|
|
352
302
|
registerSchedulerRoutes(app, scheduler, runtime, foundationSnapshot.features);
|
|
@@ -360,25 +310,28 @@ registerBulkDataRoutes(
|
|
|
360
310
|
);
|
|
361
311
|
// @windy-module system.bulk-data end
|
|
362
312
|
// @windy-module work-order begin
|
|
363
|
-
|
|
364
|
-
app,
|
|
313
|
+
installModuleRoutes(moduleHosts, app, {
|
|
365
314
|
runtime,
|
|
366
|
-
|
|
315
|
+
features: foundationSnapshot.features,
|
|
316
|
+
jobs: durableJobRuntime.service,
|
|
317
|
+
storage: {
|
|
318
|
+
uploads: storageRuntime.uploads,
|
|
319
|
+
files: storageRuntime.files,
|
|
320
|
+
},
|
|
367
321
|
});
|
|
368
322
|
// @windy-module work-order end
|
|
369
323
|
|
|
370
|
-
|
|
324
|
+
validateInstalledRuntime({
|
|
371
325
|
modules: foundationModules,
|
|
372
326
|
routes: app.routes,
|
|
373
327
|
// @windy-module system.scheduler begin
|
|
374
328
|
tasks: scheduledTaskDefinitions,
|
|
375
329
|
// @windy-module system.scheduler end
|
|
376
|
-
// @windy-module system.agent begin
|
|
377
330
|
tools: toolHandlers,
|
|
378
|
-
// @windy-module system.agent end
|
|
379
331
|
// @windy-module system.search begin
|
|
380
332
|
providers: searchHost.providerKeys,
|
|
381
333
|
// @windy-module system.search end
|
|
334
|
+
hosts: moduleHosts,
|
|
382
335
|
});
|
|
383
336
|
|
|
384
337
|
const port = process.env.PORT ? Number(process.env.PORT) : 9_747;
|
|
@@ -1,10 +1,29 @@
|
|
|
1
1
|
// @windy-module work-order begin
|
|
2
|
-
import {
|
|
2
|
+
import { createWorkOrderModule } from "./example-modules.js";
|
|
3
3
|
// @windy-module work-order end
|
|
4
|
-
import type {
|
|
4
|
+
import type { ModuleManifest } from "@southwind-ai/modules";
|
|
5
|
+
import type { InstallableServerModule } from "@southwind-ai/server-sdk";
|
|
6
|
+
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
|
|
7
|
+
import type { ManagedDepartment } from "./system/entities.js";
|
|
8
|
+
import type { EntityRepository } from "./system/repository.js";
|
|
5
9
|
|
|
6
|
-
export
|
|
10
|
+
export interface BusinessModuleRuntime {
|
|
11
|
+
readonly db?: NodePgDatabase;
|
|
12
|
+
readonly departments: EntityRepository<ManagedDepartment>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface InstalledBusinessModule extends InstallableServerModule<ModuleManifest> {
|
|
16
|
+
attach(runtime: BusinessModuleRuntime): void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const installedBusinessModules: readonly InstalledBusinessModule[] = [
|
|
7
20
|
// @windy-module work-order begin
|
|
8
|
-
|
|
21
|
+
createWorkOrderModule(),
|
|
9
22
|
// @windy-module work-order end
|
|
10
23
|
];
|
|
24
|
+
|
|
25
|
+
export function attachInstalledBusinessModules(
|
|
26
|
+
runtime: BusinessModuleRuntime,
|
|
27
|
+
): void {
|
|
28
|
+
for (const module of installedBusinessModules) module.attach(runtime);
|
|
29
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { PlatformConfig } from "@southwind-ai/config";
|
|
2
|
+
// @windy-module system.configuration begin
|
|
3
|
+
import { bootstrapModuleConfiguration } from "./configuration/bootstrap.js";
|
|
4
|
+
// @windy-module system.configuration end
|
|
5
|
+
import {
|
|
6
|
+
createFoundationSnapshot,
|
|
7
|
+
loadFoundationModules,
|
|
8
|
+
} from "./foundation.js";
|
|
9
|
+
import {
|
|
10
|
+
attachInstalledBusinessModules,
|
|
11
|
+
installedBusinessModules,
|
|
12
|
+
} from "./installed-business-modules.js";
|
|
13
|
+
import {
|
|
14
|
+
initializeModuleHosts,
|
|
15
|
+
synchronizeModuleRolePresets,
|
|
16
|
+
} from "./module-host.js";
|
|
17
|
+
import type { ServerPersistence } from "./persistence.js";
|
|
18
|
+
// @windy-module system.storage begin
|
|
19
|
+
import { platformUploadPolicies } from "./storage/runtime.js";
|
|
20
|
+
// @windy-module system.storage end
|
|
21
|
+
import {
|
|
22
|
+
createSystemRepositories,
|
|
23
|
+
synchronizeBuiltInRoles,
|
|
24
|
+
} from "./system/seed.js";
|
|
25
|
+
|
|
26
|
+
export async function bootstrapServerModules(
|
|
27
|
+
platformConfig: PlatformConfig,
|
|
28
|
+
persistence: ServerPersistence | undefined,
|
|
29
|
+
) {
|
|
30
|
+
// @windy-module system.configuration begin
|
|
31
|
+
const configurationRuntime = await bootstrapModuleConfiguration(
|
|
32
|
+
platformConfig,
|
|
33
|
+
persistence?.configVersionRepository,
|
|
34
|
+
);
|
|
35
|
+
// @windy-module system.configuration end
|
|
36
|
+
const foundationSnapshot = createFoundationSnapshot(platformConfig);
|
|
37
|
+
// @windy-module system.configuration begin
|
|
38
|
+
configurationRuntime.bindFoundation(foundationSnapshot);
|
|
39
|
+
// @windy-module system.configuration end
|
|
40
|
+
const foundationModules = loadFoundationModules();
|
|
41
|
+
const moduleHosts = await initializeModuleHosts({
|
|
42
|
+
modules: foundationModules,
|
|
43
|
+
installations: installedBusinessModules,
|
|
44
|
+
baseUploadPolicies: [
|
|
45
|
+
// @windy-module system.storage begin
|
|
46
|
+
...platformUploadPolicies,
|
|
47
|
+
// @windy-module system.storage end
|
|
48
|
+
],
|
|
49
|
+
});
|
|
50
|
+
const systemRepositories = createSystemRepositories(foundationSnapshot, {
|
|
51
|
+
db: persistence?.db,
|
|
52
|
+
});
|
|
53
|
+
const featureSync = await systemRepositories.features.syncManifest(
|
|
54
|
+
foundationSnapshot.features,
|
|
55
|
+
);
|
|
56
|
+
await systemRepositories.menuRegistry.synchronize({
|
|
57
|
+
id: "system_bootstrap",
|
|
58
|
+
type: "service",
|
|
59
|
+
name: "平台初始化",
|
|
60
|
+
roleCodes: ["system"],
|
|
61
|
+
permissionKeys: ["system.menu.manage"],
|
|
62
|
+
});
|
|
63
|
+
await synchronizeBuiltInRoles(systemRepositories, foundationSnapshot);
|
|
64
|
+
await synchronizeModuleRolePresets(
|
|
65
|
+
systemRepositories,
|
|
66
|
+
foundationSnapshot,
|
|
67
|
+
moduleHosts.rolePresets,
|
|
68
|
+
);
|
|
69
|
+
attachInstalledBusinessModules({
|
|
70
|
+
db: persistence?.db,
|
|
71
|
+
departments: systemRepositories.departments,
|
|
72
|
+
});
|
|
73
|
+
return {
|
|
74
|
+
// @windy-module system.configuration begin
|
|
75
|
+
configurationRuntime,
|
|
76
|
+
// @windy-module system.configuration end
|
|
77
|
+
featureSync,
|
|
78
|
+
foundationModules,
|
|
79
|
+
foundationSnapshot,
|
|
80
|
+
moduleHosts,
|
|
81
|
+
systemRepositories,
|
|
82
|
+
};
|
|
83
|
+
}
|