@aifabrix/builder 2.43.0 → 2.44.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/.cursor/rules/anchor-docs.mdc +15 -0
- package/.cursor/rules/cli-layout.mdc +75 -0
- package/.cursor/rules/project-rules.mdc +8 -0
- package/.npmrc.token +1 -0
- package/.nyc_output/55e9d034-ddab-4579-a706-e02a91d75c91.json +1 -0
- package/.nyc_output/processinfo/55e9d034-ddab-4579-a706-e02a91d75c91.json +1 -0
- package/.nyc_output/processinfo/index.json +1 -0
- package/README.md +1 -1
- package/anchor-docs/README.md +10 -0
- package/anchor-docs/_TEMPLATE +24 -0
- package/bin/aifabrix.js +13 -4
- package/integration/hubspot-test/README.md +31 -0
- package/integration/hubspot-test/create-hubspot.js +5 -5
- package/integration/hubspot-test/hubspot-test-datasource-company.json +58 -462
- package/integration/hubspot-test/hubspot-test-datasource-contact.json +61 -555
- package/integration/hubspot-test/hubspot-test-datasource-deal.json +63 -506
- package/integration/hubspot-test/hubspot-test-datasource-users.json +42 -83
- package/integration/hubspot-test/hubspot-test-deploy.json +3 -3
- package/integration/hubspot-test/test-dataplane-down-tests.js +1 -7
- package/integration/hubspot-test/test-dataplane-down.js +3 -3
- package/integration/hubspot-test/test.js +35 -43
- package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +23 -0
- package/integration/roundtrip-test-local/README.md +144 -0
- package/integration/roundtrip-test-local/application.yaml +13 -0
- package/integration/roundtrip-test-local/env.template +15 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +14 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +61 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +25 -0
- package/integration/roundtrip-test-local2/README.md +144 -0
- package/integration/roundtrip-test-local2/application.yaml +13 -0
- package/integration/roundtrip-test-local2/env.template +15 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +31 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +86 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +25 -0
- package/integration/test/wizard.yaml +8 -0
- package/jest.config.default.js +10 -0
- package/jest.config.integration.fixtures.js +22 -0
- package/jest.config.integration.js +21 -18
- package/jest.config.isolated.js +10 -0
- package/jest.projects.js +301 -0
- package/lib/api/certificates.api.js +62 -0
- package/lib/api/datasources-core.api.js +3 -3
- package/lib/api/dev-mtls-request.js +110 -0
- package/lib/api/dev-server-https.js +145 -0
- package/lib/api/dev.api.js +133 -144
- package/lib/api/index.js +11 -3
- package/lib/api/pipeline.api.js +67 -20
- package/lib/api/types/certificates.types.js +48 -0
- package/lib/api/types/dev.types.js +4 -3
- package/lib/api/types/pipeline.types.js +8 -5
- package/lib/api/types/validation-run.types.js +56 -0
- package/lib/api/validation-run.api.js +111 -0
- package/lib/api/validation-runner.js +109 -0
- package/lib/app/certification-show-enrich.js +129 -0
- package/lib/app/certification-verify-rows.js +60 -0
- package/lib/app/config.js +1 -1
- package/lib/app/deploy-status-display.js +2 -2
- package/lib/app/deploy.js +7 -6
- package/lib/app/display.js +2 -1
- package/lib/app/dockerfile.js +3 -2
- package/lib/app/down.js +2 -1
- package/lib/app/helpers.js +6 -5
- package/lib/app/index.js +27 -8
- package/lib/app/list.js +7 -6
- package/lib/app/push.js +4 -3
- package/lib/app/register.js +16 -7
- package/lib/app/rotate-secret.js +14 -13
- package/lib/app/run-container-start.js +184 -0
- package/lib/app/run-docker-fallback.js +108 -0
- package/lib/app/run-env-compose.js +30 -42
- package/lib/app/run-helpers.js +49 -126
- package/lib/app/run-infra-requirements.js +30 -0
- package/lib/app/run-resolve-image.js +21 -0
- package/lib/app/run.js +74 -21
- package/lib/app/show-display.js +44 -1
- package/lib/app/show.js +93 -9
- package/lib/build/index.js +13 -10
- package/lib/certification/cli-cert-sync-skip.js +21 -0
- package/lib/certification/merge-certification-from-artifact.js +185 -0
- package/lib/certification/post-unified-cert-sync.js +33 -0
- package/lib/certification/sync-after-external-command.js +52 -0
- package/lib/certification/sync-system-certification.js +197 -0
- package/lib/cli/index.js +2 -0
- package/lib/cli/setup-app.help.js +67 -0
- package/lib/cli/setup-app.js +61 -121
- package/lib/cli/setup-app.test-commands.js +195 -0
- package/lib/cli/setup-auth.js +19 -5
- package/lib/cli/setup-credential-deployment.js +22 -8
- package/lib/cli/setup-dev-path-commands.js +124 -0
- package/lib/cli/setup-dev.js +170 -113
- package/lib/cli/setup-environment.js +7 -1
- package/lib/cli/setup-external-system.js +84 -23
- package/lib/cli/setup-infra.js +126 -47
- package/lib/cli/setup-parameters.js +32 -0
- package/lib/cli/setup-secrets.js +137 -18
- package/lib/cli/setup-service-user.js +1 -1
- package/lib/cli/setup-utility.js +54 -22
- package/lib/commands/app-down.js +5 -7
- package/lib/commands/app-install.js +14 -7
- package/lib/commands/app-logs.js +13 -10
- package/lib/commands/app-shell.js +4 -1
- package/lib/commands/app-test.js +25 -19
- package/lib/commands/app.js +32 -11
- package/lib/commands/auth-config.js +6 -6
- package/lib/commands/auth-status.js +4 -3
- package/lib/commands/credential-env.js +4 -3
- package/lib/commands/credential-list.js +5 -4
- package/lib/commands/credential-push.js +4 -3
- package/lib/commands/datasource-unified-test-cli.js +428 -0
- package/lib/commands/datasource-unified-test-cli.options.js +191 -0
- package/lib/commands/datasource-unified-test-e2e-cli-helpers.js +106 -0
- package/lib/commands/datasource-validation-cli.js +143 -0
- package/lib/commands/datasource.js +125 -95
- package/lib/commands/deployment-list.js +6 -5
- package/lib/commands/dev-cli-handlers.js +122 -18
- package/lib/commands/dev-down.js +4 -3
- package/lib/commands/dev-init.js +231 -116
- package/lib/commands/dev-show-display.js +473 -0
- package/lib/commands/login-credentials.js +3 -2
- package/lib/commands/login-device.js +4 -3
- package/lib/commands/login.js +5 -4
- package/lib/commands/logout.js +8 -7
- package/lib/commands/parameters-validate.js +54 -0
- package/lib/commands/repair-datasource.js +314 -68
- package/lib/commands/repair-env-template.js +2 -2
- package/lib/commands/repair.js +21 -3
- package/lib/commands/secrets-list.js +23 -12
- package/lib/commands/secrets-remove-all.js +220 -0
- package/lib/commands/secrets-remove.js +21 -12
- package/lib/commands/secrets-set.js +21 -12
- package/lib/commands/secrets-validate.js +4 -4
- package/lib/commands/secure.js +10 -9
- package/lib/commands/service-user.js +26 -25
- package/lib/commands/test-e2e-external.js +27 -1
- package/lib/commands/up-common.js +3 -2
- package/lib/commands/up-dataplane.js +29 -16
- package/lib/commands/up-miso.js +19 -29
- package/lib/commands/upload.js +149 -39
- package/lib/commands/wizard-core-helpers.js +1 -1
- package/lib/commands/wizard-dataplane.js +4 -3
- package/lib/commands/wizard-helpers.js +3 -3
- package/lib/commands/wizard.js +2 -2
- package/lib/core/admin-secrets.js +14 -5
- package/lib/core/audit-logger.js +12 -4
- package/lib/core/config-attach-extensions.js +46 -0
- package/lib/core/config-runtime-paths.js +29 -0
- package/lib/core/config.js +55 -56
- package/lib/core/diff.js +3 -2
- package/lib/core/ensure-encryption-key.js +1 -1
- package/lib/core/secrets-ensure-infra.js +77 -0
- package/lib/core/secrets-ensure.js +120 -64
- package/lib/core/secrets-env-write.js +35 -7
- package/lib/core/secrets-infra-placeholder-sync.js +61 -0
- package/lib/core/secrets.js +200 -37
- package/lib/core/templates-env.js +4 -3
- package/lib/datasource/abac-validator.js +1 -10
- package/lib/datasource/deploy.js +75 -53
- package/lib/datasource/field-reference-validator.js +9 -6
- package/lib/datasource/integration-context.js +63 -0
- package/lib/datasource/list.js +8 -7
- package/lib/datasource/log-viewer.js +189 -67
- package/lib/datasource/resolve-app.js +4 -4
- package/lib/datasource/test-e2e.js +113 -146
- package/lib/datasource/test-integration.js +114 -122
- package/lib/datasource/unified-validation-run-body.js +68 -0
- package/lib/datasource/unified-validation-run-post.js +23 -0
- package/lib/datasource/unified-validation-run-resolve.js +43 -0
- package/lib/datasource/unified-validation-run.js +93 -0
- package/lib/datasource/validate.js +157 -13
- package/lib/deployment/deployer.js +4 -3
- package/lib/deployment/environment.js +7 -6
- package/lib/deployment/push.js +17 -8
- package/lib/external-system/delete.js +4 -3
- package/lib/external-system/deploy.js +166 -53
- package/lib/external-system/download-helpers.js +1 -1
- package/lib/external-system/download.js +7 -6
- package/lib/external-system/generator.js +92 -6
- package/lib/external-system/integration-test-dispatch.js +26 -0
- package/lib/external-system/test-execution.js +5 -1
- package/lib/external-system/test-helpers.js +0 -4
- package/lib/external-system/test-system-level-helpers.js +110 -0
- package/lib/external-system/test-system-level.js +83 -44
- package/lib/external-system/test.js +59 -8
- package/lib/generator/builders.js +23 -11
- package/lib/generator/deploy-manifest-azure-kv.js +81 -0
- package/lib/generator/external.js +16 -4
- package/lib/generator/helpers.js +58 -3
- package/lib/generator/index.js +4 -0
- package/lib/generator/split-readme.js +12 -7
- package/lib/generator/split-variables.js +2 -1
- package/lib/generator/split.js +1 -1
- package/lib/generator/wizard-readme.js +3 -3
- package/lib/generator/wizard.js +8 -8
- package/lib/infrastructure/compose.js +70 -7
- package/lib/infrastructure/helpers-docker-check.js +67 -0
- package/lib/infrastructure/helpers.js +203 -42
- package/lib/infrastructure/index.js +31 -18
- package/lib/infrastructure/services.js +21 -67
- package/lib/internal/fs-real-sync.js +104 -0
- package/lib/internal/node-fs.js +98 -0
- package/lib/parameters/database-secret-values.js +173 -0
- package/lib/parameters/infra-kv-discovery.js +121 -0
- package/lib/parameters/infra-parameter-catalog.js +458 -0
- package/lib/parameters/infra-parameter-validate.js +64 -0
- package/lib/schema/application-schema.json +37 -17
- package/lib/schema/datasource-test-run.schema.json +493 -0
- package/lib/schema/deployment-rules.yaml +102 -63
- package/lib/schema/external-datasource.schema.json +1200 -442
- package/lib/schema/external-system.schema.json +203 -5
- package/lib/schema/flag-map-validation-run.json +31 -0
- package/lib/schema/infra-parameter.schema.json +106 -0
- package/lib/schema/infra.parameter.yaml +421 -0
- package/lib/schema/type/credential-auth-templates.json +40 -0
- package/lib/schema/type/document-storage.json +226 -0
- package/lib/schema/type/message-service.json +123 -0
- package/lib/schema/type/vector-store.json +88 -0
- package/lib/utils/aifabrix-runtime-config-dir.js +132 -0
- package/lib/utils/api-error-handler.js +2 -2
- package/lib/utils/api.js +77 -17
- package/lib/utils/app-register-api.js +3 -2
- package/lib/utils/app-register-auth.js +1 -1
- package/lib/utils/app-register-config.js +4 -4
- package/lib/utils/app-register-display.js +3 -2
- package/lib/utils/app-register-validator.js +3 -2
- package/lib/utils/app-run-containers.js +26 -22
- package/lib/utils/app-scoped-config.js +31 -0
- package/lib/utils/app-service-env-from-builder.js +164 -0
- package/lib/utils/build-copy.js +1 -1
- package/lib/utils/build-helpers.js +20 -20
- package/lib/utils/build-resolve-image.js +165 -0
- package/lib/utils/cli-layout-chalk.js +8 -0
- package/lib/utils/cli-test-layout-chalk.js +267 -0
- package/lib/utils/cli-utils.js +88 -11
- package/lib/utils/compose-db-passwords.js +138 -0
- package/lib/utils/compose-generate-docker-compose.js +216 -0
- package/lib/utils/compose-generator.js +197 -291
- package/lib/utils/compose-miso-env.js +18 -0
- package/lib/utils/compose-traefik-ingress-base.js +158 -0
- package/lib/utils/config-paths.js +166 -7
- package/lib/utils/config-scoped-resources-preference.js +41 -0
- package/lib/utils/configuration-env-resolver.js +11 -8
- package/lib/utils/controller-deployment-outcome.js +68 -0
- package/lib/utils/credential-display.js +2 -2
- package/lib/utils/credential-secrets-env.js +5 -5
- package/lib/utils/dataplane-pipeline-warning.js +4 -3
- package/lib/utils/datasource-test-run-capability-scope.js +43 -0
- package/lib/utils/datasource-test-run-certificate-tty.js +82 -0
- package/lib/utils/datasource-test-run-debug-display.js +137 -0
- package/lib/utils/datasource-test-run-debug-slice.js +93 -0
- package/lib/utils/datasource-test-run-display.js +459 -0
- package/lib/utils/datasource-test-run-exit.js +83 -0
- package/lib/utils/datasource-test-run-legacy-adapter.js +93 -0
- package/lib/utils/datasource-test-run-report-version.js +51 -0
- package/lib/utils/datasource-test-run-schema-sync.js +59 -0
- package/lib/utils/datasource-test-run-tty-log.js +81 -0
- package/lib/utils/datasource-validation-watch.js +266 -0
- package/lib/utils/declarative-url-ports.js +47 -0
- package/lib/utils/derive-env-key-from-client-id.js +41 -0
- package/lib/utils/dev-ca-install.js +185 -23
- package/lib/utils/dev-cert-helper.js +266 -17
- package/lib/utils/dev-hosts-helper.js +307 -0
- package/lib/utils/dev-init-cert-hints.js +37 -0
- package/lib/utils/dev-init-health-messages.js +52 -0
- package/lib/utils/dev-init-resolve.js +86 -0
- package/lib/utils/dev-init-ssh-merge.js +65 -0
- package/lib/utils/dev-ssh-config-helper.js +196 -0
- package/lib/utils/dev-user-groups.js +93 -0
- package/lib/utils/docker-build.js +42 -17
- package/lib/utils/docker-exec.js +28 -0
- package/lib/utils/docker-manifest-public-port.js +116 -0
- package/lib/utils/docker-not-running-hint.js +52 -0
- package/lib/utils/docker.js +98 -11
- package/lib/utils/ensure-dev-certs-for-remote-docker.js +192 -0
- package/lib/utils/env-config-loader.js +10 -91
- package/lib/utils/env-copy.js +19 -10
- package/lib/utils/env-map.js +35 -8
- package/lib/utils/env-template.js +2 -2
- package/lib/utils/environment-scoped-resources.js +144 -0
- package/lib/utils/error-formatter.js +92 -13
- package/lib/utils/error-formatters/http-status-errors.js +6 -5
- package/lib/utils/error-formatters/network-errors.js +2 -1
- package/lib/utils/error-formatters/permission-errors.js +2 -1
- package/lib/utils/error-formatters/validation-errors.js +2 -1
- package/lib/utils/external-readme.js +8 -1
- package/lib/utils/external-system-display.js +242 -136
- package/lib/utils/external-system-local-test-tty.js +389 -0
- package/lib/utils/external-system-readiness-core.js +377 -0
- package/lib/utils/external-system-readiness-deploy-display.js +270 -0
- package/lib/utils/external-system-readiness-display-internals.js +150 -0
- package/lib/utils/external-system-readiness-display.js +186 -0
- package/lib/utils/external-system-system-test-tty-overview.js +120 -0
- package/lib/utils/external-system-system-test-tty.js +417 -0
- package/lib/utils/external-system-test-helpers.js +24 -6
- package/lib/utils/external-system-validators.js +30 -12
- package/lib/utils/health-check-url.js +119 -0
- package/lib/utils/health-check.js +59 -25
- package/lib/utils/help-builder.js +11 -8
- package/lib/utils/image-version.js +4 -8
- package/lib/utils/infra-containers.js +4 -7
- package/lib/utils/infra-env-defaults.js +162 -0
- package/lib/utils/infra-status-display.js +167 -0
- package/lib/utils/infra-status.js +16 -8
- package/lib/utils/local-secrets.js +3 -4
- package/lib/utils/paths.js +148 -47
- package/lib/utils/port-resolver.js +10 -23
- package/lib/utils/redis-env-scope.js +62 -0
- package/lib/utils/register-aifabrix-shell-env.js +204 -0
- package/lib/utils/remote-builder-validation.js +99 -0
- package/lib/utils/remote-dev-auth.js +117 -21
- package/lib/utils/remote-docker-env.js +67 -15
- package/lib/utils/remote-secrets-loader.js +13 -4
- package/lib/utils/resolve-docker-image-ref.js +124 -0
- package/lib/utils/schema-loader.js +22 -9
- package/lib/utils/secrets-bash-kv.js +25 -0
- package/lib/utils/secrets-generator.js +169 -49
- package/lib/utils/secrets-helpers.js +70 -59
- package/lib/utils/secrets-kv-scope.js +60 -0
- package/lib/utils/secrets-utils.js +32 -38
- package/lib/utils/secrets-validation.js +3 -1
- package/lib/utils/secrets-yaml-preserve.js +109 -0
- package/lib/utils/ssh-key-helper.js +4 -2
- package/lib/utils/template-helpers.js +2 -2
- package/lib/utils/test-log-writer.js +3 -3
- package/lib/utils/token-manager.js +1 -2
- package/lib/utils/url-declarative-public-base.js +188 -0
- package/lib/utils/url-declarative-resolve-build.js +493 -0
- package/lib/utils/url-declarative-resolve-load-doc.js +51 -0
- package/lib/utils/url-declarative-resolve.js +220 -0
- package/lib/utils/url-declarative-token-parse.js +74 -0
- package/lib/utils/url-declarative-url-flags.js +50 -0
- package/lib/utils/url-declarative-vdir-inactive-env.js +99 -0
- package/lib/utils/url-public-path-prefix.js +34 -0
- package/lib/utils/urls-local-registry.js +220 -0
- package/lib/utils/validation-report-tty-kit.js +77 -0
- package/lib/utils/validation-run-poll.js +112 -0
- package/lib/utils/validation-run-post-retry.js +85 -0
- package/lib/utils/validation-run-request.js +116 -0
- package/lib/utils/variable-transformer.js +21 -4
- package/lib/utils/yaml-preserve.js +33 -14
- package/lib/validation/datasource-warnings.js +56 -0
- package/lib/validation/env-template-auth.js +1 -1
- package/lib/validation/external-manifest-validator.js +27 -7
- package/lib/validation/validate-display.js +37 -31
- package/lib/validation/validate-external-cert-sync.js +23 -0
- package/lib/validation/validate.js +8 -14
- package/lib/validation/validator-unresolved-placeholders.js +98 -0
- package/lib/validation/validator.js +22 -65
- package/lib/validation/wizard-config-validator.js +2 -1
- package/package.json +9 -4
- package/scripts/check-datasource-test-run-schema-sync.js +34 -0
- package/scripts/diagnose-cli.js +150 -0
- package/scripts/install-local.js +307 -55
- package/scripts/pnpm-global-remove.js +48 -0
- package/templates/README.md +15 -2
- package/templates/applications/dataplane/application.yaml +52 -2
- package/templates/applications/dataplane/env.template +79 -17
- package/templates/applications/dataplane/rbac.yaml +8 -0
- package/templates/applications/keycloak/application.yaml +9 -1
- package/templates/applications/keycloak/env.template +15 -6
- package/templates/applications/miso-controller/application.yaml +10 -2
- package/templates/applications/miso-controller/env.template +42 -12
- package/templates/applications/miso-controller/rbac.yaml +5 -0
- package/templates/external-system/README.md.hbs +20 -7
- package/templates/external-system/deploy.js.hbs +5 -5
- package/templates/external-system/external-datasource.yaml.hbs +197 -118
- package/templates/infra/compose.yaml.hbs +33 -16
- package/templates/infra/servers.json.hbs +3 -1
- package/templates/python/docker-compose.hbs +16 -0
- package/templates/typescript/docker-compose.hbs +16 -0
- package/lib/api/external-test.api.js +0 -111
- package/lib/schema/env-config.yaml +0 -60
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synchronous fs helpers that use `global.__AIFABRIX_NODE_FS_UNMOCKED__` from
|
|
3
|
+
* `tests/capture-real-fs.js` when present so Jest `jest.mock('fs')` and partial
|
|
4
|
+
* `jest.mock('internal/node-fs')` cannot break config, schema, or builder scans.
|
|
5
|
+
*
|
|
6
|
+
* @fileoverview Real filesystem sync for config, schemas, urls.local registry, url:// resolution
|
|
7
|
+
*/
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @returns {import('node:fs')|null}
|
|
12
|
+
*/
|
|
13
|
+
function unmockedFsSnapshot() {
|
|
14
|
+
const g = typeof globalThis !== 'undefined' ? globalThis : global;
|
|
15
|
+
return g && g.__AIFABRIX_NODE_FS_UNMOCKED__ ? g.__AIFABRIX_NODE_FS_UNMOCKED__ : null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function delegate(name, args) {
|
|
19
|
+
const snap = unmockedFsSnapshot();
|
|
20
|
+
if (snap && typeof snap[name] === 'function') {
|
|
21
|
+
return snap[name](...args);
|
|
22
|
+
}
|
|
23
|
+
// When Jest is active, bypass any manual module mocks of node:fs.
|
|
24
|
+
// This keeps schema/catalog reads stable even if a suite does jest.mock('node:fs').
|
|
25
|
+
const fs =
|
|
26
|
+
typeof jest !== 'undefined' && typeof jest.requireActual === 'function'
|
|
27
|
+
? jest.requireActual('node:fs')
|
|
28
|
+
: require('node:fs');
|
|
29
|
+
return fs[name](...args);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param {string} p
|
|
34
|
+
* @returns {boolean}
|
|
35
|
+
*/
|
|
36
|
+
function existsSync(p) {
|
|
37
|
+
return delegate('existsSync', [p]);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Read file via snapshot/delegate only — not the same binding as {@link readFileSync} on `module.exports`.
|
|
42
|
+
* Tests may `jest.spyOn(exports, 'readFileSync')`; this function stays the real implementation for env/PIN paths.
|
|
43
|
+
* @param {string} p
|
|
44
|
+
* @param {string|import('node:fs').ObjectEncodingOptions} [enc]
|
|
45
|
+
* @returns {string|Buffer}
|
|
46
|
+
*/
|
|
47
|
+
function readFileSyncDirect(p, enc) {
|
|
48
|
+
return delegate('readFileSync', enc !== undefined ? [p, enc] : [p]);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @param {string} p
|
|
53
|
+
* @param {string|import('node:fs').ObjectEncodingOptions} [enc]
|
|
54
|
+
* @returns {string|Buffer}
|
|
55
|
+
*/
|
|
56
|
+
function readFileSync(p, enc) {
|
|
57
|
+
return readFileSyncDirect(p, enc);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @param {string} p
|
|
62
|
+
* @param {string|Buffer} data
|
|
63
|
+
* @param {object|string} [opts]
|
|
64
|
+
* @returns {void}
|
|
65
|
+
*/
|
|
66
|
+
function writeFileSync(p, data, opts) {
|
|
67
|
+
return delegate('writeFileSync', opts !== undefined ? [p, data, opts] : [p, data]);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @param {string} p
|
|
72
|
+
* @param {object} [opts]
|
|
73
|
+
* @returns {string|undefined}
|
|
74
|
+
*/
|
|
75
|
+
function mkdirSync(p, opts) {
|
|
76
|
+
return delegate('mkdirSync', opts !== undefined ? [p, opts] : [p]);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @param {string} p
|
|
81
|
+
* @returns {import('node:fs').Stats}
|
|
82
|
+
*/
|
|
83
|
+
function statSync(p) {
|
|
84
|
+
return delegate('statSync', [p]);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @param {string} p
|
|
89
|
+
* @param {object} [opts]
|
|
90
|
+
* @returns {string[]|import('node:fs').Dirent[]}
|
|
91
|
+
*/
|
|
92
|
+
function readdirSync(p, opts) {
|
|
93
|
+
return delegate('readdirSync', opts !== undefined ? [p, opts] : [p]);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
module.exports = {
|
|
97
|
+
existsSync,
|
|
98
|
+
readFileSync,
|
|
99
|
+
readFileSyncDirect,
|
|
100
|
+
writeFileSync,
|
|
101
|
+
mkdirSync,
|
|
102
|
+
statSync,
|
|
103
|
+
readdirSync
|
|
104
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Filesystem helpers that ignore jest.spyOn on require('node:fs') for sync reads.
|
|
3
|
+
* Uses jest.requireActual when Jest is active so .bind() captures native implementations even if
|
|
4
|
+
* this module loads after another suite spied fs. watch still delegates to live fs so tests can spy it.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Bound native fs from tests/capture-real-fs.js (Jest setupFiles, before mocks).
|
|
11
|
+
* @returns {Record<string, unknown>|null}
|
|
12
|
+
*/
|
|
13
|
+
function getUnmockedFsSnapshot() {
|
|
14
|
+
const g = typeof globalThis !== 'undefined' ? globalThis : global;
|
|
15
|
+
return g && g.__AIFABRIX_NODE_FS_UNMOCKED__ ? g.__AIFABRIX_NODE_FS_UNMOCKED__ : null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function getRealFs() {
|
|
19
|
+
const snap = getUnmockedFsSnapshot();
|
|
20
|
+
if (snap) {
|
|
21
|
+
return snap;
|
|
22
|
+
}
|
|
23
|
+
// When Jest is active, bypass manual module mocks (singleton may still carry spyOn).
|
|
24
|
+
if (typeof jest !== 'undefined' && typeof jest.requireActual === 'function') {
|
|
25
|
+
return jest.requireActual('node:fs');
|
|
26
|
+
}
|
|
27
|
+
return require('node:fs');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @param {import('node:fs')} fsModule
|
|
32
|
+
* @param {string} name
|
|
33
|
+
* @returns {unknown}
|
|
34
|
+
*/
|
|
35
|
+
function bindSync(fsModule, name) {
|
|
36
|
+
const fn = fsModule[name];
|
|
37
|
+
return typeof fn === 'function' ? fn.bind(fsModule) : fn;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function liveFs() {
|
|
41
|
+
return require('node:fs');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Resolve real fs on each access so callers still see the filesystem after other
|
|
46
|
+
* suites replace require('fs') with mocks (schema-loader, schema sync helpers).
|
|
47
|
+
* @returns {typeof import('node:fs')}
|
|
48
|
+
*/
|
|
49
|
+
function freshRealFs() {
|
|
50
|
+
return getRealFs();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @returns {Record<string, unknown>}
|
|
55
|
+
*/
|
|
56
|
+
function buildBoundFs() {
|
|
57
|
+
const snap = getUnmockedFsSnapshot();
|
|
58
|
+
const rf = freshRealFs();
|
|
59
|
+
const live = liveFs();
|
|
60
|
+
const promiseHost = live.promises || {};
|
|
61
|
+
const boundPromises = {
|
|
62
|
+
mkdir: bindSync(promiseHost, 'mkdir'),
|
|
63
|
+
writeFile: bindSync(promiseHost, 'writeFile'),
|
|
64
|
+
appendFile: bindSync(promiseHost, 'appendFile'),
|
|
65
|
+
readFile: bindSync(promiseHost, 'readFile')
|
|
66
|
+
};
|
|
67
|
+
if (snap) {
|
|
68
|
+
return {
|
|
69
|
+
existsSync: snap.existsSync,
|
|
70
|
+
readFileSync: snap.readFileSync,
|
|
71
|
+
writeFileSync: snap.writeFileSync,
|
|
72
|
+
mkdirSync: snap.mkdirSync,
|
|
73
|
+
readdirSync: snap.readdirSync,
|
|
74
|
+
statSync: snap.statSync,
|
|
75
|
+
watch: (...args) => live.watch(...args),
|
|
76
|
+
promises: boundPromises
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
existsSync: bindSync(rf, 'existsSync'),
|
|
81
|
+
readFileSync: bindSync(rf, 'readFileSync'),
|
|
82
|
+
writeFileSync: bindSync(rf, 'writeFileSync'),
|
|
83
|
+
mkdirSync: bindSync(rf, 'mkdirSync'),
|
|
84
|
+
readdirSync: bindSync(rf, 'readdirSync'),
|
|
85
|
+
statSync: bindSync(rf, 'statSync'),
|
|
86
|
+
watch: (...args) => live.watch(...args),
|
|
87
|
+
promises: boundPromises
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @returns {ReturnType<typeof buildBoundFs>}
|
|
93
|
+
*/
|
|
94
|
+
function nodeFs() {
|
|
95
|
+
return buildBoundFs();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = { nodeFs };
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Index-aware local PostgreSQL URL/password defaults for databases-{app}-{i}-* keys
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 2.1.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const { nodeFs } = require('../internal/node-fs');
|
|
9
|
+
const yaml = require('js-yaml');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Shipped platform templates (when builder/<app> does not exist yet).
|
|
13
|
+
* Prefer Jest/global.PROJECT_ROOT when that tree contains templates (stable under isolated projects).
|
|
14
|
+
* @returns {string}
|
|
15
|
+
*/
|
|
16
|
+
function getTemplatesApplicationsRoot() {
|
|
17
|
+
const fallback = path.join(__dirname, '..', '..', 'templates', 'applications');
|
|
18
|
+
try {
|
|
19
|
+
if (typeof global !== 'undefined' && global.PROJECT_ROOT) {
|
|
20
|
+
const g = path.join(path.resolve(String(global.PROJECT_ROOT)), 'templates', 'applications');
|
|
21
|
+
const marker = path.join(g, 'miso-controller', 'application.yaml');
|
|
22
|
+
if (nodeFs().existsSync(marker)) {
|
|
23
|
+
return g;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
} catch {
|
|
27
|
+
/* ignore */
|
|
28
|
+
}
|
|
29
|
+
return fallback;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* PostgreSQL role name from database name (same as compose pgUserName helper).
|
|
34
|
+
* @param {string} dbName - Logical database name (e.g. miso-logs)
|
|
35
|
+
* @returns {string}
|
|
36
|
+
*/
|
|
37
|
+
function pgUserFromDbName(dbName) {
|
|
38
|
+
if (!dbName) return '';
|
|
39
|
+
return `${String(dbName).replace(/-/g, '_')}_user`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Local dev password aligned with infra init scripts (user base + _pass123).
|
|
44
|
+
* @param {string} userName - e.g. miso_user, miso_logs_user
|
|
45
|
+
* @returns {string}
|
|
46
|
+
*/
|
|
47
|
+
function localDevPasswordFromPgUser(userName) {
|
|
48
|
+
const base = String(userName).replace(/_user$/i, '');
|
|
49
|
+
return `${base}_pass123`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Load requires.databases from application config if present (read-only; no rename).
|
|
54
|
+
* @param {string} appDir - Absolute path to builder/integration app folder
|
|
55
|
+
* @returns {Array<{name?: string}>|null}
|
|
56
|
+
*/
|
|
57
|
+
function loadRequiresDatabasesArray(appDir) {
|
|
58
|
+
if (!appDir || !nodeFs().existsSync(appDir)) return null;
|
|
59
|
+
const candidates = ['application.yaml', 'application.yml', 'variables.yaml'];
|
|
60
|
+
for (const name of candidates) {
|
|
61
|
+
const p = path.join(appDir, name);
|
|
62
|
+
if (!nodeFs().existsSync(p)) continue;
|
|
63
|
+
try {
|
|
64
|
+
const doc = yaml.load(nodeFs().readFileSync(p, 'utf8'));
|
|
65
|
+
const dbs = doc?.requires?.databases;
|
|
66
|
+
if (Array.isArray(dbs) && dbs.length > 0) return dbs;
|
|
67
|
+
} catch {
|
|
68
|
+
/* ignore */
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Load requires.databases from shipped Builder template (templates/applications/<appKey>/application.yaml).
|
|
76
|
+
* @param {string} appKey - Application key
|
|
77
|
+
* @returns {Array<{name?: string}>|null}
|
|
78
|
+
*/
|
|
79
|
+
function loadShippedRequiresDatabases(appKey) {
|
|
80
|
+
if (!appKey || typeof appKey !== 'string') return null;
|
|
81
|
+
const p = path.join(getTemplatesApplicationsRoot(), appKey, 'application.yaml');
|
|
82
|
+
if (!nodeFs().existsSync(p)) return null;
|
|
83
|
+
try {
|
|
84
|
+
const doc = yaml.load(nodeFs().readFileSync(p, 'utf8'));
|
|
85
|
+
const dbs = doc?.requires?.databases;
|
|
86
|
+
return Array.isArray(dbs) && dbs.length > 0 ? dbs : null;
|
|
87
|
+
} catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Resolve logical PostgreSQL database name for a databases-{appKey}-{index}-* key.
|
|
94
|
+
* @param {string} appKey - App key segment from secret key
|
|
95
|
+
* @param {number} index - Database index
|
|
96
|
+
* @param {string|null} appDir - Optional app directory to read application.yaml
|
|
97
|
+
* @returns {string}
|
|
98
|
+
*/
|
|
99
|
+
function resolveLogicalDbName(appKey, index, appDir) {
|
|
100
|
+
const fromDir = appDir ? loadRequiresDatabasesArray(appDir) : null;
|
|
101
|
+
const dbs = fromDir || loadShippedRequiresDatabases(appKey);
|
|
102
|
+
if (dbs && dbs[index] && dbs[index].name) {
|
|
103
|
+
return String(dbs[index].name);
|
|
104
|
+
}
|
|
105
|
+
if (index === 0) {
|
|
106
|
+
return String(appKey).replace(/-/g, '_');
|
|
107
|
+
}
|
|
108
|
+
return `${String(appKey).replace(/-/g, '_')}_${index}`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Parse databases-{appKey}-{index}-(urlKeyVault|passwordKeyVault).
|
|
113
|
+
* @param {string} key - Secret key
|
|
114
|
+
* @returns {{ appKey: string, index: number, kind: 'url'|'password' }|null}
|
|
115
|
+
*/
|
|
116
|
+
function parseDatabaseSecretKey(key) {
|
|
117
|
+
const m = String(key).match(/^databases-([a-z0-9-]+)-(\d+)-(urlKeyVault|passwordKeyVault)$/i);
|
|
118
|
+
if (!m) return null;
|
|
119
|
+
return {
|
|
120
|
+
appKey: m[1],
|
|
121
|
+
index: parseInt(m[2], 10),
|
|
122
|
+
kind: m[3].toLowerCase().startsWith('url') ? 'url' : 'password'
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Build postgres URL with unresolved host/port placeholders.
|
|
128
|
+
* @param {string} dbName - Database name in connection path (may contain hyphens)
|
|
129
|
+
* @param {string} userName - DB user
|
|
130
|
+
* @param {string} password - DB password
|
|
131
|
+
* @returns {string}
|
|
132
|
+
*/
|
|
133
|
+
function buildPostgresUrlTemplate(dbName, userName, password) {
|
|
134
|
+
return `postgresql://${userName}:${password}@\${DB_HOST}:\${DB_PORT}/${dbName}`;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Generate password value for databases-*-passwordKeyVault.
|
|
139
|
+
* @param {string} key - Full secret key
|
|
140
|
+
* @param {string|null} appDir - Optional app directory for YAML lookup
|
|
141
|
+
* @returns {string|null} Value or null if key does not match
|
|
142
|
+
*/
|
|
143
|
+
function generateDatabasePasswordValueForKey(key, appDir = null) {
|
|
144
|
+
const parsed = parseDatabaseSecretKey(key);
|
|
145
|
+
if (!parsed || parsed.kind !== 'password') return null;
|
|
146
|
+
const dbName = resolveLogicalDbName(parsed.appKey, parsed.index, appDir);
|
|
147
|
+
const user = pgUserFromDbName(dbName);
|
|
148
|
+
return localDevPasswordFromPgUser(user);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Generate URL value for databases-*-urlKeyVault.
|
|
153
|
+
* @param {string} key - Full secret key
|
|
154
|
+
* @param {string|null} appDir - Optional app directory for YAML lookup
|
|
155
|
+
* @returns {string|null} Value or null if key does not match
|
|
156
|
+
*/
|
|
157
|
+
function generateDatabaseUrlValueForKey(key, appDir = null) {
|
|
158
|
+
const parsed = parseDatabaseSecretKey(key);
|
|
159
|
+
if (!parsed || parsed.kind !== 'url') return null;
|
|
160
|
+
const dbName = resolveLogicalDbName(parsed.appKey, parsed.index, appDir);
|
|
161
|
+
const user = pgUserFromDbName(dbName);
|
|
162
|
+
const pass = localDevPasswordFromPgUser(user);
|
|
163
|
+
return buildPostgresUrlTemplate(dbName, user, pass);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
module.exports = {
|
|
167
|
+
parseDatabaseSecretKey,
|
|
168
|
+
generateDatabasePasswordValueForKey,
|
|
169
|
+
generateDatabaseUrlValueForKey,
|
|
170
|
+
loadRequiresDatabasesArray,
|
|
171
|
+
loadShippedRequiresDatabases,
|
|
172
|
+
resolveLogicalDbName
|
|
173
|
+
};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Discover kv:// keys for up-infra from workspace templates and application.yaml
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 2.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fsRealSync = require('../internal/fs-real-sync');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const { loadRequiresDatabasesArray } = require('./database-secret-values');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Extract kv:// secret key names from env template content (active lines only).
|
|
13
|
+
* @param {string} content - env.template body
|
|
14
|
+
* @returns {string[]}
|
|
15
|
+
*/
|
|
16
|
+
function extractKvKeysFromEnvContent(content) {
|
|
17
|
+
if (!content || typeof content !== 'string') return [];
|
|
18
|
+
const keys = new Set();
|
|
19
|
+
const kvPattern = /kv:\/\/([a-zA-Z0-9-_]+)/g;
|
|
20
|
+
const lines = content.split('\n');
|
|
21
|
+
for (const line of lines) {
|
|
22
|
+
const t = line.trim();
|
|
23
|
+
if (t === '' || t.startsWith('#')) continue;
|
|
24
|
+
let m;
|
|
25
|
+
kvPattern.lastIndex = 0;
|
|
26
|
+
while ((m = kvPattern.exec(line)) !== null) {
|
|
27
|
+
keys.add(m[1]);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return [...keys];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* List app directories for discovery (builder first, then integration-only apps).
|
|
35
|
+
* @param {object} pathsUtil - paths module
|
|
36
|
+
* @returns {{ appKey: string, dir: string }[]}
|
|
37
|
+
*/
|
|
38
|
+
function listAppDirsForDiscovery(pathsUtil) {
|
|
39
|
+
const out = [];
|
|
40
|
+
const seen = new Set();
|
|
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
|
+
seen.add(name);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
for (const name of pathsUtil.listIntegrationAppNames()) {
|
|
49
|
+
if (seen.has(name)) continue;
|
|
50
|
+
const dir = pathsUtil.getIntegrationPath(name);
|
|
51
|
+
if (fsRealSync.existsSync(dir)) {
|
|
52
|
+
out.push({ appKey: name, dir });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Derive databases-{appKey}-{i}-url/password keys from requires.databases length.
|
|
60
|
+
* @param {object} pathsUtil - paths module
|
|
61
|
+
* @returns {string[]}
|
|
62
|
+
*/
|
|
63
|
+
function deriveDatabaseKvKeysFromWorkspace(pathsUtil) {
|
|
64
|
+
const keys = new Set();
|
|
65
|
+
for (const { appKey, dir } of listAppDirsForDiscovery(pathsUtil)) {
|
|
66
|
+
const dbs = loadRequiresDatabasesArray(dir);
|
|
67
|
+
if (!Array.isArray(dbs) || dbs.length === 0) continue;
|
|
68
|
+
for (let i = 0; i < dbs.length; i++) {
|
|
69
|
+
keys.add(`databases-${appKey}-${i}-urlKeyVault`);
|
|
70
|
+
keys.add(`databases-${appKey}-${i}-passwordKeyVault`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return [...keys];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Keys from env.template files whose catalog entry includes the given hook (e.g. upInfra).
|
|
78
|
+
* @param {object} pathsUtil - paths module
|
|
79
|
+
* @param {string} hook - ensureOn hook name
|
|
80
|
+
* @param {{ keyMatchesEnsureHook: Function }} catalog - loaded catalog API
|
|
81
|
+
* @returns {string[]}
|
|
82
|
+
*/
|
|
83
|
+
function discoverKvKeysFromEnvTemplatesForHook(pathsUtil, hook, catalog) {
|
|
84
|
+
const keys = new Set();
|
|
85
|
+
for (const { dir } of listAppDirsForDiscovery(pathsUtil)) {
|
|
86
|
+
const envPath = path.join(dir, 'env.template');
|
|
87
|
+
if (!fsRealSync.existsSync(envPath)) continue;
|
|
88
|
+
let content;
|
|
89
|
+
try {
|
|
90
|
+
content = fsRealSync.readFileSync(envPath, 'utf8');
|
|
91
|
+
} catch {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
for (const k of extractKvKeysFromEnvContent(content)) {
|
|
95
|
+
if (catalog.keyMatchesEnsureHook(k, hook)) keys.add(k);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return [...keys];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Full key list for ensureInfraSecrets: catalog exact upInfra + standard miso DB + derived DB + template hooks.
|
|
103
|
+
* @param {{ getEnsureOnKeys: Function, keyMatchesEnsureHook: Function }} catalog
|
|
104
|
+
* @param {object} pathsUtil - paths module
|
|
105
|
+
* @returns {string[]}
|
|
106
|
+
*/
|
|
107
|
+
function getAllInfraEnsureKeys(catalog, pathsUtil) {
|
|
108
|
+
const set = new Set(catalog.getEnsureOnKeys('upInfra'));
|
|
109
|
+
for (const k of catalog.getStandardUpInfraBootstrapKeys()) set.add(k);
|
|
110
|
+
for (const k of deriveDatabaseKvKeysFromWorkspace(pathsUtil)) set.add(k);
|
|
111
|
+
for (const k of discoverKvKeysFromEnvTemplatesForHook(pathsUtil, 'upInfra', catalog)) set.add(k);
|
|
112
|
+
return [...set].sort();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
module.exports = {
|
|
116
|
+
extractKvKeysFromEnvContent,
|
|
117
|
+
deriveDatabaseKvKeysFromWorkspace,
|
|
118
|
+
discoverKvKeysFromEnvTemplatesForHook,
|
|
119
|
+
getAllInfraEnsureKeys,
|
|
120
|
+
listAppDirsForDiscovery
|
|
121
|
+
};
|