@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,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Surface expansion + {@link expandResolvedUrlToken} for declarative url:// tokens.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Split from url-declarative-resolve-build.js for ESLint max-lines
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const {
|
|
12
|
+
buildPublicUrlString,
|
|
13
|
+
buildPublicHostOriginString,
|
|
14
|
+
buildInternalHostOriginString,
|
|
15
|
+
buildInternalUrlString
|
|
16
|
+
} = require('./url-declarative-resolve-build-urls');
|
|
17
|
+
const { normalizeRuntimeBasePath } = require('./url-declarative-runtime-base-path');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Published/browser origin port basis for url:// public surfaces (manifest `port`), not container listen.
|
|
21
|
+
* @param {Object} r
|
|
22
|
+
* @returns {number}
|
|
23
|
+
*/
|
|
24
|
+
function publishedOriginPortBasis(r) {
|
|
25
|
+
const b = r.publicPortBasis;
|
|
26
|
+
if (b !== undefined && b !== null && Number.isFinite(Number(b))) {
|
|
27
|
+
return Number(b);
|
|
28
|
+
}
|
|
29
|
+
return r.listenPort;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param {Object} r - resolved app + patternPath + pathPrefix + remoteServer + profile + devNum + derivedEnvKey
|
|
34
|
+
* @returns {string}
|
|
35
|
+
*/
|
|
36
|
+
function expandHostSurfacePublic(r) {
|
|
37
|
+
return buildPublicHostOriginString({
|
|
38
|
+
profile: r.profile,
|
|
39
|
+
listenPort: publishedOriginPortBasis(r),
|
|
40
|
+
developerIdNum: r.devNum,
|
|
41
|
+
remoteServer: r.remoteServer,
|
|
42
|
+
traefik: r.traefik,
|
|
43
|
+
hostTemplate: r.hostTemplate,
|
|
44
|
+
tls: r.tls,
|
|
45
|
+
developerIdRaw: r.developerIdRaw,
|
|
46
|
+
infraTlsEnabled: r.infraTlsEnabled,
|
|
47
|
+
frontDoorIngressActive: r.frontDoorIngressActive,
|
|
48
|
+
declarativeTargetAppKey: r.appKey,
|
|
49
|
+
declarativeCurrentAppKey: r.currentAppKey,
|
|
50
|
+
declarativePublicUrlsUseLocalhost: r.declarativePublicUrlsUseLocalhost
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Local workstation `.env` (no remote-server): browser-reachable URLs only — internal tokens match public.
|
|
56
|
+
* **Docker** profile must keep Docker DNS / service hostnames so resolved `.env` works **inside** containers.
|
|
57
|
+
*
|
|
58
|
+
* @param {Object} r
|
|
59
|
+
* @returns {boolean}
|
|
60
|
+
*/
|
|
61
|
+
function isLocalProfileWithoutRemoteServer(r) {
|
|
62
|
+
return r.profile === 'local' && !String(r.remoteServer || '').trim();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @param {Object} r
|
|
67
|
+
* @returns {string}
|
|
68
|
+
*/
|
|
69
|
+
function expandHostSurfaceInternal(r) {
|
|
70
|
+
if (isLocalProfileWithoutRemoteServer(r)) {
|
|
71
|
+
return expandHostSurfacePublic(r);
|
|
72
|
+
}
|
|
73
|
+
return buildInternalHostOriginString({
|
|
74
|
+
profile: r.profile,
|
|
75
|
+
listenPort: r.listenPort,
|
|
76
|
+
targetAppKey: r.appKey,
|
|
77
|
+
remoteServer: r.remoteServer,
|
|
78
|
+
pathPrefix: r.pathPrefix,
|
|
79
|
+
patternPath: r.patternPath,
|
|
80
|
+
developerIdNum: r.devNum,
|
|
81
|
+
derivedEnvKey: r.derivedEnvKey,
|
|
82
|
+
traefik: r.traefik,
|
|
83
|
+
hostTemplate: r.hostTemplate,
|
|
84
|
+
tls: r.tls,
|
|
85
|
+
developerIdRaw: r.developerIdRaw,
|
|
86
|
+
infraTlsEnabled: r.infraTlsEnabled,
|
|
87
|
+
frontDoorIngressActive: r.frontDoorIngressActive,
|
|
88
|
+
declarativeTargetAppKey: r.appKey,
|
|
89
|
+
declarativeCurrentAppKey: r.currentAppKey,
|
|
90
|
+
declarativePublicUrlsUseLocalhost: r.declarativePublicUrlsUseLocalhost
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param {Object} r
|
|
96
|
+
* @returns {string}
|
|
97
|
+
*/
|
|
98
|
+
function expandFullSurfacePublic(r) {
|
|
99
|
+
return buildPublicUrlString({
|
|
100
|
+
profile: r.profile,
|
|
101
|
+
listenPort: publishedOriginPortBasis(r),
|
|
102
|
+
developerIdNum: r.devNum,
|
|
103
|
+
remoteServer: r.remoteServer,
|
|
104
|
+
pathPrefix: r.pathPrefix,
|
|
105
|
+
patternPath: r.patternPath,
|
|
106
|
+
traefik: r.traefik,
|
|
107
|
+
hostTemplate: r.hostTemplate,
|
|
108
|
+
tls: r.tls,
|
|
109
|
+
developerIdRaw: r.developerIdRaw,
|
|
110
|
+
infraTlsEnabled: r.infraTlsEnabled,
|
|
111
|
+
frontDoorIngressActive: r.frontDoorIngressActive,
|
|
112
|
+
declarativeTargetAppKey: r.appKey,
|
|
113
|
+
declarativeCurrentAppKey: r.currentAppKey,
|
|
114
|
+
declarativePublicUrlsUseLocalhost: r.declarativePublicUrlsUseLocalhost
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* @param {Object} r
|
|
120
|
+
* @returns {string}
|
|
121
|
+
*/
|
|
122
|
+
function expandFullSurfaceInternal(r) {
|
|
123
|
+
if (isLocalProfileWithoutRemoteServer(r)) {
|
|
124
|
+
return expandFullSurfacePublic(r);
|
|
125
|
+
}
|
|
126
|
+
const useOriginOnly =
|
|
127
|
+
r.profile === 'docker' && Boolean(r.internalDockerUseOriginOnly);
|
|
128
|
+
const runtimePath = useOriginOnly
|
|
129
|
+
? ''
|
|
130
|
+
: normalizeRuntimeBasePath(r.patternPath, r);
|
|
131
|
+
return buildInternalUrlString({
|
|
132
|
+
profile: r.profile,
|
|
133
|
+
listenPort: r.listenPort,
|
|
134
|
+
targetAppKey: r.appKey,
|
|
135
|
+
runtimeBasePath: runtimePath,
|
|
136
|
+
remoteServer: r.remoteServer,
|
|
137
|
+
pathPrefix: r.pathPrefix,
|
|
138
|
+
patternPath: r.patternPath,
|
|
139
|
+
developerIdNum: r.devNum,
|
|
140
|
+
derivedEnvKey: r.derivedEnvKey,
|
|
141
|
+
traefik: r.traefik,
|
|
142
|
+
hostTemplate: r.hostTemplate,
|
|
143
|
+
tls: r.tls,
|
|
144
|
+
developerIdRaw: r.developerIdRaw,
|
|
145
|
+
infraTlsEnabled: r.infraTlsEnabled,
|
|
146
|
+
frontDoorIngressActive: r.frontDoorIngressActive,
|
|
147
|
+
declarativeTargetAppKey: r.appKey,
|
|
148
|
+
declarativeCurrentAppKey: r.currentAppKey,
|
|
149
|
+
declarativePublicUrlsUseLocalhost: r.declarativePublicUrlsUseLocalhost
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @param {{ kind: string, surface: string }} parsed
|
|
155
|
+
* @param {Object} r
|
|
156
|
+
* @returns {string}
|
|
157
|
+
*/
|
|
158
|
+
function expandResolvedUrlToken(parsed, r) {
|
|
159
|
+
if (parsed.surface === 'vdir') {
|
|
160
|
+
if (!r.frontDoorIngressActive) {
|
|
161
|
+
return '';
|
|
162
|
+
}
|
|
163
|
+
// Plan 124: docker PRIVATEVDIR is always empty; public vdir still carries pattern
|
|
164
|
+
if (parsed.kind === 'internal' && r.profile === 'docker') {
|
|
165
|
+
return '';
|
|
166
|
+
}
|
|
167
|
+
const prefix = String(r.pathPrefix || '');
|
|
168
|
+
const pat = r.patternPath || '/';
|
|
169
|
+
if (!pat || pat === '/') {
|
|
170
|
+
return prefix || '';
|
|
171
|
+
}
|
|
172
|
+
const joined = `${prefix}${pat}`.replace(/\/{2,}/g, '/');
|
|
173
|
+
return joined.startsWith('/') ? joined : `/${joined}`;
|
|
174
|
+
}
|
|
175
|
+
if (parsed.surface === 'host') {
|
|
176
|
+
return parsed.kind === 'public' ? expandHostSurfacePublic(r) : expandHostSurfaceInternal(r);
|
|
177
|
+
}
|
|
178
|
+
return parsed.kind === 'public' ? expandFullSurfacePublic(r) : expandFullSurfaceInternal(r);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
module.exports = {
|
|
182
|
+
publishedOriginPortBasis,
|
|
183
|
+
isLocalProfileWithoutRemoteServer,
|
|
184
|
+
expandHostSurfacePublic,
|
|
185
|
+
expandHostSurfaceInternal,
|
|
186
|
+
expandFullSurfacePublic,
|
|
187
|
+
expandFullSurfaceInternal,
|
|
188
|
+
expandResolvedUrlToken
|
|
189
|
+
};
|
|
@@ -29,11 +29,16 @@ function tryReadApplicationYamlAt(cfgPath) {
|
|
|
29
29
|
* Prefer projectRoot/builder (fixtures, tests); then {@link pathsUtil.getBuilderPath} (global npm).
|
|
30
30
|
* @param {string} appKey
|
|
31
31
|
* @param {object} pathsUtil
|
|
32
|
+
* @param {string|null|undefined} [projectRootOverride] - When set (e.g. `ctx.projectRoot`), used instead of {@link pathsUtil.getProjectRoot} for the first candidate path (avoids flaky cross-test `paths` mocks).
|
|
32
33
|
* @returns {string[]}
|
|
33
34
|
*/
|
|
34
|
-
function collectApplicationYamlPathsForUrlResolve(appKey, pathsUtil) {
|
|
35
|
+
function collectApplicationYamlPathsForUrlResolve(appKey, pathsUtil, projectRootOverride) {
|
|
35
36
|
const list = [];
|
|
36
|
-
const
|
|
37
|
+
const trimmed =
|
|
38
|
+
projectRootOverride !== undefined && projectRootOverride !== null
|
|
39
|
+
? String(projectRootOverride).trim()
|
|
40
|
+
: '';
|
|
41
|
+
const root = trimmed || pathsUtil.getProjectRoot();
|
|
37
42
|
if (root) {
|
|
38
43
|
list.push(path.resolve(path.join(root, 'builder', appKey, 'application.yaml')));
|
|
39
44
|
}
|
|
@@ -64,7 +69,11 @@ function loadApplicationYamlDocForUrlResolve(appKey, ctx, pathsUtil) {
|
|
|
64
69
|
return fromVars;
|
|
65
70
|
}
|
|
66
71
|
}
|
|
67
|
-
|
|
72
|
+
const pr =
|
|
73
|
+
ctx && ctx.projectRoot !== undefined && ctx.projectRoot !== null
|
|
74
|
+
? String(ctx.projectRoot).trim()
|
|
75
|
+
: '';
|
|
76
|
+
for (const cfgPath of collectApplicationYamlPathsForUrlResolve(appKey, pathsUtil, pr || undefined)) {
|
|
68
77
|
const doc = tryReadApplicationYamlAt(cfgPath);
|
|
69
78
|
if (doc) {
|
|
70
79
|
return doc;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declarative url:// **surface state machine** (plan 124 + per-app `applications.<app>.proxy`).
|
|
3
|
+
*
|
|
4
|
+
* FSM inputs (per token target): `perTokenTraefik`, `frontDoorRoutingEnabled` (strict true in yaml).
|
|
5
|
+
* Output phase is the product space (see `PHASE_BY_TRAEFIK_AND_FRONT_DOOR`); `pathActive` matches
|
|
6
|
+
* {@link computePathActive}(perTokenTraefik, frontDoorRoutingEnabled).
|
|
7
|
+
*
|
|
8
|
+
* @fileoverview Single source for `perTokenTraefik` × `frontDoorRouting.enabled` → phase + `pathActive`
|
|
9
|
+
* @author AI Fabrix Team
|
|
10
|
+
* @version 1.0.0
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
const { isDeclarativeTraefikUrlsEnabled } = require('./applications-config-defaults');
|
|
16
|
+
const { computePathActive } = require('./url-declarative-url-flags');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Public URL surface phase for one url:// token target app.
|
|
20
|
+
* @readonly
|
|
21
|
+
* @enum {string}
|
|
22
|
+
*/
|
|
23
|
+
const DeclarativeUrlSurfacePhase = {
|
|
24
|
+
/** No Traefik-style hints for this token (`perTokenTraefik` false). */
|
|
25
|
+
DIRECT: 'DIRECT',
|
|
26
|
+
/** Traefik on for Plan 117 path prefix, but `frontDoorRouting.enabled` is not true — no ingress path. */
|
|
27
|
+
TRAEFIK_SCOPED: 'TRAEFIK_SCOPED',
|
|
28
|
+
/** Traefik + front door enabled — `pathActive` / pattern + vdir-public behave as ingress. */
|
|
29
|
+
FRONT_DOOR: 'FRONT_DOOR'
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @typedef {Object} DeclarativeUrlSurfaceInputs
|
|
34
|
+
* @property {Object|null|undefined} userCfg - `~/.aifabrix/config.yaml` root when resolve passes it
|
|
35
|
+
* @property {string} appKey - Target app for the url:// token
|
|
36
|
+
* @property {boolean|undefined} ctxTraefik - Legacy global flag when `userCfg` is absent
|
|
37
|
+
* @property {boolean} frontDoorRoutingEnabled - From `application.yaml` `frontDoorRouting.enabled === true`
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Bit-pair → phase lookup (explicit FSM output table).
|
|
42
|
+
* Keys: `${perTokenTraefik}:${frontDoorRoutingEnabled}` (booleans coerced to strings).
|
|
43
|
+
*
|
|
44
|
+
* @type {Object.<string, keyof typeof DeclarativeUrlSurfacePhase>}
|
|
45
|
+
*/
|
|
46
|
+
const PHASE_BY_TRAEFIK_AND_FRONT_DOOR = {
|
|
47
|
+
'false:false': DeclarativeUrlSurfacePhase.DIRECT,
|
|
48
|
+
'false:true': DeclarativeUrlSurfacePhase.DIRECT,
|
|
49
|
+
'true:false': DeclarativeUrlSurfacePhase.TRAEFIK_SCOPED,
|
|
50
|
+
'true:true': DeclarativeUrlSurfacePhase.FRONT_DOOR
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @param {boolean} perTokenTraefik
|
|
55
|
+
* @param {boolean} frontDoorRoutingEnabled
|
|
56
|
+
* @returns {string} {@link DeclarativeUrlSurfacePhase}
|
|
57
|
+
*/
|
|
58
|
+
function phaseFromTraefikAndFrontDoor(perTokenTraefik, frontDoorRoutingEnabled) {
|
|
59
|
+
const k = `${Boolean(perTokenTraefik)}:${Boolean(frontDoorRoutingEnabled)}`;
|
|
60
|
+
const phase = PHASE_BY_TRAEFIK_AND_FRONT_DOOR[k];
|
|
61
|
+
return phase || DeclarativeUrlSurfacePhase.DIRECT;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Whether Traefik-style URL hints apply for this token (infra + per-app proxy, or legacy `ctx.traefik`).
|
|
66
|
+
*
|
|
67
|
+
* @param {DeclarativeUrlSurfaceInputs} input
|
|
68
|
+
* @returns {boolean}
|
|
69
|
+
*/
|
|
70
|
+
function resolvePerTokenTraefik(input) {
|
|
71
|
+
const { userCfg, appKey, ctxTraefik } = input;
|
|
72
|
+
if (userCfg && appKey) {
|
|
73
|
+
return isDeclarativeTraefikUrlsEnabled(userCfg, appKey);
|
|
74
|
+
}
|
|
75
|
+
return Boolean(ctxTraefik);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Resolve surface phase and derived flags for one declarative url:// target.
|
|
80
|
+
*
|
|
81
|
+
* @param {DeclarativeUrlSurfaceInputs} input
|
|
82
|
+
* @returns {{
|
|
83
|
+
* phase: string,
|
|
84
|
+
* perTokenTraefik: boolean,
|
|
85
|
+
* frontDoorIngressActive: boolean
|
|
86
|
+
* }}
|
|
87
|
+
*/
|
|
88
|
+
function resolveDeclarativeUrlSurfaceState(input) {
|
|
89
|
+
const frontDoorRoutingEnabled = Boolean(input.frontDoorRoutingEnabled);
|
|
90
|
+
const perTokenTraefik = resolvePerTokenTraefik(input);
|
|
91
|
+
const phase = phaseFromTraefikAndFrontDoor(perTokenTraefik, frontDoorRoutingEnabled);
|
|
92
|
+
const frontDoorIngressActive = computePathActive(perTokenTraefik, frontDoorRoutingEnabled);
|
|
93
|
+
return { phase, perTokenTraefik, frontDoorIngressActive };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
module.exports = {
|
|
97
|
+
DeclarativeUrlSurfacePhase,
|
|
98
|
+
PHASE_BY_TRAEFIK_AND_FRONT_DOOR,
|
|
99
|
+
phaseFromTraefikAndFrontDoor,
|
|
100
|
+
resolvePerTokenTraefik,
|
|
101
|
+
resolveDeclarativeUrlSurfaceState
|
|
102
|
+
};
|
|
@@ -17,6 +17,9 @@ const { computeDeclarativePathPrefix } = require('./url-declarative-url-flags');
|
|
|
17
17
|
const { refreshUrlsLocalRegistryFromBuilder, normalizePatternForUrl } = require('./urls-local-registry');
|
|
18
18
|
const pathsUtil = require('./paths');
|
|
19
19
|
const { parseUrlToken } = require('./url-declarative-token-parse');
|
|
20
|
+
const {
|
|
21
|
+
getApplicationsRunProxyHint
|
|
22
|
+
} = require('./applications-config-defaults');
|
|
20
23
|
const {
|
|
21
24
|
applyTstRemoteDeveloperHost,
|
|
22
25
|
applyTstRemoteDeveloperHostToOrigin,
|
|
@@ -100,6 +103,27 @@ function readTargetAppScopedFlag(targetAppKey) {
|
|
|
100
103
|
}
|
|
101
104
|
}
|
|
102
105
|
|
|
106
|
+
/**
|
|
107
|
+
* When global `traefik` is **false** in user config, public bases never use `remote-server`.
|
|
108
|
+
* Otherwise follows per-app `proxy` or legacy `ctx.declarativePublicUrlsUseLocalhost`.
|
|
109
|
+
*
|
|
110
|
+
* @param {Object} ctx
|
|
111
|
+
* @param {string} [appKey]
|
|
112
|
+
* @returns {boolean|undefined}
|
|
113
|
+
*/
|
|
114
|
+
function resolveDeclarativePublicLocalhostFlag(ctx, appKey) {
|
|
115
|
+
if (ctx.userCfg && ctx.userCfg.traefik === false) {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
if (ctx.userCfg && appKey) {
|
|
119
|
+
return !getApplicationsRunProxyHint(ctx.userCfg, appKey);
|
|
120
|
+
}
|
|
121
|
+
if (ctx.declarativePublicUrlsUseLocalhost === undefined) {
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
return Boolean(ctx.declarativePublicUrlsUseLocalhost);
|
|
125
|
+
}
|
|
126
|
+
|
|
103
127
|
/**
|
|
104
128
|
* Resolve one url:// token to a concrete URL string.
|
|
105
129
|
* @param {string} token
|
|
@@ -123,14 +147,18 @@ function replaceUrlRefToken(token, ctx, profile, devNum, derivedEnvKey, registry
|
|
|
123
147
|
patternStr,
|
|
124
148
|
hostTemplate,
|
|
125
149
|
tls,
|
|
126
|
-
frontDoorIngressActive
|
|
150
|
+
frontDoorIngressActive,
|
|
151
|
+
perTokenTraefik,
|
|
152
|
+
internalDockerUseOriginOnly
|
|
127
153
|
} = resolved;
|
|
154
|
+
const traefikForToken = perTokenTraefik;
|
|
155
|
+
const declarativePublicUrlsUseLocalhostForToken = resolveDeclarativePublicLocalhostFlag(ctx, appKey);
|
|
128
156
|
const patternPath = normalizePatternForUrl(patternStr);
|
|
129
157
|
const appScoped = parsed.targetKey
|
|
130
158
|
? readTargetAppScopedFlag(parsed.targetKey)
|
|
131
159
|
: Boolean(ctx.appEnvironmentScopedResources);
|
|
132
160
|
const pathPrefix = computeDeclarativePathPrefix(
|
|
133
|
-
|
|
161
|
+
traefikForToken,
|
|
134
162
|
ctx.useEnvironmentScopedResources,
|
|
135
163
|
appScoped,
|
|
136
164
|
derivedEnvKey
|
|
@@ -146,12 +174,14 @@ function replaceUrlRefToken(token, ctx, profile, devNum, derivedEnvKey, registry
|
|
|
146
174
|
remoteServer: ctx.remoteServer,
|
|
147
175
|
devNum,
|
|
148
176
|
derivedEnvKey,
|
|
149
|
-
traefik:
|
|
177
|
+
traefik: traefikForToken,
|
|
150
178
|
hostTemplate,
|
|
151
179
|
tls,
|
|
152
180
|
frontDoorIngressActive,
|
|
153
181
|
developerIdRaw: ctx.developerIdRaw,
|
|
154
|
-
infraTlsEnabled: Boolean(ctx.infraTlsEnabled)
|
|
182
|
+
infraTlsEnabled: Boolean(ctx.infraTlsEnabled),
|
|
183
|
+
internalDockerUseOriginOnly,
|
|
184
|
+
declarativePublicUrlsUseLocalhost: declarativePublicUrlsUseLocalhostForToken
|
|
155
185
|
});
|
|
156
186
|
}
|
|
157
187
|
|
|
@@ -168,8 +198,12 @@ function replaceUrlRefToken(token, ctx, profile, devNum, derivedEnvKey, registry
|
|
|
168
198
|
* @param {boolean} ctx.appEnvironmentScopedResources
|
|
169
199
|
* @param {string|null|undefined} ctx.remoteServer
|
|
170
200
|
* @param {string|number|null|undefined} ctx.developerIdRaw
|
|
171
|
-
* @param {boolean} [ctx.traefik] -
|
|
172
|
-
* @param {boolean} [ctx.
|
|
201
|
+
* @param {boolean} [ctx.traefik] - When `ctx.userCfg` is absent: global Traefik-style URL flag. When `ctx.userCfg` is set: `ctx.traefik` is ignored for per-token Traefik; see {@link resolveDeclarativeUrlSurfaceState}.
|
|
202
|
+
* @param {boolean|undefined} [ctx.declarativePublicUrlsUseLocalhost] - When `ctx.userCfg` is absent: **`undefined`** (default) skips `remote-server` when Traefik is off; **`true`** forces localhost; **`false`** allows remote authority without Traefik. When `ctx.userCfg` is set and root **`traefik` is not** `false`: ignored for public bases; derived per target app from `applications.<target>.proxy`. When **`ctx.userCfg.traefik === false`**, public bases always use localhost (per-app `proxy` does not opt into `remote-server` without infra Traefik).
|
|
203
|
+
* @param {Object} [ctx.userCfg] - `~/.aifabrix/config.yaml` root; when set, `applications.<app>.proxy` and `traefik` apply per **target** app for each `url://` token (so e.g. Keycloak URLs follow `applications.keycloak`, not only the app being resolved), except public authority stays on localhost when root `traefik` is **`false`**.
|
|
204
|
+
* @param {string|null|undefined} [ctx.projectRoot] - Optional absolute project root for `builder/<app>/application.yaml` discovery and `urls.local.yaml` refresh; when set, avoids relying on `paths.getProjectRoot()` (stable under cross-test `paths` mocks).
|
|
205
|
+
* @param {boolean} [ctx.excludeCwdBuilderScan] - When **true**, {@link refreshUrlsLocalRegistryFromBuilder} omits the cwd checkout **`builder/`** directory from the canonical scan list (tests / isolated fixtures that must not merge the ambient repo `builder/` into `urls.local.yaml`). Omit or **false** for normal CLI and `.env` expansion.
|
|
206
|
+
* @param {boolean} [ctx.infraTlsEnabled] - When true (`tlsEnabled` in config / `up-infra --tls`), Traefik front-door `url://public` uses **https**; when **false**, front-door bases use **http** (regardless of `frontDoorRouting.tls`). Loopback hosts stay **http**.
|
|
173
207
|
* @returns {Promise<string>}
|
|
174
208
|
*/
|
|
175
209
|
async function expandDeclarativeUrlsInEnvContent(content, ctx) {
|
|
@@ -182,7 +216,13 @@ async function expandDeclarativeUrlsInEnvContent(content, ctx) {
|
|
|
182
216
|
const clientId = envMap.MISO_CLIENTID;
|
|
183
217
|
const pipelineOverride = envMap.MISO_PIPELINE_ENV_KEY;
|
|
184
218
|
const derivedEnvKey = deriveEnvKeyFromClientId(clientId, pipelineOverride);
|
|
185
|
-
const
|
|
219
|
+
const pr =
|
|
220
|
+
ctx.projectRoot !== undefined && ctx.projectRoot !== null ? String(ctx.projectRoot).trim() : '';
|
|
221
|
+
const registryRoot = pr || pathsUtil.getProjectRoot();
|
|
222
|
+
const registry =
|
|
223
|
+
ctx.excludeCwdBuilderScan === true
|
|
224
|
+
? refreshUrlsLocalRegistryFromBuilder(registryRoot, { excludeCwdBuilderScan: true })
|
|
225
|
+
: refreshUrlsLocalRegistryFromBuilder(registryRoot);
|
|
186
226
|
|
|
187
227
|
const lines = content.split('\n');
|
|
188
228
|
const outLines = lines.map((line) => {
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime base path helpers for declarative url:// resolution.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Keeps path-aware internal URLs out of the main resolver file.
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Runtime base path is derived from the existing frontDoorRouting path only
|
|
13
|
+
* when that path is active for the target app.
|
|
14
|
+
* @param {string|null|undefined} patternPath
|
|
15
|
+
* @param {Object} r
|
|
16
|
+
* @returns {string}
|
|
17
|
+
*/
|
|
18
|
+
function normalizeRuntimeBasePath(patternPath, r) {
|
|
19
|
+
if (!r.frontDoorIngressActive) {
|
|
20
|
+
return '';
|
|
21
|
+
}
|
|
22
|
+
const value = String(patternPath || '').trim();
|
|
23
|
+
if (!value || value === '/') {
|
|
24
|
+
return '';
|
|
25
|
+
}
|
|
26
|
+
const pathValue = value.startsWith('/') ? value : `/${value}`;
|
|
27
|
+
return pathValue.replace(/\/{2,}/g, '/').replace(/\/+$/, '');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Read front-door host/TLS and optional internal-Docker origin-only flag from application.yaml.
|
|
32
|
+
* @param {object|null|undefined} doc
|
|
33
|
+
* @returns {{ hostTemplate: string|null, tls: boolean, internalDockerUseOriginOnly: boolean }}
|
|
34
|
+
*/
|
|
35
|
+
function readFrontDoorHostTlsFromDoc(doc) {
|
|
36
|
+
if (!doc || !doc.frontDoorRouting) {
|
|
37
|
+
return { hostTemplate: null, tls: true, internalDockerUseOriginOnly: false };
|
|
38
|
+
}
|
|
39
|
+
const fd = doc.frontDoorRouting;
|
|
40
|
+
const hostTemplate =
|
|
41
|
+
typeof fd.host === 'string' && fd.host.trim() ? fd.host.trim() : null;
|
|
42
|
+
return {
|
|
43
|
+
hostTemplate,
|
|
44
|
+
tls: fd.tls !== false,
|
|
45
|
+
internalDockerUseOriginOnly: fd.internalDockerUseOriginOnly === true
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module.exports = {
|
|
50
|
+
normalizeRuntimeBasePath,
|
|
51
|
+
readFrontDoorHostTlsFromDoc
|
|
52
|
+
};
|
|
@@ -95,5 +95,6 @@ module.exports = {
|
|
|
95
95
|
URL_DECLARATIVE_VDIR_PUBLIC_TOKEN,
|
|
96
96
|
INACTIVE_VDIR_PUBLIC_ENV_FALLBACK,
|
|
97
97
|
applyInactiveVdirPublicTokenRewrite,
|
|
98
|
-
rewriteInactiveDeclarativeVdirPublicContent
|
|
98
|
+
rewriteInactiveDeclarativeVdirPublicContent,
|
|
99
|
+
isFrontDoorRoutingEnabledInDoc
|
|
99
100
|
};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builder-directory scan for {@link module:lib/utils/urls-local-registry} refresh.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Collect application config per app key across builder roots (plan 141 P3: scan order
|
|
5
|
+
* defines precedence; later directories override earlier ones for the same `app.key`).
|
|
6
|
+
* @author AI Fabrix Team
|
|
7
|
+
* @version 1.0.0
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const fsRealSync = require('../internal/fs-real-sync');
|
|
14
|
+
const { resolveApplicationConfigPath } = require('./app-config-resolver');
|
|
15
|
+
const { loadConfigFile } = require('./config-format');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {string} appDir - Absolute path to a builder app folder (directory containing application config)
|
|
19
|
+
* @returns {{ doc: object }|null}
|
|
20
|
+
*/
|
|
21
|
+
function tryGetApplicationDirConfigForRegistry(appDir) {
|
|
22
|
+
let cfgPath;
|
|
23
|
+
try {
|
|
24
|
+
cfgPath = resolveApplicationConfigPath(appDir);
|
|
25
|
+
} catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
if (!fsRealSync.existsSync(cfgPath)) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
let doc;
|
|
32
|
+
try {
|
|
33
|
+
doc = loadConfigFile(cfgPath);
|
|
34
|
+
} catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
if (!doc || typeof doc !== 'object') {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
return { doc };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @param {string} builderDir
|
|
45
|
+
* @param {import('fs').Dirent} ent
|
|
46
|
+
* @param {number} dirIndex
|
|
47
|
+
* @param {Map<string, { folderName: string, doc: object, dirIndex: number }>} best
|
|
48
|
+
*/
|
|
49
|
+
function maybeUpdateBestFromAppFolder(builderDir, ent, dirIndex, best) {
|
|
50
|
+
const appDir = path.join(builderDir, ent.name);
|
|
51
|
+
const entry = tryGetApplicationDirConfigForRegistry(appDir);
|
|
52
|
+
if (!entry) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const { doc } = entry;
|
|
56
|
+
const appKey = (doc.app && doc.app.key) || ent.name;
|
|
57
|
+
const cur = best.get(appKey);
|
|
58
|
+
if (!cur || dirIndex > cur.dirIndex) {
|
|
59
|
+
best.set(appKey, { folderName: ent.name, doc, dirIndex });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @param {string} builderDir
|
|
65
|
+
* @param {number} dirIndex
|
|
66
|
+
* @param {Map<string, { folderName: string, doc: object, dirIndex: number }>} best
|
|
67
|
+
*/
|
|
68
|
+
function mergeBuilderDirScanIntoBestMap(builderDir, dirIndex, best) {
|
|
69
|
+
if (!builderDir || typeof builderDir !== 'string') {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (!fsRealSync.existsSync(builderDir) || !fsRealSync.statSync(builderDir).isDirectory()) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
for (const ent of fsRealSync.readdirSync(builderDir, { withFileTypes: true })) {
|
|
76
|
+
if (!ent.isDirectory()) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
maybeUpdateBestFromAppFolder(builderDir, ent, dirIndex, best);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* When the same app exists under multiple builder roots, the **last** directory in `scanDirs`
|
|
85
|
+
* wins (highest `dirIndex`). Matches plan 141 canonical precedence (checkout / cwd after system materialization).
|
|
86
|
+
*
|
|
87
|
+
* @param {string[]} scanDirs - Builder or `packages` directories, low → high priority
|
|
88
|
+
* @returns {Array<{ folderName: string, doc: object }>}
|
|
89
|
+
*/
|
|
90
|
+
function collectLatestApplicationYamlEntriesPerApp(scanDirs) {
|
|
91
|
+
/** @type {Map<string, { folderName: string, doc: object, dirIndex: number }>} */
|
|
92
|
+
const best = new Map();
|
|
93
|
+
scanDirs.forEach((builderDir, dirIndex) => {
|
|
94
|
+
mergeBuilderDirScanIntoBestMap(builderDir, dirIndex, best);
|
|
95
|
+
});
|
|
96
|
+
return [...best.entries()]
|
|
97
|
+
.sort((a, b) => a[0].localeCompare(b[0]))
|
|
98
|
+
.map(([, v]) => ({ folderName: v.folderName, doc: v.doc }));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
module.exports = {
|
|
102
|
+
collectLatestApplicationYamlEntriesPerApp
|
|
103
|
+
};
|