@aifabrix/builder 2.44.5 → 2.45.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/.cursor/rules/cli-layout.mdc +8 -4
- package/.cursor/rules/project-rules.mdc +1 -1
- package/README.md +15 -23
- package/integration/hubspot-test/README.md +2 -0
- package/integration/hubspot-test/test.js +5 -3
- package/jest.projects.js +104 -2
- package/lib/api/controller-health.api.js +49 -0
- package/lib/api/dimension-values.api.js +82 -0
- package/lib/api/dimensions.api.js +114 -0
- package/lib/api/external-systems.api.js +1 -0
- package/lib/api/integration-clients.api.js +168 -0
- package/lib/api/types/dimension-values.types.js +28 -0
- package/lib/api/types/dimensions.types.js +31 -0
- package/lib/api/types/integration-clients.types.js +45 -0
- package/lib/api/validation-runner.js +46 -25
- package/lib/app/deploy-config.js +11 -1
- package/lib/app/deploy-status-display.js +3 -3
- package/lib/app/deploy.js +36 -14
- package/lib/app/display.js +15 -11
- package/lib/app/helpers.js +3 -3
- package/lib/app/index.js +3 -3
- package/lib/app/push.js +46 -23
- package/lib/app/register.js +7 -6
- package/lib/app/restart-display.js +126 -0
- package/lib/app/rotate-secret.js +7 -6
- package/lib/app/run-container-start.js +12 -6
- package/lib/app/run-env-compose.js +30 -1
- package/lib/app/run-helpers.js +58 -19
- package/lib/app/run-reload-sync.js +148 -0
- package/lib/app/run-resolve-image.js +51 -1
- package/lib/app/run.js +148 -74
- package/lib/app/show-display.js +7 -0
- package/lib/app/show.js +87 -5
- package/lib/build/index.js +83 -49
- package/lib/cli/doctor-check.js +117 -0
- package/lib/cli/index.js +8 -2
- package/lib/cli/infra-guided.js +460 -0
- package/lib/cli/installation-log-command.js +73 -0
- package/lib/cli/setup-app.js +31 -3
- package/lib/cli/setup-auth.js +98 -27
- package/lib/cli/setup-dev-path-commands.js +50 -3
- package/lib/cli/setup-infra-up-dataplane-action.js +111 -0
- package/lib/cli/setup-infra-up-platform-action.js +131 -0
- package/lib/cli/setup-infra.js +132 -118
- package/lib/cli/setup-integration-client.js +182 -0
- package/lib/cli/setup-parameters.js +21 -2
- package/lib/cli/setup-platform.js +102 -0
- package/lib/cli/setup-secrets.js +18 -6
- package/lib/cli/setup-utility-resolve.js +132 -0
- package/lib/cli/setup-utility.js +143 -84
- package/lib/commands/app-logs.js +81 -33
- package/lib/commands/auth-config.js +116 -18
- package/lib/commands/datasource-capability-dimension-cli.js +128 -0
- package/lib/commands/datasource-capability-output.js +29 -0
- package/lib/commands/datasource-capability-relate-cli.js +140 -0
- package/lib/commands/datasource-capability.js +411 -0
- package/lib/commands/datasource-unified-test-cli.options.js +1 -1
- package/lib/commands/datasource.js +53 -13
- package/lib/commands/dev-down.js +3 -3
- package/lib/commands/dev-infra-gate.js +32 -0
- package/lib/commands/dev-init.js +13 -7
- package/lib/commands/dimension-value.js +179 -0
- package/lib/commands/dimension.js +330 -0
- package/lib/commands/integration-client.js +430 -0
- package/lib/commands/login-device.js +65 -30
- package/lib/commands/login.js +21 -10
- package/lib/commands/parameters-validate.js +78 -13
- package/lib/commands/repair-datasource-auto-rbac.js +166 -0
- package/lib/commands/repair-datasource-keys.js +10 -5
- package/lib/commands/repair-datasource.js +19 -7
- package/lib/commands/repair-env-template.js +4 -1
- package/lib/commands/repair-openapi-sync.js +172 -0
- package/lib/commands/repair-persist.js +102 -0
- package/lib/commands/repair-rbac-extract.js +27 -0
- package/lib/commands/repair-rbac-migrate.js +186 -0
- package/lib/commands/repair-rbac.js +214 -31
- package/lib/commands/repair-system-alignment.js +246 -0
- package/lib/commands/repair-system-permissions.js +168 -0
- package/lib/commands/repair.js +120 -338
- package/lib/commands/secure.js +1 -1
- package/lib/commands/setup-modes.js +468 -0
- package/lib/commands/setup-prompts.js +421 -0
- package/lib/commands/setup.js +254 -0
- package/lib/commands/teardown.js +277 -0
- package/lib/commands/up-common.js +113 -19
- package/lib/commands/up-dataplane.js +44 -19
- package/lib/commands/up-miso.js +18 -18
- package/lib/commands/upload.js +111 -23
- package/lib/commands/wizard-core-helpers.js +14 -11
- package/lib/commands/wizard-core.js +6 -5
- package/lib/commands/wizard-dataplane.js +2 -2
- package/lib/commands/wizard-entity-selection.js +4 -3
- package/lib/commands/wizard-headless.js +2 -1
- package/lib/commands/wizard.js +2 -1
- package/lib/constants/infra-compose-service-names.js +40 -0
- package/lib/core/audit-logger.js +1 -34
- package/lib/core/config-admin-email.js +56 -0
- package/lib/core/config-normalize.js +60 -0
- package/lib/core/config-registered-controller-urls.js +54 -0
- package/lib/core/config.js +33 -50
- package/lib/core/env-reader.js +16 -3
- package/lib/core/secrets-admin-env.js +101 -0
- package/lib/core/secrets-ensure-infra.js +34 -1
- package/lib/core/secrets-ensure.js +88 -66
- package/lib/core/secrets-env-content.js +428 -0
- package/lib/core/secrets-env-declarative-expand.js +170 -0
- package/lib/core/secrets-env-write.js +29 -1
- package/lib/core/secrets-load.js +252 -0
- package/lib/core/secrets-names.js +32 -0
- package/lib/core/secrets.js +17 -757
- package/lib/datasource/capability/basic-exposure.js +76 -0
- package/lib/datasource/capability/capability-diff-slice.js +41 -0
- package/lib/datasource/capability/capability-key.js +34 -0
- package/lib/datasource/capability/capability-resolve.js +172 -0
- package/lib/datasource/capability/capability-storage-keys.js +22 -0
- package/lib/datasource/capability/copy-operations.js +348 -0
- package/lib/datasource/capability/copy-test-payload.js +139 -0
- package/lib/datasource/capability/create-operations.js +235 -0
- package/lib/datasource/capability/dimension-operations.js +151 -0
- package/lib/datasource/capability/dimension-validate.js +219 -0
- package/lib/datasource/capability/json-pointer.js +31 -0
- package/lib/datasource/capability/reference-rewrite.js +51 -0
- package/lib/datasource/capability/relate-operations.js +325 -0
- package/lib/datasource/capability/relate-validate.js +219 -0
- package/lib/datasource/capability/remove-operations.js +275 -0
- package/lib/datasource/capability/run-capability-copy.js +152 -0
- package/lib/datasource/capability/run-capability-diff.js +135 -0
- package/lib/datasource/capability/run-capability-dimension.js +291 -0
- package/lib/datasource/capability/run-capability-edit.js +377 -0
- package/lib/datasource/capability/run-capability-relate.js +193 -0
- package/lib/datasource/capability/run-capability-remove.js +105 -0
- package/lib/datasource/capability/templates/minimal-fetch.json +18 -0
- package/lib/datasource/capability/validate-capability-slice.js +35 -0
- package/lib/datasource/list.js +136 -23
- package/lib/datasource/log-viewer.js +2 -4
- package/lib/datasource/unified-validation-run.js +51 -16
- package/lib/datasource/validate.js +53 -1
- package/lib/deployment/deploy-poll-ui.js +60 -0
- package/lib/deployment/deployer-status.js +29 -3
- package/lib/deployment/deployer.js +48 -30
- package/lib/deployment/environment.js +7 -2
- package/lib/deployment/poll-interval.js +72 -0
- package/lib/deployment/push.js +11 -9
- package/lib/external-system/deploy.js +9 -2
- package/lib/external-system/download.js +61 -32
- package/lib/external-system/sync-deploy-manifest.js +33 -0
- package/lib/infrastructure/index.js +49 -19
- package/lib/infrastructure/orphan-infra-docker-teardown.js +177 -0
- package/lib/internal/node-fs.js +2 -0
- package/lib/parameters/infra-kv-discovery.js +29 -4
- package/lib/parameters/infra-parameter-catalog.js +6 -3
- package/lib/parameters/infra-parameter-validate.js +67 -19
- package/lib/resolvers/datasource-resolver.js +53 -0
- package/lib/resolvers/dimension-file.js +52 -0
- package/lib/resolvers/manifest-resolver.js +133 -0
- package/lib/schema/application-schema.json +4 -0
- package/lib/schema/external-datasource.schema.json +183 -53
- package/lib/schema/external-system.schema.json +23 -10
- package/lib/schema/infra.parameter.yaml +26 -1
- package/lib/schema/wizard-config.schema.json +1 -1
- package/lib/utils/aifabrix-config-dir-walk.js +40 -0
- package/lib/utils/aifabrix-runtime-config-dir.js +26 -3
- package/lib/utils/app-config-resolver.js +24 -1
- package/lib/utils/app-run-containers.js +2 -2
- package/lib/utils/applications-config-defaults.js +206 -0
- package/lib/utils/auth-config-validator.js +2 -12
- package/lib/utils/bash-secret-env.js +59 -0
- package/lib/utils/cli-secrets-error-format.js +78 -0
- package/lib/utils/cli-test-layout-chalk.js +31 -9
- package/lib/utils/cli-utils.js +4 -36
- package/lib/utils/compose-generate-docker-compose.js +111 -6
- package/lib/utils/compose-generator.js +17 -8
- package/lib/utils/controller-url.js +50 -7
- package/lib/utils/datasource-test-run-display.js +8 -0
- package/lib/utils/dev-hosts-helper.js +3 -2
- package/lib/utils/dev-init-ssh-merge.js +2 -1
- package/lib/utils/docker-build.js +17 -9
- package/lib/utils/docker-reload-mount.js +127 -0
- package/lib/utils/env-copy.js +99 -14
- package/lib/utils/env-template.js +5 -1
- package/lib/utils/external-readme.js +71 -2
- package/lib/utils/external-system-local-test-tty.js +3 -2
- package/lib/utils/external-system-readiness-core.js +45 -12
- package/lib/utils/external-system-readiness-deploy-display.js +3 -3
- package/lib/utils/external-system-readiness-display-internals.js +33 -3
- package/lib/utils/external-system-readiness-display.js +10 -1
- package/lib/utils/file-upload.js +40 -3
- package/lib/utils/health-check-db-init.js +107 -0
- package/lib/utils/health-check-public-warn.js +69 -0
- package/lib/utils/health-check-url.js +28 -10
- package/lib/utils/health-check.js +139 -107
- package/lib/utils/help-builder.js +5 -1
- package/lib/utils/image-name.js +34 -7
- package/lib/utils/infra-optional-service-flags.js +69 -0
- package/lib/utils/installation-log-core.js +282 -0
- package/lib/utils/installation-log-record.js +237 -0
- package/lib/utils/installation-log.js +123 -0
- package/lib/utils/integration-file-backup.js +74 -0
- package/lib/utils/log-redaction.js +105 -0
- package/lib/utils/manifest-location.js +164 -0
- package/lib/utils/manifest-source-emit.js +162 -0
- package/lib/utils/mutagen-install.js +30 -3
- package/lib/utils/paths.js +308 -76
- package/lib/utils/postgres-wipe.js +212 -0
- package/lib/utils/register-aifabrix-shell-env.js +15 -0
- package/lib/utils/remote-dev-auth.js +21 -5
- package/lib/utils/remote-docker-env.js +9 -1
- package/lib/utils/remote-secrets-loader.js +49 -4
- package/lib/utils/resolve-docker-image-ref.js +9 -3
- package/lib/utils/run-cli-flags.js +29 -0
- package/lib/utils/secrets-ancestor-paths.js +47 -0
- package/lib/utils/secrets-canonical.js +10 -3
- package/lib/utils/secrets-helpers.js +17 -10
- package/lib/utils/secrets-kv-refs.js +42 -0
- package/lib/utils/secrets-kv-scope.js +19 -2
- package/lib/utils/secrets-materialize-local.js +134 -0
- package/lib/utils/secrets-path.js +26 -13
- package/lib/utils/secrets-utils.js +20 -10
- package/lib/utils/system-builder-root.js +42 -0
- package/lib/utils/url-declarative-public-base.js +80 -12
- package/lib/utils/url-declarative-resolve-build-urls.js +238 -0
- package/lib/utils/url-declarative-resolve-build.js +24 -388
- package/lib/utils/url-declarative-resolve-expand-token.js +189 -0
- package/lib/utils/url-declarative-resolve-load-doc.js +12 -3
- package/lib/utils/url-declarative-resolve-surface-state.js +102 -0
- package/lib/utils/url-declarative-resolve.js +47 -7
- package/lib/utils/url-declarative-runtime-base-path.js +52 -0
- package/lib/utils/url-declarative-vdir-inactive-env.js +2 -1
- package/lib/utils/urls-local-registry-scan.js +103 -0
- package/lib/utils/urls-local-registry.js +158 -76
- package/lib/utils/validation-poll-ui.js +81 -0
- package/lib/utils/validation-run-poll.js +29 -5
- package/lib/utils/with-muted-logger.js +53 -0
- package/package.json +3 -1
- package/templates/applications/dataplane/application.yaml +5 -1
- package/templates/applications/dataplane/rbac.yaml +10 -10
- package/templates/applications/keycloak/env.template +8 -6
- package/templates/applications/miso-controller/application.yaml +9 -0
- package/templates/applications/miso-controller/env.template +27 -29
- package/templates/applications/miso-controller/rbac.yaml +9 -9
- package/templates/external-system/README.md.hbs +83 -123
- package/.npmrc.token +0 -1
- package/.nyc_output/55e9d034-ddab-4579-a706-e02a91d75c91.json +0 -1
- package/.nyc_output/processinfo/55e9d034-ddab-4579-a706-e02a91d75c91.json +0 -1
- package/.nyc_output/processinfo/index.json +0 -1
- package/lib/api/service-users.api.js +0 -150
- package/lib/api/types/service-users.types.js +0 -65
- package/lib/cli/setup-service-user.js +0 -187
- package/lib/commands/service-user.js +0 -429
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tear down AI Fabrix infra Docker resources when compose.yaml / admin-secrets
|
|
3
|
+
* are missing from disk (e.g. after manual deletes). Matches compose naming from
|
|
4
|
+
* `templates/infra/compose.yaml.hbs` and `lib/infrastructure/compose.js`.
|
|
5
|
+
*
|
|
6
|
+
* @fileoverview Orphan Docker teardown for developer-scoped infra stacks
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const dockerUtils = require('../utils/docker');
|
|
12
|
+
const logger = require('../utils/logger');
|
|
13
|
+
const { execAsyncWithCwd } = require('./services');
|
|
14
|
+
const { getInfraProjectName } = require('./helpers');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Bridge network name for this developer (must match compose generator).
|
|
18
|
+
* @param {string|number} devId - Developer ID
|
|
19
|
+
* @returns {string}
|
|
20
|
+
*/
|
|
21
|
+
function getInfraBridgeNetworkName(devId) {
|
|
22
|
+
const idNum = typeof devId === 'string' ? parseInt(devId, 10) : devId;
|
|
23
|
+
return idNum === 0 ? 'infra-aifabrix-network' : `infra-dev${devId}-aifabrix-network`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Known infra service container names (postgres, redis, optional UIs).
|
|
28
|
+
* @param {string|number} devId - Developer ID
|
|
29
|
+
* @returns {string[]}
|
|
30
|
+
*/
|
|
31
|
+
function getInfraServiceContainerNames(devId) {
|
|
32
|
+
const idNum = typeof devId === 'string' ? parseInt(devId, 10) : devId;
|
|
33
|
+
if (idNum === 0) {
|
|
34
|
+
return ['aifabrix-postgres', 'aifabrix-redis', 'aifabrix-pgadmin', 'aifabrix-redis-commander', 'aifabrix-traefik'];
|
|
35
|
+
}
|
|
36
|
+
return [
|
|
37
|
+
`aifabrix-dev${devId}-postgres`,
|
|
38
|
+
`aifabrix-dev${devId}-redis`,
|
|
39
|
+
`aifabrix-dev${devId}-pgadmin`,
|
|
40
|
+
`aifabrix-dev${devId}-redis-commander`,
|
|
41
|
+
`aifabrix-dev${devId}-traefik`
|
|
42
|
+
];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Named volumes declared in infra compose (explicit `name:` entries).
|
|
47
|
+
* @param {string|number} devId - Developer ID
|
|
48
|
+
* @returns {string[]}
|
|
49
|
+
*/
|
|
50
|
+
function getInfraNamedVolumeCandidates(devId) {
|
|
51
|
+
const idNum = typeof devId === 'string' ? parseInt(devId, 10) : devId;
|
|
52
|
+
if (idNum === 0) {
|
|
53
|
+
return ['infra_postgres_data', 'infra_redis_data', 'infra_pgadmin_data'];
|
|
54
|
+
}
|
|
55
|
+
return [
|
|
56
|
+
`infra_dev${devId}_postgres_data`,
|
|
57
|
+
`infra_dev${devId}_redis_data`,
|
|
58
|
+
`infra_dev${devId}_pgadmin_data`
|
|
59
|
+
];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* `docker compose down` using only the Compose project name (works when the
|
|
64
|
+
* compose file was removed but the project still exists in Docker).
|
|
65
|
+
*
|
|
66
|
+
* @param {string|number} devId - Developer ID
|
|
67
|
+
* @param {boolean} withVolumes - Pass `-v` to remove named volumes
|
|
68
|
+
* @returns {Promise<void>}
|
|
69
|
+
*/
|
|
70
|
+
async function tryComposeProjectDown(devId, withVolumes) {
|
|
71
|
+
const composeCmd = await dockerUtils.getComposeCommand();
|
|
72
|
+
const projectName = getInfraProjectName(devId);
|
|
73
|
+
const volFlag = withVolumes ? ' -v' : '';
|
|
74
|
+
await execAsyncWithCwd(`${composeCmd} -p "${projectName}" down${volFlag}`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @param {string} name - Container name
|
|
79
|
+
* @returns {Promise<void>}
|
|
80
|
+
*/
|
|
81
|
+
async function dockerRmForceOne(name) {
|
|
82
|
+
try {
|
|
83
|
+
await execAsyncWithCwd(`docker rm -f "${name}"`);
|
|
84
|
+
logger.log(`Stopped and removed container: ${name}`);
|
|
85
|
+
} catch {
|
|
86
|
+
logger.log(`Container ${name} not running or already removed`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @param {string} vol - Volume name
|
|
92
|
+
* @returns {Promise<void>}
|
|
93
|
+
*/
|
|
94
|
+
async function dockerVolumeRmForceOne(vol) {
|
|
95
|
+
try {
|
|
96
|
+
await execAsyncWithCwd(`docker volume rm -f "${vol}"`);
|
|
97
|
+
logger.log(`Removed volume: ${vol}`);
|
|
98
|
+
} catch {
|
|
99
|
+
logger.log(`Volume ${vol} not found or already removed`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Remove containers on the developer infra bridge network (covers strays).
|
|
105
|
+
* @param {string} networkName - Docker network name
|
|
106
|
+
* @returns {Promise<void>}
|
|
107
|
+
*/
|
|
108
|
+
async function removeContainersOnNetwork(networkName) {
|
|
109
|
+
let stdout = '';
|
|
110
|
+
try {
|
|
111
|
+
({ stdout } = await execAsyncWithCwd(
|
|
112
|
+
`docker network inspect "${networkName}" --format '{{json .Containers}}'`
|
|
113
|
+
));
|
|
114
|
+
} catch {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const raw = String(stdout || '').trim();
|
|
118
|
+
if (!raw || raw === 'null' || raw === '{}') return;
|
|
119
|
+
let containers;
|
|
120
|
+
try {
|
|
121
|
+
containers = JSON.parse(raw);
|
|
122
|
+
} catch {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
for (const endpoint of Object.values(containers)) {
|
|
126
|
+
const name = endpoint && typeof endpoint.Name === 'string' ? endpoint.Name.replace(/^\//, '') : '';
|
|
127
|
+
if (name) await dockerRmForceOne(name);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Remove bridge network if present.
|
|
133
|
+
* @param {string} networkName - Docker network name
|
|
134
|
+
* @returns {Promise<void>}
|
|
135
|
+
*/
|
|
136
|
+
async function removeNetworkIfPresent(networkName) {
|
|
137
|
+
try {
|
|
138
|
+
await execAsyncWithCwd(`docker network rm "${networkName}"`);
|
|
139
|
+
logger.log(`Removed network: ${networkName}`);
|
|
140
|
+
} catch {
|
|
141
|
+
logger.log(`Network ${networkName} not removed (still in use or already gone)`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Last-resort teardown: remove known infra containers, optional volumes, then network.
|
|
147
|
+
*
|
|
148
|
+
* @param {string|number} devId - Developer ID
|
|
149
|
+
* @param {{ removeVolumes?: boolean }} [opts]
|
|
150
|
+
* @returns {Promise<void>}
|
|
151
|
+
*/
|
|
152
|
+
async function stopInfraDockerStackOrphaned(devId, opts = {}) {
|
|
153
|
+
const removeVolumes = opts.removeVolumes !== false;
|
|
154
|
+
const networkName = getInfraBridgeNetworkName(devId);
|
|
155
|
+
|
|
156
|
+
for (const name of getInfraServiceContainerNames(devId)) {
|
|
157
|
+
await dockerRmForceOne(name);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
await removeContainersOnNetwork(networkName);
|
|
161
|
+
|
|
162
|
+
if (removeVolumes) {
|
|
163
|
+
for (const vol of getInfraNamedVolumeCandidates(devId)) {
|
|
164
|
+
await dockerVolumeRmForceOne(vol);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
await removeNetworkIfPresent(networkName);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
module.exports = {
|
|
172
|
+
getInfraBridgeNetworkName,
|
|
173
|
+
getInfraServiceContainerNames,
|
|
174
|
+
getInfraNamedVolumeCandidates,
|
|
175
|
+
tryComposeProjectDown,
|
|
176
|
+
stopInfraDockerStackOrphaned
|
|
177
|
+
};
|
package/lib/internal/node-fs.js
CHANGED
|
@@ -72,6 +72,7 @@ function buildBoundFs() {
|
|
|
72
72
|
mkdirSync: snap.mkdirSync,
|
|
73
73
|
readdirSync: snap.readdirSync,
|
|
74
74
|
statSync: snap.statSync,
|
|
75
|
+
renameSync: snap.renameSync,
|
|
75
76
|
watch: (...args) => live.watch(...args),
|
|
76
77
|
promises: boundPromises
|
|
77
78
|
};
|
|
@@ -83,6 +84,7 @@ function buildBoundFs() {
|
|
|
83
84
|
mkdirSync: bindSync(rf, 'mkdirSync'),
|
|
84
85
|
readdirSync: bindSync(rf, 'readdirSync'),
|
|
85
86
|
statSync: bindSync(rf, 'statSync'),
|
|
87
|
+
renameSync: bindSync(rf, 'renameSync'),
|
|
86
88
|
watch: (...args) => live.watch(...args),
|
|
87
89
|
promises: boundPromises
|
|
88
90
|
};
|
|
@@ -30,6 +30,23 @@ function extractKvKeysFromEnvContent(content) {
|
|
|
30
30
|
return [...keys];
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
/**
|
|
34
|
+
* List builder app directories only (no integration/* apps).
|
|
35
|
+
* Used by `parameters validate` so sample integrations do not require catalog entries.
|
|
36
|
+
* @param {object} pathsUtil - paths module
|
|
37
|
+
* @returns {{ appKey: string, dir: string }[]}
|
|
38
|
+
*/
|
|
39
|
+
function listBuilderAppDirsForDiscovery(pathsUtil) {
|
|
40
|
+
const out = [];
|
|
41
|
+
for (const name of pathsUtil.listBuilderAppNames()) {
|
|
42
|
+
const dir = pathsUtil.getBuilderPath(name);
|
|
43
|
+
if (fsRealSync.existsSync(dir)) {
|
|
44
|
+
out.push({ appKey: name, dir });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
|
|
33
50
|
/**
|
|
34
51
|
* List app directories for discovery (builder first, then integration-only apps).
|
|
35
52
|
* @param {object} pathsUtil - paths module
|
|
@@ -99,13 +116,20 @@ function discoverKvKeysFromEnvTemplatesForHook(pathsUtil, hook, catalog) {
|
|
|
99
116
|
}
|
|
100
117
|
|
|
101
118
|
/**
|
|
102
|
-
*
|
|
103
|
-
*
|
|
119
|
+
* Keys `ensureInfraSecrets` (`up-infra`) may write locally:
|
|
120
|
+
* - {@link standardUpInfraEnsureKeys} in infra.parameter.yaml (explicit bootstrap + Redis/Postgres core)
|
|
121
|
+
* - `databases-{app}-{i}-*` derived from each workspace app `requires.databases`
|
|
122
|
+
* - `kv://` names from env.template lines whose catalog entry includes `upInfra`
|
|
123
|
+
*
|
|
124
|
+
* Does **not** union every `parameters[].ensureOn: upInfra` catalog entry—those would create dozens of
|
|
125
|
+
* unused Azure/BASH/app placeholders (often emptyString locally). Apps pull those via `resolve` / run when needed.
|
|
126
|
+
*
|
|
127
|
+
* @param {{ getStandardUpInfraBootstrapKeys: Function, keyMatchesEnsureHook: Function }} catalog
|
|
104
128
|
* @param {object} pathsUtil - paths module
|
|
105
129
|
* @returns {string[]}
|
|
106
130
|
*/
|
|
107
131
|
function getAllInfraEnsureKeys(catalog, pathsUtil) {
|
|
108
|
-
const set = new Set(
|
|
132
|
+
const set = new Set();
|
|
109
133
|
for (const k of catalog.getStandardUpInfraBootstrapKeys()) set.add(k);
|
|
110
134
|
for (const k of deriveDatabaseKvKeysFromWorkspace(pathsUtil)) set.add(k);
|
|
111
135
|
for (const k of discoverKvKeysFromEnvTemplatesForHook(pathsUtil, 'upInfra', catalog)) set.add(k);
|
|
@@ -117,5 +141,6 @@ module.exports = {
|
|
|
117
141
|
deriveDatabaseKvKeysFromWorkspace,
|
|
118
142
|
discoverKvKeysFromEnvTemplatesForHook,
|
|
119
143
|
getAllInfraEnsureKeys,
|
|
120
|
-
listAppDirsForDiscovery
|
|
144
|
+
listAppDirsForDiscovery,
|
|
145
|
+
listBuilderAppDirsForDiscovery
|
|
121
146
|
};
|
|
@@ -133,7 +133,10 @@ function createCatalogApi(doc, exact, patterns) {
|
|
|
133
133
|
|
|
134
134
|
function isKeyAllowedEmpty(key) {
|
|
135
135
|
const entry = findEntryForKey(key);
|
|
136
|
-
|
|
136
|
+
const gen = entry && entry.generator;
|
|
137
|
+
// emptyAllowed: e.g. Redis password when no requirepass.
|
|
138
|
+
// emptyString: optional user-supplied keys (OpenAI / Azure OpenAI) — absent resolves like ''.
|
|
139
|
+
return Boolean(gen && (gen.type === 'emptyAllowed' || gen.type === 'emptyString'));
|
|
137
140
|
}
|
|
138
141
|
|
|
139
142
|
function keyMatchesEnsureHook(key, hook) {
|
|
@@ -236,7 +239,7 @@ function readRelaxedUpInfraEnsureKeyList(catalogPath = DEFAULT_CATALOG_PATH) {
|
|
|
236
239
|
}
|
|
237
240
|
|
|
238
241
|
/**
|
|
239
|
-
* YAML-only: keys whose generator type is emptyAllowed (
|
|
242
|
+
* YAML-only: keys whose generator type is emptyAllowed or emptyString (optional / absent OK).
|
|
240
243
|
*
|
|
241
244
|
* @param {string} [catalogPath]
|
|
242
245
|
* @returns {Set<string>|null}
|
|
@@ -254,7 +257,7 @@ function readRelaxedEmptyAllowedKeySet(catalogPath = DEFAULT_CATALOG_PATH) {
|
|
|
254
257
|
typeof entry.key === 'string' &&
|
|
255
258
|
entry.key.trim() &&
|
|
256
259
|
entry.generator &&
|
|
257
|
-
entry.generator.type === 'emptyAllowed'
|
|
260
|
+
(entry.generator.type === 'emptyAllowed' || entry.generator.type === 'emptyString')
|
|
258
261
|
) {
|
|
259
262
|
set.add(entry.key.trim());
|
|
260
263
|
}
|
|
@@ -6,38 +6,86 @@
|
|
|
6
6
|
|
|
7
7
|
const { nodeFs } = require('../internal/node-fs');
|
|
8
8
|
const path = require('path');
|
|
9
|
-
const {
|
|
9
|
+
const {
|
|
10
|
+
listBuilderAppDirsForDiscovery,
|
|
11
|
+
extractKvKeysFromEnvContent
|
|
12
|
+
} = require('./infra-kv-discovery');
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
function _scanEnvTemplate(fs, cwd, envPath) {
|
|
15
|
+
const rel = path.relative(cwd, envPath) || envPath;
|
|
16
|
+
try {
|
|
17
|
+
const content = fs.readFileSync(envPath, 'utf8');
|
|
18
|
+
return { rel, keys: extractKvKeysFromEnvContent(content), readError: null };
|
|
19
|
+
} catch (e) {
|
|
20
|
+
return { rel, keys: [], readError: e };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function _scanBuilderEnvTemplates(catalog, pathsUtil) {
|
|
19
25
|
const cwd = process.cwd();
|
|
20
26
|
const fs = nodeFs();
|
|
27
|
+
const errors = [];
|
|
28
|
+
const scannedApps = [];
|
|
29
|
+
const scannedEnvTemplates = [];
|
|
30
|
+
const kvKeysUnique = new Set();
|
|
21
31
|
|
|
22
|
-
for (const { dir } of
|
|
32
|
+
for (const { dir } of listBuilderAppDirsForDiscovery(pathsUtil)) {
|
|
33
|
+
scannedApps.push(path.relative(cwd, dir) || dir);
|
|
23
34
|
const envPath = path.join(dir, 'env.template');
|
|
24
35
|
if (!fs.existsSync(envPath)) continue;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
36
|
+
const scan = _scanEnvTemplate(fs, cwd, envPath);
|
|
37
|
+
scannedEnvTemplates.push(scan.rel);
|
|
38
|
+
if (scan.readError) {
|
|
39
|
+
errors.push({
|
|
40
|
+
key: '__read_error__',
|
|
41
|
+
envTemplatePath: scan.rel,
|
|
42
|
+
message: scan.readError.message
|
|
43
|
+
});
|
|
30
44
|
continue;
|
|
31
45
|
}
|
|
32
|
-
const
|
|
33
|
-
|
|
46
|
+
for (const k of scan.keys) {
|
|
47
|
+
kvKeysUnique.add(k);
|
|
34
48
|
if (!catalog.findEntryForKey(k)) {
|
|
35
|
-
errors.push(
|
|
49
|
+
errors.push({ key: k, envTemplatePath: scan.rel });
|
|
36
50
|
}
|
|
37
51
|
}
|
|
38
52
|
}
|
|
39
53
|
|
|
40
|
-
return {
|
|
54
|
+
return { errors, scannedApps, scannedEnvTemplates, kvKeysUnique };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Validate that every kv:// key under builder app env.template files has catalog coverage.
|
|
59
|
+
* Integration apps under integration/ are not scanned (they often use ad-hoc kv keys).
|
|
60
|
+
* @param {{ findEntryForKey: Function }} catalog - Loaded catalog API
|
|
61
|
+
* @param {object} pathsUtil - paths module
|
|
62
|
+
* @returns {{
|
|
63
|
+
* valid: boolean,
|
|
64
|
+
* errors: { key: string, envTemplatePath: string, message?: string }[],
|
|
65
|
+
* summary: {
|
|
66
|
+
* scannedApps: string[],
|
|
67
|
+
* scannedEnvTemplates: string[],
|
|
68
|
+
* kvKeysUnique: string[],
|
|
69
|
+
* kvKeysCount: number
|
|
70
|
+
* }
|
|
71
|
+
* }}
|
|
72
|
+
*/
|
|
73
|
+
function validateWorkspaceKvRefsAgainstCatalog(catalog, pathsUtil) {
|
|
74
|
+
const { errors, scannedApps, scannedEnvTemplates, kvKeysUnique } = _scanBuilderEnvTemplates(
|
|
75
|
+
catalog,
|
|
76
|
+
pathsUtil
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
valid: errors.length === 0,
|
|
81
|
+
errors,
|
|
82
|
+
summary: {
|
|
83
|
+
scannedApps: scannedApps.sort(),
|
|
84
|
+
scannedEnvTemplates: scannedEnvTemplates.sort(),
|
|
85
|
+
kvKeysUnique: [...kvKeysUnique].sort(),
|
|
86
|
+
kvKeysCount: kvKeysUnique.size
|
|
87
|
+
}
|
|
88
|
+
};
|
|
41
89
|
}
|
|
42
90
|
|
|
43
91
|
/**
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared datasource resolver utilities.
|
|
3
|
+
*
|
|
4
|
+
* Intentionally CLI-agnostic (no commander/options), so it can be reused by commands and tests.
|
|
5
|
+
*
|
|
6
|
+
* @fileoverview Datasource path + JSON loading helpers
|
|
7
|
+
* @author AI Fabrix Team
|
|
8
|
+
* @version 2.0.0
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const { resolveValidateInputPath, resolvePathFromIntegrationDatasourceKey } = require('../datasource/validate');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {string} fileOrKey
|
|
18
|
+
* @returns {string} Absolute path to datasource JSON file
|
|
19
|
+
*/
|
|
20
|
+
function resolveDatasourceJsonPath(fileOrKey) {
|
|
21
|
+
return resolveValidateInputPath(String(fileOrKey || '').trim());
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Attempt to resolve a datasource key under integration/<app>/ without throwing.
|
|
26
|
+
*
|
|
27
|
+
* @param {string} datasourceKey
|
|
28
|
+
* @returns {{ ok: true, path: string } | { ok: false, error: string }}
|
|
29
|
+
*/
|
|
30
|
+
function tryResolveDatasourceKeyToLocalPath(datasourceKey) {
|
|
31
|
+
try {
|
|
32
|
+
const p = resolvePathFromIntegrationDatasourceKey(String(datasourceKey || '').trim());
|
|
33
|
+
return { ok: true, path: p };
|
|
34
|
+
} catch (e) {
|
|
35
|
+
return { ok: false, error: e?.message || String(e) };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @param {string} jsonPath
|
|
41
|
+
* @returns {any}
|
|
42
|
+
*/
|
|
43
|
+
function readJsonFile(jsonPath) {
|
|
44
|
+
const raw = fs.readFileSync(jsonPath, 'utf8');
|
|
45
|
+
return JSON.parse(raw);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = {
|
|
49
|
+
resolveDatasourceJsonPath,
|
|
50
|
+
tryResolveDatasourceKeyToLocalPath,
|
|
51
|
+
readJsonFile
|
|
52
|
+
};
|
|
53
|
+
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dimension file helpers for `aifabrix dimension create --file`.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Dimension file parsing
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 2.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {Object} DimensionCreateInput
|
|
16
|
+
* @property {string} key
|
|
17
|
+
* @property {string} displayName
|
|
18
|
+
* @property {string} [description]
|
|
19
|
+
* @property {'string'|'number'|'boolean'} dataType
|
|
20
|
+
* @property {boolean} [isRequired]
|
|
21
|
+
* @property {Array<{ value: string, displayName?: string, description?: string }>} [values]
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param {string} filePath
|
|
26
|
+
* @returns {DimensionCreateInput}
|
|
27
|
+
*/
|
|
28
|
+
function readDimensionCreateFile(filePath) {
|
|
29
|
+
const p = path.resolve(String(filePath || '').trim());
|
|
30
|
+
if (!p) {
|
|
31
|
+
throw new Error('--file is required');
|
|
32
|
+
}
|
|
33
|
+
if (!fs.existsSync(p)) {
|
|
34
|
+
throw new Error(`File not found: ${p}`);
|
|
35
|
+
}
|
|
36
|
+
const raw = fs.readFileSync(p, 'utf8');
|
|
37
|
+
let parsed;
|
|
38
|
+
try {
|
|
39
|
+
parsed = JSON.parse(raw);
|
|
40
|
+
} catch (e) {
|
|
41
|
+
throw new Error(`Invalid JSON in ${p}: ${e.message}`);
|
|
42
|
+
}
|
|
43
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
44
|
+
throw new Error(`Dimension file must be a JSON object: ${p}`);
|
|
45
|
+
}
|
|
46
|
+
return parsed;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module.exports = {
|
|
50
|
+
readDimensionCreateFile
|
|
51
|
+
};
|
|
52
|
+
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared remote manifest lookup helpers (dataplane).
|
|
3
|
+
*
|
|
4
|
+
* This module does not decide *when* to fetch; callers can treat failures as
|
|
5
|
+
* \"not authenticated\" or \"remote unavailable\" depending on their UX needs.
|
|
6
|
+
*
|
|
7
|
+
* @fileoverview Remote manifest fetch helpers
|
|
8
|
+
* @author AI Fabrix Team
|
|
9
|
+
* @version 2.0.0
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
'use strict';
|
|
13
|
+
|
|
14
|
+
const { resolveDataplaneAndAuth } = require('../commands/upload');
|
|
15
|
+
const { getExternalSystemConfig } = require('../api/external-systems.api');
|
|
16
|
+
const { getDatasourceConfig } = require('../api/datasources-core.api');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {any} maybeEnvelope
|
|
20
|
+
* @returns {{ isFailure: boolean, status: number, errorType: string|undefined, message: string|undefined }}
|
|
21
|
+
*/
|
|
22
|
+
function unwrapApiFailure(maybeEnvelope) {
|
|
23
|
+
if (!maybeEnvelope || typeof maybeEnvelope !== 'object') {
|
|
24
|
+
return { isFailure: false, status: 0, errorType: undefined, message: undefined };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (maybeEnvelope.success !== false) {
|
|
28
|
+
return { isFailure: false, status: 0, errorType: undefined, message: undefined };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
isFailure: true,
|
|
33
|
+
status: Number(maybeEnvelope.status) || 0,
|
|
34
|
+
errorType: maybeEnvelope.errorType,
|
|
35
|
+
message: maybeEnvelope.error || maybeEnvelope.formattedError || maybeEnvelope.message
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @param {{ status: number, errorType: string|undefined, message: string|undefined }} failure
|
|
41
|
+
* @returns {string|undefined}
|
|
42
|
+
*/
|
|
43
|
+
function failureCodeFrom(failure) {
|
|
44
|
+
if (failure.errorType === 'notfound' || failure.status === 404) return 'not_found';
|
|
45
|
+
if (/Authentication required\./i.test(String(failure.message || ''))) return 'not_authenticated';
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Fetch running manifest for one external system key (includes dataSources[]).
|
|
51
|
+
*
|
|
52
|
+
* @param {string} systemKey
|
|
53
|
+
* @param {{ silent?: boolean }} [opts]
|
|
54
|
+
* @returns {Promise<{ ok: true, dataplaneUrl: string, authConfig: Object, manifest: any } | { ok: false, error: string, code?: string }>}
|
|
55
|
+
*/
|
|
56
|
+
async function tryFetchRunningManifest(systemKey, opts = {}) {
|
|
57
|
+
try {
|
|
58
|
+
const { dataplaneUrl, authConfig } = await resolveDataplaneAndAuth(String(systemKey || '').trim(), {
|
|
59
|
+
silent: opts.silent === true
|
|
60
|
+
});
|
|
61
|
+
const res = await getExternalSystemConfig(dataplaneUrl, systemKey, authConfig);
|
|
62
|
+
const manifest = res?.data?.data ?? res?.data ?? res;
|
|
63
|
+
return { ok: true, dataplaneUrl, authConfig, manifest };
|
|
64
|
+
} catch (e) {
|
|
65
|
+
const msg = e?.message || String(e);
|
|
66
|
+
const code = /Authentication required\./i.test(msg) ? 'not_authenticated' : undefined;
|
|
67
|
+
return { ok: false, error: msg, code };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @param {any} runningManifest
|
|
73
|
+
* @param {string} datasourceKey
|
|
74
|
+
* @returns {any|null}
|
|
75
|
+
*/
|
|
76
|
+
function findDatasourceInRunningManifest(runningManifest, datasourceKey) {
|
|
77
|
+
const dsKey = String(datasourceKey || '').trim();
|
|
78
|
+
const dataSources = runningManifest?.dataSources;
|
|
79
|
+
if (!Array.isArray(dataSources)) return null;
|
|
80
|
+
return dataSources.find((d) => d && d.key === dsKey) || null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
module.exports = {
|
|
84
|
+
tryFetchRunningManifest,
|
|
85
|
+
findDatasourceInRunningManifest,
|
|
86
|
+
/**
|
|
87
|
+
* Fetch one datasource config by key/id using dataplane auth resolved from a systemKey.
|
|
88
|
+
*
|
|
89
|
+
* This is useful for cross-system FK target validation because datasource keys are globally unique.
|
|
90
|
+
*
|
|
91
|
+
* @param {string} systemKey - any system key usable for auth resolution
|
|
92
|
+
* @param {string} datasourceKey - datasource key to fetch config for
|
|
93
|
+
* @param {{ silent?: boolean }} [opts]
|
|
94
|
+
* @returns {Promise<{ ok: true, datasourceConfig: any } | { ok: false, error: string, code?: string }>}
|
|
95
|
+
*/
|
|
96
|
+
async tryFetchDatasourceConfig(systemKey, datasourceKey, opts = {}) {
|
|
97
|
+
try {
|
|
98
|
+
const trimmedSystemKey = String(systemKey || '').trim();
|
|
99
|
+
const trimmedDatasourceKey = String(datasourceKey || '').trim();
|
|
100
|
+
|
|
101
|
+
const { dataplaneUrl, authConfig } = await resolveDataplaneAndAuth(trimmedSystemKey, {
|
|
102
|
+
silent: opts.silent === true
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const res = await getDatasourceConfig(dataplaneUrl, trimmedDatasourceKey, authConfig);
|
|
106
|
+
const outerFailure = unwrapApiFailure(res);
|
|
107
|
+
if (outerFailure.isFailure) {
|
|
108
|
+
return {
|
|
109
|
+
ok: false,
|
|
110
|
+
error: outerFailure.message || `Failed to fetch datasource config: ${trimmedDatasourceKey}`,
|
|
111
|
+
code: failureCodeFrom(outerFailure)
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const cfg = res?.data?.data ?? res?.data ?? res;
|
|
116
|
+
const innerFailure = unwrapApiFailure(cfg);
|
|
117
|
+
if (innerFailure.isFailure) {
|
|
118
|
+
return {
|
|
119
|
+
ok: false,
|
|
120
|
+
error: innerFailure.message || `Failed to fetch datasource config: ${trimmedDatasourceKey}`,
|
|
121
|
+
code: failureCodeFrom(innerFailure)
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return { ok: true, datasourceConfig: cfg };
|
|
126
|
+
} catch (e) {
|
|
127
|
+
const msg = e?.message || String(e);
|
|
128
|
+
const code = /Authentication required\./i.test(msg) ? 'not_authenticated' : undefined;
|
|
129
|
+
return { ok: false, error: msg, code };
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
@@ -534,6 +534,10 @@
|
|
|
534
534
|
"pattern": "^[a-zA-Z.$\\{\\}_-]+$",
|
|
535
535
|
"default": true
|
|
536
536
|
},
|
|
537
|
+
"internalDockerUseOriginOnly": {
|
|
538
|
+
"type": "boolean",
|
|
539
|
+
"description": "When true, declarative url://*-internal full URLs in Docker profile use http://service:containerPort only (omit frontDoorRouting.pattern). Use when the ingress path (e.g. /miso) is not part of in-container routes. Omit or false to keep pattern on internal URLs (e.g. Keycloak /auth)."
|
|
540
|
+
},
|
|
537
541
|
"certStore": {
|
|
538
542
|
"type": "string",
|
|
539
543
|
"description": "Certificate store name for wildcard certificates. Optional - only needed when using a pre-configured certificate store in Traefik.",
|