@wildo-ai/platform-config-lib 1.0.1
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/dist/esm/bootstrap/application-backend-env.contracts.d.ts +2 -0
- package/dist/esm/bootstrap/application-backend-env.contracts.d.ts.map +1 -0
- package/dist/esm/bootstrap/application-backend-env.contracts.js +2 -0
- package/dist/esm/bootstrap/application-backend-env.contracts.js.map +1 -0
- package/dist/esm/bootstrap/bootstrap-planner.d.ts +20 -0
- package/dist/esm/bootstrap/bootstrap-planner.d.ts.map +1 -0
- package/dist/esm/bootstrap/bootstrap-planner.js +26 -0
- package/dist/esm/bootstrap/bootstrap-planner.js.map +1 -0
- package/dist/esm/bootstrap/bootstrap.contracts.d.ts +120 -0
- package/dist/esm/bootstrap/bootstrap.contracts.d.ts.map +1 -0
- package/dist/esm/bootstrap/bootstrap.contracts.js +117 -0
- package/dist/esm/bootstrap/bootstrap.contracts.js.map +1 -0
- package/dist/esm/bootstrap/bootstrap.schemas.d.ts +485 -0
- package/dist/esm/bootstrap/bootstrap.schemas.d.ts.map +1 -0
- package/dist/esm/bootstrap/bootstrap.schemas.js +130 -0
- package/dist/esm/bootstrap/bootstrap.schemas.js.map +1 -0
- package/dist/esm/bootstrap/platform-runtime-env.contracts.d.ts +78 -0
- package/dist/esm/bootstrap/platform-runtime-env.contracts.d.ts.map +1 -0
- package/dist/esm/bootstrap/platform-runtime-env.contracts.js +98 -0
- package/dist/esm/bootstrap/platform-runtime-env.contracts.js.map +1 -0
- package/dist/esm/bootstrap/runtime-topology.contracts.d.ts +17 -0
- package/dist/esm/bootstrap/runtime-topology.contracts.d.ts.map +1 -0
- package/dist/esm/bootstrap/runtime-topology.contracts.js +60 -0
- package/dist/esm/bootstrap/runtime-topology.contracts.js.map +1 -0
- package/dist/esm/credentials/credential-generator.service.d.ts +11 -0
- package/dist/esm/credentials/credential-generator.service.d.ts.map +1 -0
- package/dist/esm/credentials/credential-generator.service.js +31 -0
- package/dist/esm/credentials/credential-generator.service.js.map +1 -0
- package/dist/esm/credentials/credentials-provisioner.service.d.ts +190 -0
- package/dist/esm/credentials/credentials-provisioner.service.d.ts.map +1 -0
- package/dist/esm/credentials/credentials-provisioner.service.js +278 -0
- package/dist/esm/credentials/credentials-provisioner.service.js.map +1 -0
- package/dist/esm/index.d.ts +16 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +16 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/infra-managers/infra-manager.models.d.ts +146 -0
- package/dist/esm/infra-managers/infra-manager.models.d.ts.map +1 -0
- package/dist/esm/infra-managers/infra-manager.models.js +2 -0
- package/dist/esm/infra-managers/infra-manager.models.js.map +1 -0
- package/dist/esm/infra-managers/mongo-atlas-manager.service.d.ts +64 -0
- package/dist/esm/infra-managers/mongo-atlas-manager.service.d.ts.map +1 -0
- package/dist/esm/infra-managers/mongo-atlas-manager.service.js +307 -0
- package/dist/esm/infra-managers/mongo-atlas-manager.service.js.map +1 -0
- package/dist/esm/infra-managers/postgresql-manager.service.d.ts +115 -0
- package/dist/esm/infra-managers/postgresql-manager.service.d.ts.map +1 -0
- package/dist/esm/infra-managers/postgresql-manager.service.js +403 -0
- package/dist/esm/infra-managers/postgresql-manager.service.js.map +1 -0
- package/dist/esm/infra-managers/rabbitmq-manager.service.d.ts +64 -0
- package/dist/esm/infra-managers/rabbitmq-manager.service.d.ts.map +1 -0
- package/dist/esm/infra-managers/rabbitmq-manager.service.js +288 -0
- package/dist/esm/infra-managers/rabbitmq-manager.service.js.map +1 -0
- package/dist/esm/infra-managers/redis-manager.service.d.ts +78 -0
- package/dist/esm/infra-managers/redis-manager.service.d.ts.map +1 -0
- package/dist/esm/infra-managers/redis-manager.service.js +326 -0
- package/dist/esm/infra-managers/redis-manager.service.js.map +1 -0
- package/dist/esm/project-config/define-framework-config.d.ts +36 -0
- package/dist/esm/project-config/define-framework-config.d.ts.map +1 -0
- package/dist/esm/project-config/define-framework-config.js +30 -0
- package/dist/esm/project-config/define-framework-config.js.map +1 -0
- package/dist/esm/project-config/define-infra-config.d.ts +128 -0
- package/dist/esm/project-config/define-infra-config.d.ts.map +1 -0
- package/dist/esm/project-config/define-infra-config.js +87 -0
- package/dist/esm/project-config/define-infra-config.js.map +1 -0
- package/dist/esm/project-config/define-minion-config.d.ts +41 -0
- package/dist/esm/project-config/define-minion-config.d.ts.map +1 -0
- package/dist/esm/project-config/define-minion-config.js +24 -0
- package/dist/esm/project-config/define-minion-config.js.map +1 -0
- package/dist/esm/project-config/define-platform-config.d.ts +65 -0
- package/dist/esm/project-config/define-platform-config.d.ts.map +1 -0
- package/dist/esm/project-config/define-platform-config.js +22 -0
- package/dist/esm/project-config/define-platform-config.js.map +1 -0
- package/dist/esm/project-config/define-platform-env-config.d.ts +41 -0
- package/dist/esm/project-config/define-platform-env-config.d.ts.map +1 -0
- package/dist/esm/project-config/define-platform-env-config.js +45 -0
- package/dist/esm/project-config/define-platform-env-config.js.map +1 -0
- package/dist/esm/project-config/define-project-config.d.ts +38 -0
- package/dist/esm/project-config/define-project-config.d.ts.map +1 -0
- package/dist/esm/project-config/define-project-config.js +57 -0
- package/dist/esm/project-config/define-project-config.js.map +1 -0
- package/dist/esm/project-config/define-saas-config.d.ts +252 -0
- package/dist/esm/project-config/define-saas-config.d.ts.map +1 -0
- package/dist/esm/project-config/define-saas-config.js +137 -0
- package/dist/esm/project-config/define-saas-config.js.map +1 -0
- package/dist/esm/project-config/define-sharing-policy.d.ts +35 -0
- package/dist/esm/project-config/define-sharing-policy.d.ts.map +1 -0
- package/dist/esm/project-config/define-sharing-policy.js +30 -0
- package/dist/esm/project-config/define-sharing-policy.js.map +1 -0
- package/dist/esm/project-config/define-worker-config.d.ts +42 -0
- package/dist/esm/project-config/define-worker-config.d.ts.map +1 -0
- package/dist/esm/project-config/define-worker-config.js +24 -0
- package/dist/esm/project-config/define-worker-config.js.map +1 -0
- package/dist/esm/project-config/index.d.ts +22 -0
- package/dist/esm/project-config/index.d.ts.map +1 -0
- package/dist/esm/project-config/index.js +22 -0
- package/dist/esm/project-config/index.js.map +1 -0
- package/dist/esm/project-config/loader.d.ts +42 -0
- package/dist/esm/project-config/loader.d.ts.map +1 -0
- package/dist/esm/project-config/loader.js +164 -0
- package/dist/esm/project-config/loader.js.map +1 -0
- package/dist/esm/project-config/shared/application-modules.schemas.d.ts +10 -0
- package/dist/esm/project-config/shared/application-modules.schemas.d.ts.map +1 -0
- package/dist/esm/project-config/shared/application-modules.schemas.js +6 -0
- package/dist/esm/project-config/shared/application-modules.schemas.js.map +1 -0
- package/dist/esm/project-config/shared/application-modules.utils.d.ts +6 -0
- package/dist/esm/project-config/shared/application-modules.utils.d.ts.map +1 -0
- package/dist/esm/project-config/shared/application-modules.utils.js +26 -0
- package/dist/esm/project-config/shared/application-modules.utils.js.map +1 -0
- package/dist/esm/project-config/shared/backing-services.schemas.d.ts +68 -0
- package/dist/esm/project-config/shared/backing-services.schemas.d.ts.map +1 -0
- package/dist/esm/project-config/shared/backing-services.schemas.js +49 -0
- package/dist/esm/project-config/shared/backing-services.schemas.js.map +1 -0
- package/dist/esm/project-config/shared/data-services.schemas.d.ts +33 -0
- package/dist/esm/project-config/shared/data-services.schemas.d.ts.map +1 -0
- package/dist/esm/project-config/shared/data-services.schemas.js +47 -0
- package/dist/esm/project-config/shared/data-services.schemas.js.map +1 -0
- package/dist/esm/project-config/shared/env-example-defaults.d.ts +27 -0
- package/dist/esm/project-config/shared/env-example-defaults.d.ts.map +1 -0
- package/dist/esm/project-config/shared/env-example-defaults.js +30 -0
- package/dist/esm/project-config/shared/env-example-defaults.js.map +1 -0
- package/dist/esm/project-config/shared/environment.schemas.d.ts +106 -0
- package/dist/esm/project-config/shared/environment.schemas.d.ts.map +1 -0
- package/dist/esm/project-config/shared/environment.schemas.js +111 -0
- package/dist/esm/project-config/shared/environment.schemas.js.map +1 -0
- package/dist/esm/project-config/shared/infrastructure-defaults.schemas.d.ts +42 -0
- package/dist/esm/project-config/shared/infrastructure-defaults.schemas.d.ts.map +1 -0
- package/dist/esm/project-config/shared/infrastructure-defaults.schemas.js +42 -0
- package/dist/esm/project-config/shared/infrastructure-defaults.schemas.js.map +1 -0
- package/dist/esm/project-config/shared/k8s-utils.d.ts +36 -0
- package/dist/esm/project-config/shared/k8s-utils.d.ts.map +1 -0
- package/dist/esm/project-config/shared/k8s-utils.js +50 -0
- package/dist/esm/project-config/shared/k8s-utils.js.map +1 -0
- package/dist/esm/project-config/shared/platform-services.schemas.d.ts +30 -0
- package/dist/esm/project-config/shared/platform-services.schemas.d.ts.map +1 -0
- package/dist/esm/project-config/shared/platform-services.schemas.js +27 -0
- package/dist/esm/project-config/shared/platform-services.schemas.js.map +1 -0
- package/dist/esm/project-config/shared/service-definitions.schemas.d.ts +42 -0
- package/dist/esm/project-config/shared/service-definitions.schemas.d.ts.map +1 -0
- package/dist/esm/project-config/shared/service-definitions.schemas.js +29 -0
- package/dist/esm/project-config/shared/service-definitions.schemas.js.map +1 -0
- package/dist/esm/project-config/sharing-policy-validation.d.ts +40 -0
- package/dist/esm/project-config/sharing-policy-validation.d.ts.map +1 -0
- package/dist/esm/project-config/sharing-policy-validation.js +143 -0
- package/dist/esm/project-config/sharing-policy-validation.js.map +1 -0
- package/dist/esm/release/framework-release.constants.d.ts +3 -0
- package/dist/esm/release/framework-release.constants.d.ts.map +1 -0
- package/dist/esm/release/framework-release.constants.js +3 -0
- package/dist/esm/release/framework-release.constants.js.map +1 -0
- package/dist/esm/runtime-bridge/platform-runtime-bridge.contracts.d.ts +23 -0
- package/dist/esm/runtime-bridge/platform-runtime-bridge.contracts.d.ts.map +1 -0
- package/dist/esm/runtime-bridge/platform-runtime-bridge.contracts.js +13 -0
- package/dist/esm/runtime-bridge/platform-runtime-bridge.contracts.js.map +1 -0
- package/dist/esm/schemas/framework-info.schemas.d.ts +8 -0
- package/dist/esm/schemas/framework-info.schemas.d.ts.map +1 -0
- package/dist/esm/schemas/framework-info.schemas.js +8 -0
- package/dist/esm/schemas/framework-info.schemas.js.map +1 -0
- package/dist/esm/schemas/framework-secrets.schemas.d.ts +22 -0
- package/dist/esm/schemas/framework-secrets.schemas.d.ts.map +1 -0
- package/dist/esm/schemas/framework-secrets.schemas.js +14 -0
- package/dist/esm/schemas/framework-secrets.schemas.js.map +1 -0
- package/dist/esm/schemas/platform-application-config.schemas.d.ts +20 -0
- package/dist/esm/schemas/platform-application-config.schemas.d.ts.map +1 -0
- package/dist/esm/schemas/platform-application-config.schemas.js +19 -0
- package/dist/esm/schemas/platform-application-config.schemas.js.map +1 -0
- package/dist/esm/schemas/platform-application-secrets.schemas.d.ts +54 -0
- package/dist/esm/schemas/platform-application-secrets.schemas.d.ts.map +1 -0
- package/dist/esm/schemas/platform-application-secrets.schemas.js +67 -0
- package/dist/esm/schemas/platform-application-secrets.schemas.js.map +1 -0
- package/dist/esm/schemas/platform-config.schemas.d.ts +66 -0
- package/dist/esm/schemas/platform-config.schemas.d.ts.map +1 -0
- package/dist/esm/schemas/platform-config.schemas.js +28 -0
- package/dist/esm/schemas/platform-config.schemas.js.map +1 -0
- package/dist/esm/workspace-scope/index.d.ts +3 -0
- package/dist/esm/workspace-scope/index.d.ts.map +1 -0
- package/dist/esm/workspace-scope/index.js +3 -0
- package/dist/esm/workspace-scope/index.js.map +1 -0
- package/dist/esm/workspace-scope/workspace-scope-detector.d.ts +15 -0
- package/dist/esm/workspace-scope/workspace-scope-detector.d.ts.map +1 -0
- package/dist/esm/workspace-scope/workspace-scope-detector.js +87 -0
- package/dist/esm/workspace-scope/workspace-scope-detector.js.map +1 -0
- package/dist/esm/workspace-scope/workspace-scope.schemas.d.ts +118 -0
- package/dist/esm/workspace-scope/workspace-scope.schemas.d.ts.map +1 -0
- package/dist/esm/workspace-scope/workspace-scope.schemas.js +157 -0
- package/dist/esm/workspace-scope/workspace-scope.schemas.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/package.json +52 -0
- package/src/bootstrap/application-backend-env.contracts.ts +17 -0
- package/src/bootstrap/bootstrap-planner.ts +46 -0
- package/src/bootstrap/bootstrap.contracts.ts +251 -0
- package/src/bootstrap/bootstrap.schemas.ts +164 -0
- package/src/bootstrap/platform-runtime-env.contracts.ts +99 -0
- package/src/bootstrap/runtime-topology.contracts.ts +102 -0
- package/src/credentials/credential-generator.service.ts +39 -0
- package/src/index.ts +16 -0
- package/src/project-config/__tests__/application-modules.utils.test.ts +53 -0
- package/src/project-config/__tests__/define-framework-config.test.ts +43 -0
- package/src/project-config/__tests__/define-saas-config.test.ts +210 -0
- package/src/project-config/__tests__/loader.test.ts +100 -0
- package/src/project-config/define-framework-config.ts +44 -0
- package/src/project-config/define-infra-config.ts +168 -0
- package/src/project-config/define-minion-config.ts +27 -0
- package/src/project-config/define-platform-config.ts +28 -0
- package/src/project-config/define-platform-env-config.ts +59 -0
- package/src/project-config/define-project-config.ts +63 -0
- package/src/project-config/define-saas-config.ts +171 -0
- package/src/project-config/define-sharing-policy.ts +36 -0
- package/src/project-config/define-worker-config.ts +27 -0
- package/src/project-config/index.ts +23 -0
- package/src/project-config/loader.ts +220 -0
- package/src/project-config/shared/application-modules.schemas.ts +12 -0
- package/src/project-config/shared/application-modules.utils.ts +65 -0
- package/src/project-config/shared/backing-services.schemas.ts +59 -0
- package/src/project-config/shared/data-services.schemas.ts +58 -0
- package/src/project-config/shared/env-example-defaults.ts +50 -0
- package/src/project-config/shared/environment.schemas.ts +136 -0
- package/src/project-config/shared/infrastructure-defaults.schemas.ts +47 -0
- package/src/project-config/shared/k8s-utils.ts +56 -0
- package/src/project-config/shared/platform-services.schemas.ts +33 -0
- package/src/project-config/shared/service-definitions.schemas.ts +38 -0
- package/src/project-config/sharing-policy-validation.ts +159 -0
- package/src/release/framework-release.constants.ts +2 -0
- package/src/schemas/__tests__/platform-config.schemas.test.ts +90 -0
- package/src/schemas/framework-info.schemas.ts +13 -0
- package/src/schemas/framework-secrets.schemas.ts +19 -0
- package/src/schemas/platform-application-config.schemas.ts +25 -0
- package/src/schemas/platform-application-secrets.schemas.ts +78 -0
- package/src/schemas/platform-config.schemas.ts +45 -0
- package/src/workspace-scope/index.ts +2 -0
- package/src/workspace-scope/workspace-scope-detector.ts +98 -0
- package/src/workspace-scope/workspace-scope.schemas.ts +224 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { generateKeyPairSync, randomBytes } from 'crypto';
|
|
2
|
+
|
|
3
|
+
const ALPHANUMERIC = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
4
|
+
const PASSWORD_CHARS = ALPHANUMERIC + '_+-';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export class CredentialGenerator {
|
|
8
|
+
|
|
9
|
+
static generateECKeyPair(): { privateKey: string; publicKey: string } {
|
|
10
|
+
const { publicKey, privateKey } = generateKeyPairSync('ec', {
|
|
11
|
+
namedCurve: 'prime256v1',
|
|
12
|
+
publicKeyEncoding: { type: 'spki', format: 'pem' },
|
|
13
|
+
privateKeyEncoding: { type: 'sec1', format: 'pem' },
|
|
14
|
+
});
|
|
15
|
+
return { privateKey: privateKey.trim(), publicKey: publicKey.trim() };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static generatePassword(length: number = 24): string {
|
|
19
|
+
return this.generateFromCharset(length, PASSWORD_CHARS);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static generateSecret(length: number = 48): string {
|
|
23
|
+
return this.generateFromCharset(length, ALPHANUMERIC);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
static generateErlangCookie(): string {
|
|
27
|
+
return this.generateFromCharset(32, ALPHANUMERIC);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static generateFromCharset(length: number, charset: string): string {
|
|
31
|
+
const bytes = randomBytes(length);
|
|
32
|
+
let result = '';
|
|
33
|
+
for (let i = 0; i < length; i++) {
|
|
34
|
+
result += charset[bytes[i] % charset.length];
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export * from './project-config';
|
|
2
|
+
export * from './workspace-scope';
|
|
3
|
+
export * from './credentials/credential-generator.service';
|
|
4
|
+
|
|
5
|
+
export * from './schemas/platform-application-config.schemas';
|
|
6
|
+
export * from './schemas/platform-application-secrets.schemas';
|
|
7
|
+
export * from './schemas/platform-config.schemas';
|
|
8
|
+
export * from './schemas/framework-info.schemas';
|
|
9
|
+
export * from './schemas/framework-secrets.schemas';
|
|
10
|
+
export * from './release/framework-release.constants';
|
|
11
|
+
export * from './bootstrap/bootstrap.schemas';
|
|
12
|
+
export * from './bootstrap/bootstrap.contracts';
|
|
13
|
+
export * from './bootstrap/bootstrap-planner';
|
|
14
|
+
export * from './bootstrap/application-backend-env.contracts';
|
|
15
|
+
export * from './bootstrap/platform-runtime-env.contracts';
|
|
16
|
+
export * from './bootstrap/runtime-topology.contracts';
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
getDeclaredApplicationModuleIds,
|
|
4
|
+
getServiceBoundApplicationModuleIds,
|
|
5
|
+
resolveDeclaredApplicationModules,
|
|
6
|
+
resolveServiceBoundApplicationModules,
|
|
7
|
+
} from '../shared/application-modules.utils';
|
|
8
|
+
|
|
9
|
+
describe('application module utilities', () => {
|
|
10
|
+
const modules = {
|
|
11
|
+
'tasks-manager': {
|
|
12
|
+
services: ['backendApi', 'app'],
|
|
13
|
+
},
|
|
14
|
+
'admin-tools': {
|
|
15
|
+
services: ['backendApi'],
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
it('lists declared module ids in declaration order', () => {
|
|
20
|
+
expect(getDeclaredApplicationModuleIds(modules)).toEqual(['tasks-manager', 'admin-tools']);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('filters module ids by declared service key', () => {
|
|
24
|
+
expect(getServiceBoundApplicationModuleIds(modules, 'app')).toEqual(['tasks-manager']);
|
|
25
|
+
expect(getServiceBoundApplicationModuleIds(modules, 'backendApi')).toEqual([
|
|
26
|
+
'tasks-manager',
|
|
27
|
+
'admin-tools',
|
|
28
|
+
]);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('resolves declared modules against a local registry map', () => {
|
|
32
|
+
const declaredModulesById = {
|
|
33
|
+
'tasks-manager': 'shared.tasks',
|
|
34
|
+
'admin-tools': 'shared.admin',
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
expect(resolveDeclaredApplicationModules(modules, declaredModulesById, 'test consumer')).toEqual([
|
|
38
|
+
'shared.tasks',
|
|
39
|
+
'shared.admin',
|
|
40
|
+
]);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('fails when a declared module is missing from the local registry map', () => {
|
|
44
|
+
expect(() => resolveServiceBoundApplicationModules(
|
|
45
|
+
modules,
|
|
46
|
+
'backendApi',
|
|
47
|
+
{ 'tasks-manager': 'backend.tasks' },
|
|
48
|
+
'backend service "backendApi"',
|
|
49
|
+
)).toThrow(
|
|
50
|
+
'Application modules [admin-tools] are declared for backend service "backendApi" in wildo.saas.config.ts but no matching implementation was registered.',
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { defineFrameworkConfig } from '../define-framework-config';
|
|
3
|
+
|
|
4
|
+
describe('defineFrameworkConfig', () => {
|
|
5
|
+
it('accepts the framework release contract', () => {
|
|
6
|
+
const parsed = defineFrameworkConfig({
|
|
7
|
+
version: 1,
|
|
8
|
+
frameworkVersion: '0.2.0',
|
|
9
|
+
minCliVersion: '0.2.0',
|
|
10
|
+
publish: {
|
|
11
|
+
npm: {
|
|
12
|
+
scope: '@wildo-ai',
|
|
13
|
+
packages: ['@wildo-ai/saas-models'],
|
|
14
|
+
},
|
|
15
|
+
docker: {
|
|
16
|
+
namespace: 'wildoai',
|
|
17
|
+
images: ['wildo-platform'],
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
expect(parsed.publish.npm.scope).toBe('@wildo-ai');
|
|
23
|
+
expect(parsed.publish.docker.namespace).toBe('wildoai');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('rejects an invalid npm scope', () => {
|
|
27
|
+
expect(() => defineFrameworkConfig({
|
|
28
|
+
version: 1,
|
|
29
|
+
frameworkVersion: '0.2.0',
|
|
30
|
+
minCliVersion: '0.2.0',
|
|
31
|
+
publish: {
|
|
32
|
+
npm: {
|
|
33
|
+
scope: 'wildo-ai',
|
|
34
|
+
packages: [],
|
|
35
|
+
},
|
|
36
|
+
docker: {
|
|
37
|
+
namespace: 'wildoai',
|
|
38
|
+
images: [],
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
})).toThrow('npm scope must look like @scope or @scope/name');
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { ExternalProvider_ExchangeProtocol_Kind } from '@wildo-ai/external-connectors-models';
|
|
3
|
+
import { AppFrontendType } from '../shared/service-definitions.schemas';
|
|
4
|
+
import { defineSaasConfig } from '../define-saas-config';
|
|
5
|
+
|
|
6
|
+
describe('defineSaasConfig', () => {
|
|
7
|
+
it('accepts sparse external provider protocol maps', () => {
|
|
8
|
+
const parsed = defineSaasConfig({
|
|
9
|
+
version: 1,
|
|
10
|
+
name: 'wonder-todos',
|
|
11
|
+
slug: 'wonder-todos',
|
|
12
|
+
displayName: 'Wonder Todos',
|
|
13
|
+
type: 'saas',
|
|
14
|
+
services: {
|
|
15
|
+
app: {
|
|
16
|
+
path: './app',
|
|
17
|
+
serviceName: 'wonder-todos-app',
|
|
18
|
+
defaultPort: 4242,
|
|
19
|
+
frontendType: AppFrontendType.SAAS_APP,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
externalProvidersConfigurations: {
|
|
23
|
+
anthropic: {
|
|
24
|
+
[ExternalProvider_ExchangeProtocol_Kind.CLI_RUNTIME]: {
|
|
25
|
+
enabled: true,
|
|
26
|
+
executionProfiles: {},
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
features: {
|
|
31
|
+
organizations: false,
|
|
32
|
+
billing: false,
|
|
33
|
+
multiLanguage: false,
|
|
34
|
+
},
|
|
35
|
+
bootstrap: {
|
|
36
|
+
firstAdmin: {
|
|
37
|
+
userTypes: ['member'],
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
dataServices: {
|
|
41
|
+
mongodb: {
|
|
42
|
+
databasePrefix: 'wonder-todos',
|
|
43
|
+
},
|
|
44
|
+
redis: {
|
|
45
|
+
keyPrefix: 'wonder-todos:',
|
|
46
|
+
},
|
|
47
|
+
rabbitmq: {
|
|
48
|
+
vhost: 'wonder-todos',
|
|
49
|
+
},
|
|
50
|
+
s3: {
|
|
51
|
+
bucketPrefix: 'wonder-todos',
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
expect(parsed.externalProvidersConfigurations.anthropic?.cli_runtime?.enabled).toBe(true);
|
|
57
|
+
expect(parsed.externalProvidersConfigurations.anthropic?.llm_provider).toBeUndefined();
|
|
58
|
+
expect(parsed.bootstrap?.firstAdmin?.userTypes).toEqual(['member']);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('accepts module service bindings declared with service keys only', () => {
|
|
62
|
+
const parsed = defineSaasConfig({
|
|
63
|
+
version: 1,
|
|
64
|
+
name: 'wonder-todos',
|
|
65
|
+
slug: 'wonder-todos',
|
|
66
|
+
displayName: 'Wonder Todos',
|
|
67
|
+
type: 'saas',
|
|
68
|
+
services: {
|
|
69
|
+
backendApi: {
|
|
70
|
+
path: './backend-api',
|
|
71
|
+
serviceName: 'wonder-todos-backend-api',
|
|
72
|
+
},
|
|
73
|
+
app: {
|
|
74
|
+
path: './app',
|
|
75
|
+
serviceName: 'wonder-todos-app',
|
|
76
|
+
frontendType: AppFrontendType.SAAS_APP,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
modules: {
|
|
80
|
+
'tasks-manager': {
|
|
81
|
+
services: ['backendApi', 'app'],
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
externalProvidersConfigurations: {},
|
|
85
|
+
features: {
|
|
86
|
+
organizations: false,
|
|
87
|
+
billing: false,
|
|
88
|
+
multiLanguage: false,
|
|
89
|
+
},
|
|
90
|
+
dataServices: {
|
|
91
|
+
mongodb: {
|
|
92
|
+
databasePrefix: 'wonder-todos',
|
|
93
|
+
},
|
|
94
|
+
redis: {
|
|
95
|
+
keyPrefix: 'wonder-todos:',
|
|
96
|
+
},
|
|
97
|
+
rabbitmq: {
|
|
98
|
+
vhost: 'wonder-todos',
|
|
99
|
+
},
|
|
100
|
+
s3: {
|
|
101
|
+
bucketPrefix: 'wonder-todos',
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
expect(parsed.modules?.['tasks-manager']?.services).toEqual(['backendApi', 'app']);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('rejects module bindings that reference unknown services', () => {
|
|
110
|
+
try {
|
|
111
|
+
defineSaasConfig({
|
|
112
|
+
version: 1,
|
|
113
|
+
name: 'wonder-todos',
|
|
114
|
+
slug: 'wonder-todos',
|
|
115
|
+
displayName: 'Wonder Todos',
|
|
116
|
+
type: 'saas',
|
|
117
|
+
services: {
|
|
118
|
+
backendApi: {
|
|
119
|
+
path: './backend-api',
|
|
120
|
+
serviceName: 'wonder-todos-backend-api',
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
modules: {
|
|
124
|
+
'tasks-manager': {
|
|
125
|
+
services: ['backendApi', 'app'],
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
externalProvidersConfigurations: {},
|
|
129
|
+
features: {
|
|
130
|
+
organizations: false,
|
|
131
|
+
billing: false,
|
|
132
|
+
multiLanguage: false,
|
|
133
|
+
},
|
|
134
|
+
dataServices: {
|
|
135
|
+
mongodb: {
|
|
136
|
+
databasePrefix: 'wonder-todos',
|
|
137
|
+
},
|
|
138
|
+
redis: {
|
|
139
|
+
keyPrefix: 'wonder-todos:',
|
|
140
|
+
},
|
|
141
|
+
rabbitmq: {
|
|
142
|
+
vhost: 'wonder-todos',
|
|
143
|
+
},
|
|
144
|
+
s3: {
|
|
145
|
+
bucketPrefix: 'wonder-todos',
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
throw new Error('Expected defineSaasConfig to reject unknown service bindings.');
|
|
150
|
+
} catch (error) {
|
|
151
|
+
expect(error).toBeInstanceOf(Error);
|
|
152
|
+
expect((error as Error).message).toContain(
|
|
153
|
+
'Module \\"tasks-manager\\" references unknown service \\"app\\".',
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('rejects companion-only metadata on service declarations', () => {
|
|
159
|
+
try {
|
|
160
|
+
defineSaasConfig({
|
|
161
|
+
version: 1,
|
|
162
|
+
name: 'wonder-todos',
|
|
163
|
+
slug: 'wonder-todos',
|
|
164
|
+
displayName: 'Wonder Todos',
|
|
165
|
+
type: 'saas',
|
|
166
|
+
services: {
|
|
167
|
+
backendApi: {
|
|
168
|
+
path: './backend-api',
|
|
169
|
+
serviceName: 'wonder-todos-backend-api',
|
|
170
|
+
companionIntrospection: {
|
|
171
|
+
targets: {},
|
|
172
|
+
behaviors: {},
|
|
173
|
+
},
|
|
174
|
+
} as unknown as {
|
|
175
|
+
path: string;
|
|
176
|
+
serviceName: string;
|
|
177
|
+
defaultPort?: number | undefined;
|
|
178
|
+
frontendType?: AppFrontendType | undefined;
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
modules: {},
|
|
182
|
+
externalProvidersConfigurations: {},
|
|
183
|
+
features: {
|
|
184
|
+
organizations: false,
|
|
185
|
+
billing: false,
|
|
186
|
+
multiLanguage: false,
|
|
187
|
+
},
|
|
188
|
+
dataServices: {
|
|
189
|
+
mongodb: {
|
|
190
|
+
databasePrefix: 'wonder-todos',
|
|
191
|
+
},
|
|
192
|
+
redis: {
|
|
193
|
+
keyPrefix: 'wonder-todos:',
|
|
194
|
+
},
|
|
195
|
+
rabbitmq: {
|
|
196
|
+
vhost: 'wonder-todos',
|
|
197
|
+
},
|
|
198
|
+
s3: {
|
|
199
|
+
bucketPrefix: 'wonder-todos',
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
throw new Error('Expected defineSaasConfig to reject companion-only service metadata.');
|
|
204
|
+
} catch (error) {
|
|
205
|
+
expect(error).toBeInstanceOf(Error);
|
|
206
|
+
expect((error as Error).message).toContain('companionIntrospection');
|
|
207
|
+
expect((error as Error).message).toContain('unrecognized_keys');
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
});
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'fs';
|
|
2
|
+
import { tmpdir } from 'os';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
5
|
+
import { ConfigArtifactsZone, WORKSPACE_CONFIG_NAMES } from '../../workspace-scope/workspace-scope.schemas';
|
|
6
|
+
import { loadConfig, loadFrameworkConfig, loadPackageCompanionExport } from '../loader';
|
|
7
|
+
|
|
8
|
+
const tempDirs: string[] = [];
|
|
9
|
+
|
|
10
|
+
describe('loadConfig', () => {
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
for (const dir of tempDirs.splice(0)) {
|
|
13
|
+
rmSync(dir, { recursive: true, force: true });
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('writes sibling platform config artifacts into the project-owned dist zone', async () => {
|
|
18
|
+
const sandboxRoot = mkdtempSync(join(tmpdir(), 'platform-config-lib-loader-'));
|
|
19
|
+
tempDirs.push(sandboxRoot);
|
|
20
|
+
|
|
21
|
+
const projectRoot = join(sandboxRoot, 'project');
|
|
22
|
+
const platformRoot = join(sandboxRoot, 'shared-platform', 'remotes', 'staging');
|
|
23
|
+
mkdirSync(projectRoot, { recursive: true });
|
|
24
|
+
mkdirSync(platformRoot, { recursive: true });
|
|
25
|
+
|
|
26
|
+
writeFileSync(join(projectRoot, WORKSPACE_CONFIG_NAMES.PROJECT), 'export default {};', 'utf8');
|
|
27
|
+
writeFileSync(
|
|
28
|
+
join(platformRoot, 'wildo.infra.staging.saas.config.ts'),
|
|
29
|
+
'export default { deployment: { branch: "staging" } };',
|
|
30
|
+
'utf8',
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const config = await loadConfig<{ deployment: { branch: string } }>(
|
|
34
|
+
join(platformRoot, 'wildo.infra.staging.saas.config.ts'),
|
|
35
|
+
{
|
|
36
|
+
artifactLocation: {
|
|
37
|
+
zone: ConfigArtifactsZone.PLATFORM,
|
|
38
|
+
ownerRoot: projectRoot,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
expect(config.deployment.branch).toBe('staging');
|
|
44
|
+
expect(existsSync(join(projectRoot, '.wildo-project', 'dist', 'config-loader', 'platform'))).toBe(true);
|
|
45
|
+
expect(existsSync(join(platformRoot, 'dist'))).toBe(false);
|
|
46
|
+
expect(existsSync(join(platformRoot, '.swc'))).toBe(false);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('writes framework config artifacts into the framework-owned dist zone', async () => {
|
|
50
|
+
const sandboxRoot = mkdtempSync(join(tmpdir(), 'platform-config-lib-framework-loader-'));
|
|
51
|
+
tempDirs.push(sandboxRoot);
|
|
52
|
+
|
|
53
|
+
const frameworkRoot = join(sandboxRoot, 'wildo-ai');
|
|
54
|
+
const frameworkConfigRoot = join(frameworkRoot, WORKSPACE_CONFIG_NAMES.FRAMEWORK_DIR);
|
|
55
|
+
mkdirSync(frameworkConfigRoot, { recursive: true });
|
|
56
|
+
|
|
57
|
+
writeFileSync(join(frameworkRoot, 'wildo-framework.info.json'), '{"version":"0.2.0","minCliVersion":"0.2.0"}', 'utf8');
|
|
58
|
+
writeFileSync(
|
|
59
|
+
join(frameworkConfigRoot, 'wildo.framework.config.ts'),
|
|
60
|
+
[
|
|
61
|
+
"import { defineFrameworkConfig } from '@wildo-ai/platform-config-lib';",
|
|
62
|
+
'export default defineFrameworkConfig({',
|
|
63
|
+
" frameworkVersion: '0.2.0',",
|
|
64
|
+
" minCliVersion: '0.2.0',",
|
|
65
|
+
' publish: {',
|
|
66
|
+
" npm: { scope: '@wildo-ai', packages: [] },",
|
|
67
|
+
" docker: { namespace: 'wildoai', images: [] },",
|
|
68
|
+
' },',
|
|
69
|
+
'});',
|
|
70
|
+
].join('\n'),
|
|
71
|
+
'utf8',
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const config = await loadFrameworkConfig(frameworkRoot);
|
|
75
|
+
|
|
76
|
+
expect(config?.publish.npm.scope).toBe('@wildo-ai');
|
|
77
|
+
expect(existsSync(join(frameworkRoot, '.wildo-framework', 'dist', 'config-loader', 'framework'))).toBe(true);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('loads a companion export from the source fallback when dist export is unavailable', async () => {
|
|
81
|
+
const sandboxRoot = mkdtempSync(join(tmpdir(), 'platform-config-lib-companion-loader-'));
|
|
82
|
+
tempDirs.push(sandboxRoot);
|
|
83
|
+
|
|
84
|
+
writeFileSync(
|
|
85
|
+
join(sandboxRoot, 'package.json'),
|
|
86
|
+
JSON.stringify({ name: '@test/app', type: 'module', exports: { './companion': { import: './dist/library/companion-exports.js' } } }, null, 2),
|
|
87
|
+
'utf8',
|
|
88
|
+
);
|
|
89
|
+
mkdirSync(join(sandboxRoot, 'src'), { recursive: true });
|
|
90
|
+
writeFileSync(
|
|
91
|
+
join(sandboxRoot, 'src', 'companion-exports.ts'),
|
|
92
|
+
'export default { designSystemConfig: { chartPalette: "rose,amber" } };',
|
|
93
|
+
'utf8',
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const exports = await loadPackageCompanionExport<{ designSystemConfig: { chartPalette: string } }>(sandboxRoot);
|
|
97
|
+
|
|
98
|
+
expect(exports.designSystemConfig.chartPalette).toBe('rose,amber');
|
|
99
|
+
});
|
|
100
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import {
|
|
3
|
+
FRAMEWORK_RELEASE_DOCKER_NAMESPACE,
|
|
4
|
+
FRAMEWORK_RELEASE_NPM_SCOPE,
|
|
5
|
+
} from '../release/framework-release.constants';
|
|
6
|
+
|
|
7
|
+
const SimpleSemverSchema = z.string().regex(
|
|
8
|
+
/^\d+\.\d+\.\d+$/,
|
|
9
|
+
'must be a simple semver string in the form x.y.z',
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
export const WildoFrameworkReleaseNpmConfigSchema = z.object({
|
|
13
|
+
scope: z.literal(FRAMEWORK_RELEASE_NPM_SCOPE),
|
|
14
|
+
packages: z.array(z.string().min(1)).default([]),
|
|
15
|
+
});
|
|
16
|
+
export type WildoFrameworkReleaseNpmConfig = z.infer<typeof WildoFrameworkReleaseNpmConfigSchema>;
|
|
17
|
+
|
|
18
|
+
export const WildoFrameworkReleaseDockerConfigSchema = z.object({
|
|
19
|
+
namespace: z.literal(FRAMEWORK_RELEASE_DOCKER_NAMESPACE),
|
|
20
|
+
images: z.array(z.string().min(1)).default([]),
|
|
21
|
+
});
|
|
22
|
+
export type WildoFrameworkReleaseDockerConfig = z.infer<typeof WildoFrameworkReleaseDockerConfigSchema>;
|
|
23
|
+
|
|
24
|
+
export const WildoFrameworkConfigSchema = z.object({
|
|
25
|
+
version: z.number().int().positive().default(1),
|
|
26
|
+
frameworkVersion: SimpleSemverSchema,
|
|
27
|
+
minCliVersion: SimpleSemverSchema,
|
|
28
|
+
publish: z.object({
|
|
29
|
+
npm: WildoFrameworkReleaseNpmConfigSchema,
|
|
30
|
+
docker: WildoFrameworkReleaseDockerConfigSchema,
|
|
31
|
+
}),
|
|
32
|
+
});
|
|
33
|
+
export type WildoFrameworkConfig = z.infer<typeof WildoFrameworkConfigSchema>;
|
|
34
|
+
export type WildoFrameworkConfigInput = z.input<typeof WildoFrameworkConfigSchema>;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Define framework-scoped release configuration.
|
|
38
|
+
*
|
|
39
|
+
* This is the author-owned source of truth for framework release metadata that
|
|
40
|
+
* later materializes into `wildo-framework.info.json` and the CLI publish flow.
|
|
41
|
+
*/
|
|
42
|
+
export function defineFrameworkConfig(config: WildoFrameworkConfigInput): WildoFrameworkConfig {
|
|
43
|
+
return WildoFrameworkConfigSchema.parse(config);
|
|
44
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import {
|
|
3
|
+
WildoEnvironmentIdSchema,
|
|
4
|
+
WildoDeploymentRuntime,
|
|
5
|
+
WildoDeploymentConfigSchema,
|
|
6
|
+
WildoImageTagStrategy,
|
|
7
|
+
} from './shared/environment.schemas';
|
|
8
|
+
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// Service Schemas — runtime-specific shapes
|
|
11
|
+
// ============================================================================
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Addressing config for local or Docker Compose services.
|
|
15
|
+
* Describes how to reach a service (host, port, URL override).
|
|
16
|
+
*/
|
|
17
|
+
export const InfraServiceAddressingSchema = z.object({
|
|
18
|
+
host: z.string().optional(),
|
|
19
|
+
port: z.number().int().positive().optional(),
|
|
20
|
+
url: z.string().optional(),
|
|
21
|
+
});
|
|
22
|
+
export type InfraServiceAddressing = z.infer<typeof InfraServiceAddressingSchema>;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Scaling config for Kubernetes-deployed services.
|
|
26
|
+
* Controls replica count per service in K8s Deployment manifests.
|
|
27
|
+
*/
|
|
28
|
+
export const InfraServiceK8sSchema = z.object({
|
|
29
|
+
replicas: z.number().int().positive().optional(),
|
|
30
|
+
});
|
|
31
|
+
export type InfraServiceK8s = z.infer<typeof InfraServiceK8sSchema>;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Internal union schema for Zod parsing — accepts all fields,
|
|
35
|
+
* runtime validation in `superRefine` enforces per-runtime constraints.
|
|
36
|
+
*/
|
|
37
|
+
const InfraServiceSchema = z.object({
|
|
38
|
+
host: z.string().optional(),
|
|
39
|
+
port: z.number().int().positive().optional(),
|
|
40
|
+
url: z.string().optional(),
|
|
41
|
+
replicas: z.number().int().positive().optional(),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// ============================================================================
|
|
45
|
+
// Infra Config Schema
|
|
46
|
+
// ============================================================================
|
|
47
|
+
|
|
48
|
+
export const WildoInfraConfigSchema = z.object({
|
|
49
|
+
version: z.number().int().positive().default(1),
|
|
50
|
+
environment: WildoEnvironmentIdSchema,
|
|
51
|
+
|
|
52
|
+
deployment: WildoDeploymentConfigSchema.optional(),
|
|
53
|
+
|
|
54
|
+
database: z.object({
|
|
55
|
+
name: z.string().min(1).optional(),
|
|
56
|
+
host: z.string().optional(),
|
|
57
|
+
port: z.number().int().positive().optional(),
|
|
58
|
+
}).optional(),
|
|
59
|
+
|
|
60
|
+
cache: z.object({
|
|
61
|
+
host: z.string().optional(),
|
|
62
|
+
port: z.number().int().positive().optional(),
|
|
63
|
+
database: z.number().int().nonnegative().optional(),
|
|
64
|
+
}).optional(),
|
|
65
|
+
|
|
66
|
+
queue: z.object({
|
|
67
|
+
host: z.string().optional(),
|
|
68
|
+
port: z.number().int().positive().optional(),
|
|
69
|
+
vhost: z.string().optional(),
|
|
70
|
+
}).optional(),
|
|
71
|
+
|
|
72
|
+
storage: z.object({
|
|
73
|
+
bucket: z.string().min(1).optional(),
|
|
74
|
+
endpoint: z.string().optional(),
|
|
75
|
+
}).optional(),
|
|
76
|
+
|
|
77
|
+
services: z.record(z.string(), InfraServiceSchema).optional(),
|
|
78
|
+
domain: z.string().optional(),
|
|
79
|
+
}).superRefine((data, ctx) => {
|
|
80
|
+
const runtime = data.deployment?.runtime;
|
|
81
|
+
const services = data.services;
|
|
82
|
+
if (!services) return;
|
|
83
|
+
|
|
84
|
+
for (const [name, svc] of Object.entries(services)) {
|
|
85
|
+
if (runtime !== WildoDeploymentRuntime.KUBERNETES && svc.replicas !== undefined) {
|
|
86
|
+
ctx.addIssue({
|
|
87
|
+
code: z.ZodIssueCode.custom,
|
|
88
|
+
path: ['services', name, 'replicas'],
|
|
89
|
+
message: `"replicas" is only valid when deployment.runtime is "${WildoDeploymentRuntime.KUBERNETES}". Docker Compose always runs 1 container per service.`,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (runtime === WildoDeploymentRuntime.KUBERNETES) {
|
|
94
|
+
if (svc.host !== undefined || svc.port !== undefined || svc.url !== undefined) {
|
|
95
|
+
ctx.addIssue({
|
|
96
|
+
code: z.ZodIssueCode.custom,
|
|
97
|
+
path: ['services', name],
|
|
98
|
+
message: `"host"/"port"/"url" are not used in Kubernetes runtime — service discovery handles addressing.`,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
export type WildoInfraConfig = z.infer<typeof WildoInfraConfigSchema>;
|
|
106
|
+
export type WildoInfraConfigInput = z.input<typeof WildoInfraConfigSchema>;
|
|
107
|
+
|
|
108
|
+
// ============================================================================
|
|
109
|
+
// Typed input interfaces for compile-time enforcement
|
|
110
|
+
// ============================================================================
|
|
111
|
+
|
|
112
|
+
interface InfraConfigBase {
|
|
113
|
+
version?: number;
|
|
114
|
+
environment: string;
|
|
115
|
+
database?: { name?: string; host?: string; port?: number };
|
|
116
|
+
cache?: { host?: string; port?: number; database?: number };
|
|
117
|
+
queue?: { host?: string; port?: number; vhost?: string };
|
|
118
|
+
storage?: { bucket?: string; endpoint?: string };
|
|
119
|
+
domain?: string;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Input shape when no deployment is configured (local environment). */
|
|
123
|
+
interface InfraConfigLocal extends InfraConfigBase {
|
|
124
|
+
deployment?: undefined;
|
|
125
|
+
services?: Record<string, InfraServiceAddressing>;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Input shape for Docker Compose runtime. */
|
|
129
|
+
interface InfraConfigDockerCompose extends InfraConfigBase {
|
|
130
|
+
deployment: {
|
|
131
|
+
branch: string;
|
|
132
|
+
runtime: WildoDeploymentRuntime.DOCKER_COMPOSE;
|
|
133
|
+
imageTagStrategy?: WildoImageTagStrategy | `${WildoImageTagStrategy}`;
|
|
134
|
+
};
|
|
135
|
+
services?: Record<string, InfraServiceAddressing>;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Input shape for Kubernetes runtime — services support `replicas`. */
|
|
139
|
+
interface InfraConfigKubernetes extends InfraConfigBase {
|
|
140
|
+
deployment: {
|
|
141
|
+
branch: string;
|
|
142
|
+
runtime: WildoDeploymentRuntime.KUBERNETES;
|
|
143
|
+
registry?: string;
|
|
144
|
+
namespace?: string;
|
|
145
|
+
imageTagStrategy?: WildoImageTagStrategy | `${WildoImageTagStrategy}`;
|
|
146
|
+
};
|
|
147
|
+
services?: Record<string, InfraServiceK8s>;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Define per-environment infrastructure configuration for a SaaS app.
|
|
152
|
+
*
|
|
153
|
+
* The function is overloaded to enforce runtime-specific constraints at
|
|
154
|
+
* compile time:
|
|
155
|
+
* - **No deployment / Docker Compose**: services accept `host`, `port`, `url`
|
|
156
|
+
* - **Kubernetes**: services accept `replicas`
|
|
157
|
+
*
|
|
158
|
+
* Additional runtime validation via Zod `superRefine` catches mismatches
|
|
159
|
+
* that TypeScript inference might not catch (e.g., generic `WildoInfraConfigInput`).
|
|
160
|
+
*/
|
|
161
|
+
export function defineInfraConfig(config: InfraConfigLocal): WildoInfraConfig;
|
|
162
|
+
export function defineInfraConfig(config: InfraConfigDockerCompose): WildoInfraConfig;
|
|
163
|
+
export function defineInfraConfig(config: InfraConfigKubernetes): WildoInfraConfig;
|
|
164
|
+
export function defineInfraConfig(
|
|
165
|
+
config: InfraConfigLocal | InfraConfigDockerCompose | InfraConfigKubernetes,
|
|
166
|
+
): WildoInfraConfig {
|
|
167
|
+
return WildoInfraConfigSchema.parse(config as WildoInfraConfigInput);
|
|
168
|
+
}
|