@aifabrix/builder 2.42.1 → 2.44.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/anchor-docs.mdc +15 -0
- package/README.md +2 -2
- 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 +157 -0
- package/integration/{hubspot → hubspot-test}/application.json +6 -6
- package/integration/{hubspot → hubspot-test}/create-hubspot.js +10 -10
- package/integration/hubspot-test/env.template +4 -0
- package/integration/hubspot-test/hubspot-test-datasource-company.json +138 -0
- package/integration/hubspot-test/hubspot-test-datasource-contact.json +146 -0
- package/integration/hubspot-test/hubspot-test-datasource-deal.json +146 -0
- package/integration/hubspot-test/hubspot-test-datasource-users.json +76 -0
- package/integration/{hubspot/hubspot-deploy.json → hubspot-test/hubspot-test-deploy.json} +201 -24
- package/integration/{hubspot/hubspot-system.json → hubspot-test/hubspot-test-system.json} +8 -7
- package/integration/hubspot-test/rbac.json +166 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-hubspot-credential-real.yaml +3 -3
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-hubspot-env-vars.yaml +2 -2
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-add-datasource.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-credential-create.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-credential-select.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-known-platform.yaml +1 -1
- package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-source.yaml +2 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-mode.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-openapi-file.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-openapi-url.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-source.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-dimension-array-test.yaml +1 -1
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-key-test.yaml +5 -0
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-path-test.yaml +5 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-dimension-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-rbac-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-dataplane-down-tests.js +1 -7
- package/integration/{hubspot → hubspot-test}/test-dataplane-down.js +3 -3
- package/integration/{hubspot → hubspot-test}/test.js +137 -102
- package/integration/{hubspot → hubspot-test}/wizard-hubspot-e2e.yaml +2 -2
- package/integration/{hubspot → hubspot-test}/wizard-hubspot-platform.yaml +1 -1
- 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 +288 -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 +0 -1
- package/lib/api/pipeline.api.js +67 -20
- package/lib/api/service-users.api.js +111 -2
- package/lib/api/types/dev.types.js +4 -3
- package/lib/api/types/pipeline.types.js +8 -5
- package/lib/api/types/service-users.types.js +41 -0
- package/lib/api/types/validation-run.types.js +56 -0
- package/lib/api/validation-run.api.js +99 -0
- package/lib/api/validation-runner.js +99 -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 +19 -8
- package/lib/app/rotate-secret.js +17 -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 +1 -1
- package/lib/app/show.js +1 -1
- package/lib/build/index.js +13 -10
- package/lib/cli/index.js +2 -0
- package/lib/cli/setup-app.help.js +67 -0
- package/lib/cli/setup-app.js +59 -123
- package/lib/cli/setup-app.test-commands.js +179 -0
- package/lib/cli/setup-auth.js +36 -14
- 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 +190 -103
- package/lib/cli/setup-environment.js +11 -20
- package/lib/cli/setup-external-system.js +62 -22
- package/lib/cli/setup-infra.js +139 -47
- package/lib/cli/setup-parameters.js +32 -0
- package/lib/cli/setup-secrets.js +147 -10
- package/lib/cli/setup-service-user.js +146 -20
- package/lib/cli/setup-utility.js +47 -19
- 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 +22 -10
- package/lib/commands/auth-config.js +10 -14
- 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 +495 -0
- package/lib/commands/datasource-unified-test-cli.options.js +149 -0
- package/lib/commands/datasource-validation-cli.js +129 -0
- package/lib/commands/datasource.js +123 -71
- 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 +16 -10
- package/lib/commands/repair-rbac.js +25 -19
- package/lib/commands/repair.js +116 -32
- package/lib/commands/secrets-list.js +23 -12
- package/lib/commands/secrets-remove-all.js +220 -0
- package/lib/commands/secrets-remove.js +22 -13
- package/lib/commands/secrets-set.js +21 -12
- package/lib/commands/secrets-validate.js +20 -7
- package/lib/commands/secure.js +10 -9
- package/lib/commands/service-user.js +243 -13
- package/lib/commands/test-e2e-external.js +27 -1
- package/lib/commands/up-common.js +28 -2
- package/lib/commands/up-dataplane.js +31 -18
- package/lib/commands/up-miso.js +19 -29
- package/lib/commands/upload.js +138 -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 +16 -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 +59 -58
- package/lib/core/diff.js +3 -2
- package/lib/core/ensure-encryption-key.js +2 -4
- 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 +228 -42
- package/lib/core/templates-env.js +4 -3
- package/lib/core/templates.js +1 -1
- package/lib/datasource/abac-validator.js +148 -0
- package/lib/datasource/deploy.js +75 -53
- package/lib/datasource/field-reference-validator.js +77 -36
- package/lib/datasource/integration-context.js +63 -0
- package/lib/datasource/list.js +8 -7
- package/lib/datasource/log-viewer.js +252 -0
- package/lib/datasource/resolve-app.js +109 -0
- package/lib/datasource/test-e2e.js +95 -155
- package/lib/datasource/test-integration.js +121 -109
- package/lib/datasource/unified-validation-run-body.js +65 -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 +92 -0
- package/lib/datasource/validate.js +162 -15
- 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 +131 -53
- package/lib/external-system/download-helpers.js +1 -1
- package/lib/external-system/download.js +7 -6
- package/lib/external-system/generator.js +104 -14
- 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-controller-manifest.js +3 -3
- package/lib/generator/external.js +23 -11
- package/lib/generator/helpers.js +71 -12
- package/lib/generator/index.js +8 -4
- package/lib/generator/split-readme.js +12 -7
- package/lib/generator/split-variables.js +2 -1
- package/lib/generator/split.js +46 -11
- package/lib/generator/wizard-readme.js +3 -3
- package/lib/generator/wizard.js +16 -13
- package/lib/infrastructure/compose.js +60 -6
- package/lib/infrastructure/helpers.js +238 -51
- package/lib/infrastructure/index.js +64 -37
- package/lib/infrastructure/services.js +21 -15
- 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 +1201 -433
- package/lib/schema/external-system.schema.json +181 -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 +213 -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 +49 -14
- package/lib/utils/app-config-resolver.js +23 -1
- 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 +209 -6
- package/lib/utils/config-scoped-resources-preference.js +41 -0
- package/lib/utils/controller-deployment-outcome.js +68 -0
- package/lib/utils/credential-display.js +2 -2
- package/lib/utils/credential-secrets-env.js +16 -1
- 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-debug-display.js +137 -0
- package/lib/utils/datasource-test-run-debug-slice.js +93 -0
- package/lib/utils/datasource-test-run-display.js +442 -0
- package/lib/utils/datasource-test-run-exit.js +58 -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 +42 -11
- package/lib/utils/env-template.js +2 -2
- package/lib/utils/environment-scoped-resources.js +144 -0
- package/lib/utils/error-formatter.js +125 -9
- 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-env-template.js +180 -0
- package/lib/utils/external-readme.js +8 -1
- package/lib/utils/external-system-display.js +277 -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-test-helpers.js +24 -6
- package/lib/utils/external-system-validators.js +32 -14
- package/lib/utils/health-check-url.js +119 -0
- package/lib/utils/health-check.js +59 -25
- package/lib/utils/help-builder.js +14 -13
- 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 +29 -7
- package/lib/utils/paths.js +136 -48
- 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 +171 -51
- package/lib/utils/secrets-helpers.js +70 -59
- package/lib/utils/secrets-kv-scope.js +60 -0
- package/lib/utils/secrets-utils.js +35 -37
- package/lib/utils/secrets-validation.js +3 -1
- package/lib/utils/secrets-yaml-preserve.js +109 -0
- package/lib/utils/secure-file-permissions.js +91 -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 +37 -5
- 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 +89 -0
- package/lib/utils/validation-run-post-retry.js +73 -0
- package/lib/utils/validation-run-request.js +98 -0
- package/lib/utils/variable-transformer.js +21 -4
- package/lib/utils/yaml-preserve.js +78 -1
- package/lib/validation/datasource-warnings.js +56 -0
- package/lib/validation/env-template-auth.js +50 -2
- package/lib/validation/external-manifest-validator.js +35 -7
- package/lib/validation/validate-display.js +37 -31
- package/lib/validation/validate.js +9 -10
- package/lib/validation/validator-unresolved-placeholders.js +98 -0
- package/lib/validation/validator.js +32 -78
- package/lib/validation/wizard-config-validator.js +2 -1
- package/package.json +11 -3
- package/scripts/check-datasource-test-run-schema-sync.js +34 -0
- package/scripts/diagnose-cli.js +150 -0
- package/scripts/install-local.js +304 -55
- package/templates/README.md +15 -2
- package/templates/applications/dataplane/application.yaml +52 -2
- package/templates/applications/dataplane/env.template +80 -18
- 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 +55 -14
- 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/env.template.hbs +22 -0
- package/templates/external-system/external-datasource.yaml.hbs +197 -118
- package/templates/infra/compose.yaml.hbs +20 -4
- package/templates/python/docker-compose.hbs +16 -0
- package/templates/typescript/docker-compose.hbs +16 -0
- package/integration/hubspot/README.md +0 -102
- package/integration/hubspot/env.template +0 -4
- package/integration/hubspot/hubspot-datasource-company.json +0 -541
- package/integration/hubspot/hubspot-datasource-contact.json +0 -639
- package/integration/hubspot/hubspot-datasource-deal.json +0 -588
- package/integration/hubspot/hubspot-datasource-users.json +0 -116
- package/integration/hubspot/test-artifacts/wizard-invalid-missing-source.yaml +0 -2
- package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-key-test.yaml +0 -5
- package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-path-test.yaml +0 -5
- package/lib/api/external-test.api.js +0 -111
- package/lib/schema/env-config.yaml +0 -43
- /package/integration/{hubspot → hubspot-test}/companies.json +0 -0
- /package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-app-name.yaml +0 -0
- /package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-missing-app.yaml +0 -0
- /package/integration/{hubspot → hubspot-test}/test-dataplane-down-helpers.js +0 -0
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Datasource repair helpers: align dimensions, metadataSchema, exposed, sync, testPayload
|
|
3
|
-
* with fieldMappings.attributes as source of truth.
|
|
3
|
+
* with fieldMappings.attributes as source of truth (external-datasource schema v2.4+).
|
|
4
4
|
*
|
|
5
5
|
* @fileoverview Repair datasource files for external integration
|
|
6
6
|
* @author AI Fabrix Team
|
|
7
|
-
* @version 2.
|
|
7
|
+
* @version 2.2.0
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
11
11
|
|
|
12
12
|
const DEFAULT_SYNC = {
|
|
13
13
|
mode: 'pull',
|
|
14
|
-
batchSize: 500
|
|
15
|
-
maxParallelRequests: 5
|
|
14
|
+
batchSize: 500
|
|
16
15
|
};
|
|
17
16
|
|
|
18
17
|
const MINIMAL_METADATA_SCHEMA = {
|
|
@@ -20,6 +19,61 @@ const MINIMAL_METADATA_SCHEMA = {
|
|
|
20
19
|
additionalProperties: true
|
|
21
20
|
};
|
|
22
21
|
|
|
22
|
+
/** Plan 346 / v2.4.1 closed root for testPayload */
|
|
23
|
+
const TEST_PAYLOAD_TOP_LEVEL_ALLOW = new Set([
|
|
24
|
+
'mode',
|
|
25
|
+
'primaryKey',
|
|
26
|
+
'scenarios',
|
|
27
|
+
'fk',
|
|
28
|
+
'actors',
|
|
29
|
+
'payloadTemplate',
|
|
30
|
+
'expectedResult'
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {string|undefined} entityType - entityType from datasource
|
|
35
|
+
* @returns {boolean}
|
|
36
|
+
*/
|
|
37
|
+
function isNoneEntityType(entityType) {
|
|
38
|
+
return entityType === 'none';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @param {string|undefined} entityType - entityType from datasource
|
|
43
|
+
* @returns {boolean}
|
|
44
|
+
*/
|
|
45
|
+
function isStorageEntityType(entityType) {
|
|
46
|
+
return entityType === 'recordStorage' || entityType === 'documentStorage';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Ensures metadataSchema.properties.externalId for recordStorage/documentStorage (schema v2.4).
|
|
51
|
+
* @param {Object} parsed - Parsed datasource (mutated)
|
|
52
|
+
* @param {string[]} changes - Change log
|
|
53
|
+
* @returns {boolean} True if externalId was added or corrected
|
|
54
|
+
*/
|
|
55
|
+
function ensureStorageExternalIdMetadataProperty(parsed, changes) {
|
|
56
|
+
if (!isStorageEntityType(parsed?.entityType)) return false;
|
|
57
|
+
if (!parsed.metadataSchema || typeof parsed.metadataSchema !== 'object') return false;
|
|
58
|
+
if (!parsed.metadataSchema.properties || typeof parsed.metadataSchema.properties !== 'object') {
|
|
59
|
+
parsed.metadataSchema.properties = {};
|
|
60
|
+
}
|
|
61
|
+
const props = parsed.metadataSchema.properties;
|
|
62
|
+
const ext = props.externalId;
|
|
63
|
+
const ok = ext
|
|
64
|
+
&& typeof ext === 'object'
|
|
65
|
+
&& ext.type === 'string'
|
|
66
|
+
&& ext.index === true;
|
|
67
|
+
if (ok) return false;
|
|
68
|
+
props.externalId = {
|
|
69
|
+
...(typeof ext === 'object' && ext !== null ? ext : {}),
|
|
70
|
+
type: 'string',
|
|
71
|
+
index: true
|
|
72
|
+
};
|
|
73
|
+
changes.push('Ensured metadataSchema.properties.externalId (type string, index true) for storage entityType');
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
|
|
23
77
|
/**
|
|
24
78
|
* Returns the set of attribute keys from fieldMappings.attributes.
|
|
25
79
|
* @param {Object} parsed - Parsed datasource object
|
|
@@ -32,12 +86,24 @@ function getAttributeKeys(parsed) {
|
|
|
32
86
|
}
|
|
33
87
|
|
|
34
88
|
/**
|
|
35
|
-
*
|
|
89
|
+
* @param {string} path - Normalized path (raw. prefix already stripped)
|
|
90
|
+
* @param {string[]} paths
|
|
91
|
+
* @param {Set<string>} topLevelKeys
|
|
92
|
+
* @param {Set<string>} referencedSchemaPropertyNames
|
|
93
|
+
*/
|
|
94
|
+
function accumulatePathSegments(path, paths, topLevelKeys, referencedSchemaPropertyNames) {
|
|
95
|
+
paths.push(path);
|
|
96
|
+
const segments = path.split('.');
|
|
97
|
+
const first = segments[0];
|
|
98
|
+
if (first) topLevelKeys.add(first);
|
|
99
|
+
if (first === 'metadata' && segments.length >= 2 && segments[1]) {
|
|
100
|
+
referencedSchemaPropertyNames.add(segments[1]);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Extracts paths from attribute expressions (e.g. {{ metadata.email }}, {{ raw.id }}).
|
|
36
106
|
* Skips record_ref: expressions.
|
|
37
|
-
* - topLevelKeys: first segment of each path (e.g. "metadata" from "metadata.id").
|
|
38
|
-
* - referencedSchemaPropertyNames: for paths like "metadata.xxx" or "metadata.xxx.yyy", the name "xxx"
|
|
39
|
-
* (the first property under metadata). Used to prune metadataSchema.properties so we only keep
|
|
40
|
-
* properties that are referenced; we do not compare against "metadata" or the schema would be wiped.
|
|
41
107
|
*
|
|
42
108
|
* @param {Object} attributes - fieldMappings.attributes object
|
|
43
109
|
* @returns {{ paths: string[], topLevelKeys: Set<string>, referencedSchemaPropertyNames: Set<string> }}
|
|
@@ -46,111 +112,246 @@ function parsePathsFromExpressions(attributes) {
|
|
|
46
112
|
const paths = [];
|
|
47
113
|
const topLevelKeys = new Set();
|
|
48
114
|
const referencedSchemaPropertyNames = new Set();
|
|
49
|
-
if (!attributes || typeof attributes !== 'object')
|
|
115
|
+
if (!attributes || typeof attributes !== 'object') {
|
|
116
|
+
return { paths, topLevelKeys, referencedSchemaPropertyNames };
|
|
117
|
+
}
|
|
50
118
|
for (const attr of Object.values(attributes)) {
|
|
51
119
|
const expr = attr?.expression;
|
|
52
120
|
if (typeof expr !== 'string') continue;
|
|
53
121
|
if (/^\s*record_ref:/i.test(expr.trim())) continue;
|
|
54
122
|
const match = expr.match(/\{\{\s*([^}]+)\s*\}\}/);
|
|
55
123
|
if (!match) continue;
|
|
56
|
-
|
|
57
|
-
if (path)
|
|
58
|
-
|
|
59
|
-
const segments = path.split('.');
|
|
60
|
-
const first = segments[0];
|
|
61
|
-
if (first) topLevelKeys.add(first);
|
|
62
|
-
if (first === 'metadata' && segments.length >= 2 && segments[1]) {
|
|
63
|
-
referencedSchemaPropertyNames.add(segments[1]);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
124
|
+
let path = match[1].trim().split('|')[0].trim();
|
|
125
|
+
if (path.startsWith('raw.')) path = path.slice(4);
|
|
126
|
+
if (path) accumulatePathSegments(path, paths, topLevelKeys, referencedSchemaPropertyNames);
|
|
66
127
|
}
|
|
67
128
|
return { paths, topLevelKeys, referencedSchemaPropertyNames };
|
|
68
129
|
}
|
|
69
130
|
|
|
70
131
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
132
|
+
* @param {Object} binding - dimension binding
|
|
133
|
+
* @param {string} dimKey - dimension key
|
|
134
|
+
* @param {string[]} changes - Change log
|
|
135
|
+
* @returns {boolean}
|
|
136
|
+
*/
|
|
137
|
+
function removeOperatorWithoutActor(binding, dimKey, changes) {
|
|
138
|
+
if (binding.operator && !binding.actor) {
|
|
139
|
+
delete binding.operator;
|
|
140
|
+
changes.push(`Removed 'operator' from dimension '${dimKey}' (no actor)`);
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* @param {string} dimKey - dimension key
|
|
148
|
+
* @param {Object} binding - dimension binding
|
|
149
|
+
* @param {string[]} changes - Change log
|
|
150
|
+
* @returns {boolean}
|
|
151
|
+
*/
|
|
152
|
+
function repairFkDimensionBinding(dimKey, binding, changes) {
|
|
153
|
+
let updated = false;
|
|
154
|
+
if (binding.field !== undefined) {
|
|
155
|
+
delete binding.field;
|
|
156
|
+
changes.push(`Removed invalid 'field' from FK dimension '${dimKey}'`);
|
|
157
|
+
updated = true;
|
|
158
|
+
}
|
|
159
|
+
return removeOperatorWithoutActor(binding, dimKey, changes) || updated;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* @param {string} dimKey - dimension key
|
|
164
|
+
* @param {Object} binding - dimension binding
|
|
165
|
+
* @param {string[]} changes - Change log
|
|
166
|
+
* @returns {boolean}
|
|
167
|
+
*/
|
|
168
|
+
function repairLocalDimensionBinding(dimKey, binding, changes) {
|
|
169
|
+
let updated = false;
|
|
170
|
+
if (binding.via !== undefined) {
|
|
171
|
+
delete binding.via;
|
|
172
|
+
changes.push(`Removed invalid 'via' from local dimension '${dimKey}'`);
|
|
173
|
+
updated = true;
|
|
174
|
+
}
|
|
175
|
+
return removeOperatorWithoutActor(binding, dimKey, changes) || updated;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Normalizes dimension bindings: FK vs local invariants; strip operator without actor.
|
|
180
|
+
* @param {Object} parsed - Parsed datasource (mutated)
|
|
181
|
+
* @param {string[]} changes - Change log
|
|
182
|
+
* @returns {boolean}
|
|
183
|
+
*/
|
|
184
|
+
function repairDimensionBindingShape(parsed, changes) {
|
|
185
|
+
const dims = parsed?.dimensions;
|
|
186
|
+
if (!dims || typeof dims !== 'object') return false;
|
|
187
|
+
let updated = false;
|
|
188
|
+
for (const [dimKey, binding] of Object.entries(dims)) {
|
|
189
|
+
if (!binding || typeof binding !== 'object') continue;
|
|
190
|
+
const t = binding.type;
|
|
191
|
+
if (t === 'fk') {
|
|
192
|
+
updated = repairFkDimensionBinding(dimKey, binding, changes) || updated;
|
|
193
|
+
} else if (t === 'local' || t === undefined) {
|
|
194
|
+
updated = repairLocalDimensionBinding(dimKey, binding, changes) || updated;
|
|
195
|
+
} else {
|
|
196
|
+
updated = removeOperatorWithoutActor(binding, dimKey, changes) || updated;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return updated;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Removes root local dimension bindings whose field is not in fieldMappings.attributes.
|
|
204
|
+
* Skips FK bindings.
|
|
74
205
|
* @param {Object} parsed - Parsed datasource (mutated)
|
|
75
|
-
* @param {string[]} changes -
|
|
206
|
+
* @param {string[]} changes - Change log
|
|
76
207
|
* @returns {boolean} True if any dimension was removed
|
|
77
208
|
*/
|
|
78
|
-
function
|
|
79
|
-
const dims = parsed?.
|
|
209
|
+
function repairRootDimensionsFromAttributes(parsed, changes) {
|
|
210
|
+
const dims = parsed?.dimensions;
|
|
80
211
|
if (!dims || typeof dims !== 'object') return false;
|
|
81
212
|
const attributeKeys = getAttributeKeys(parsed);
|
|
82
213
|
let updated = false;
|
|
83
|
-
for (const [dimKey,
|
|
84
|
-
if (typeof
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
|
|
214
|
+
for (const [dimKey, binding] of Object.entries(dims)) {
|
|
215
|
+
if (!binding || typeof binding !== 'object') continue;
|
|
216
|
+
if (binding.type === 'fk') continue;
|
|
217
|
+
if (binding.type !== undefined && binding.type !== 'local') continue;
|
|
218
|
+
const field = binding.field;
|
|
219
|
+
if (typeof field !== 'string') continue;
|
|
220
|
+
if (attributeKeys.has(field)) continue;
|
|
88
221
|
delete dims[dimKey];
|
|
89
|
-
changes.push(`Removed dimension '${dimKey}': ${
|
|
222
|
+
changes.push(`Removed root dimension '${dimKey}': field '${field}' not in fieldMappings.attributes`);
|
|
90
223
|
updated = true;
|
|
91
224
|
}
|
|
92
225
|
return updated;
|
|
93
226
|
}
|
|
94
227
|
|
|
95
228
|
/**
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
229
|
+
* Adds metadataSchema property stubs for metadata.* paths referenced in attributes.
|
|
230
|
+
* @param {Object} parsed - Parsed datasource (mutated)
|
|
231
|
+
* @param {Set<string>} referencedSchemaPropertyNames - Property names under metadata
|
|
232
|
+
* @param {string[]} changes - Change log
|
|
233
|
+
* @returns {boolean}
|
|
234
|
+
*/
|
|
235
|
+
function ensureMetadataSchemaPropertyStubs(parsed, referencedSchemaPropertyNames, changes) {
|
|
236
|
+
if (!referencedSchemaPropertyNames || referencedSchemaPropertyNames.size === 0) return false;
|
|
237
|
+
if (!parsed.metadataSchema || typeof parsed.metadataSchema !== 'object') return false;
|
|
238
|
+
if (!parsed.metadataSchema.properties || typeof parsed.metadataSchema.properties !== 'object') {
|
|
239
|
+
parsed.metadataSchema.properties = {};
|
|
240
|
+
}
|
|
241
|
+
const props = parsed.metadataSchema.properties;
|
|
242
|
+
const added = [];
|
|
243
|
+
for (const name of referencedSchemaPropertyNames) {
|
|
244
|
+
if (!name || props[name] !== undefined) continue;
|
|
245
|
+
props[name] = { type: 'string' };
|
|
246
|
+
added.push(name);
|
|
247
|
+
}
|
|
248
|
+
if (added.length === 0) return false;
|
|
249
|
+
changes.push(`Added metadataSchema.properties stubs for [${added.join(', ')}]`);
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* @param {Object} parsed - Parsed datasource (mutated)
|
|
255
|
+
* @param {Set<string>} referencedSchemaPropertyNames - metadata.* names from expressions
|
|
256
|
+
* @param {string[]} changes - Change log
|
|
257
|
+
* @returns {boolean}
|
|
258
|
+
*/
|
|
259
|
+
function pruneMetadataSchemaPropertiesByAttributeRefs(parsed, referencedSchemaPropertyNames, changes) {
|
|
260
|
+
const props = parsed.metadataSchema?.properties;
|
|
261
|
+
if (
|
|
262
|
+
!props || typeof props !== 'object'
|
|
263
|
+
|| referencedSchemaPropertyNames.size === 0
|
|
264
|
+
) {
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
const toRemove = Object.keys(props).filter(k => {
|
|
268
|
+
if (referencedSchemaPropertyNames.has(k)) return false;
|
|
269
|
+
if (isStorageEntityType(parsed.entityType) && k === 'externalId') return false;
|
|
270
|
+
return true;
|
|
271
|
+
});
|
|
272
|
+
if (toRemove.length === 0) return false;
|
|
273
|
+
toRemove.forEach(k => delete props[k]);
|
|
274
|
+
changes.push(`Pruned metadataSchema.properties: removed [${toRemove.join(', ')}] (not referenced by attributes)`);
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Ensures metadataSchema exists (minimal stub if missing). Prunes top-level properties not
|
|
280
|
+
* referenced by metadata.* paths in expressions (after stripping raw. prefix).
|
|
281
|
+
* Skipped entirely for entityType 'none'.
|
|
100
282
|
*
|
|
101
283
|
* @param {Object} parsed - Parsed datasource (mutated)
|
|
102
|
-
* @param {string[]} changes -
|
|
284
|
+
* @param {string[]} changes - Change log
|
|
103
285
|
* @returns {boolean} True if schema was added or pruned
|
|
104
286
|
*/
|
|
105
287
|
function repairMetadataSchemaFromAttributes(parsed, changes) {
|
|
288
|
+
if (isNoneEntityType(parsed?.entityType)) {
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
106
291
|
const { referencedSchemaPropertyNames } = parsePathsFromExpressions(parsed?.fieldMappings?.attributes ?? {});
|
|
292
|
+
let updated = false;
|
|
293
|
+
|
|
107
294
|
if (!parsed.metadataSchema || typeof parsed.metadataSchema !== 'object') {
|
|
108
|
-
parsed.metadataSchema = { ...MINIMAL_METADATA_SCHEMA };
|
|
295
|
+
parsed.metadataSchema = { ...MINIMAL_METADATA_SCHEMA, properties: {} };
|
|
109
296
|
changes.push('Added minimal metadataSchema (was missing)');
|
|
110
|
-
|
|
297
|
+
ensureMetadataSchemaPropertyStubs(parsed, referencedSchemaPropertyNames, changes);
|
|
298
|
+
updated = true;
|
|
299
|
+
} else {
|
|
300
|
+
if (pruneMetadataSchemaPropertiesByAttributeRefs(parsed, referencedSchemaPropertyNames, changes)) {
|
|
301
|
+
updated = true;
|
|
302
|
+
}
|
|
303
|
+
if (ensureMetadataSchemaPropertyStubs(parsed, referencedSchemaPropertyNames, changes)) {
|
|
304
|
+
updated = true;
|
|
305
|
+
}
|
|
111
306
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if (toRemove.length === 0) return false;
|
|
117
|
-
toRemove.forEach(k => delete props[k]);
|
|
118
|
-
changes.push(`Pruned metadataSchema.properties: removed [${toRemove.join(', ')}] (not referenced by attributes)`);
|
|
119
|
-
return true;
|
|
307
|
+
if (ensureStorageExternalIdMetadataProperty(parsed, changes)) {
|
|
308
|
+
updated = true;
|
|
309
|
+
}
|
|
310
|
+
return updated;
|
|
120
311
|
}
|
|
121
312
|
|
|
122
313
|
/**
|
|
123
|
-
* Sets exposed.
|
|
124
|
-
*
|
|
314
|
+
* Sets exposed.schema from fieldMappings.attributes keys (metadata.<key> leaves). v2.4 canonical.
|
|
315
|
+
* Removes deprecated exposed.attributes when present so output matches schema.
|
|
125
316
|
*
|
|
126
317
|
* @param {Object} parsed - Parsed datasource (mutated)
|
|
127
|
-
* @param {string[]} changes -
|
|
318
|
+
* @param {string[]} changes - Change log
|
|
128
319
|
* @returns {boolean} True if exposed was updated
|
|
129
320
|
*/
|
|
130
321
|
function repairExposeFromAttributes(parsed, changes) {
|
|
131
322
|
const keys = Array.from(getAttributeKeys(parsed)).filter(Boolean).sort();
|
|
132
323
|
if (keys.length === 0) return false;
|
|
133
324
|
if (!parsed.exposed) parsed.exposed = {};
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
325
|
+
const schema = {};
|
|
326
|
+
keys.forEach(k => {
|
|
327
|
+
schema[k] = `metadata.${k}`;
|
|
328
|
+
});
|
|
329
|
+
const prev = parsed.exposed.schema;
|
|
330
|
+
const same = prev && typeof prev === 'object'
|
|
331
|
+
&& keys.length === Object.keys(prev).length
|
|
332
|
+
&& keys.every(k => prev[k] === schema[k]);
|
|
333
|
+
if (same && parsed.exposed.attributes === undefined) return false;
|
|
334
|
+
parsed.exposed.schema = schema;
|
|
335
|
+
if (parsed.exposed.attributes !== undefined) {
|
|
336
|
+
delete parsed.exposed.attributes;
|
|
337
|
+
}
|
|
338
|
+
changes.push(`Set exposed.schema for [${keys.join(', ')}]`);
|
|
139
339
|
return true;
|
|
140
340
|
}
|
|
141
341
|
|
|
142
342
|
/**
|
|
143
|
-
* Adds default sync section if missing or empty.
|
|
343
|
+
* Adds default sync section if missing or empty. Not applied for entityType 'none'.
|
|
144
344
|
*
|
|
145
345
|
* @param {Object} parsed - Parsed datasource (mutated)
|
|
146
|
-
* @param {string[]} changes -
|
|
346
|
+
* @param {string[]} changes - Change log
|
|
147
347
|
* @returns {boolean} True if sync was added
|
|
148
348
|
*/
|
|
149
349
|
function repairSyncSection(parsed, changes) {
|
|
350
|
+
if (isNoneEntityType(parsed?.entityType)) return false;
|
|
150
351
|
const sync = parsed.sync;
|
|
151
352
|
if (sync && typeof sync === 'object' && Object.keys(sync).length > 0) return false;
|
|
152
353
|
parsed.sync = { ...DEFAULT_SYNC };
|
|
153
|
-
changes.push('Added default sync section (mode: pull, batchSize: 500
|
|
354
|
+
changes.push('Added default sync section (mode: pull, batchSize: 500)');
|
|
154
355
|
return true;
|
|
155
356
|
}
|
|
156
357
|
|
|
@@ -173,11 +374,32 @@ function setNested(obj, pathParts, value) {
|
|
|
173
374
|
if (last) cur[last] = value;
|
|
174
375
|
}
|
|
175
376
|
|
|
377
|
+
/**
|
|
378
|
+
* Removes unknown top-level keys from testPayload (v2.4.1 closed root).
|
|
379
|
+
* @param {Object} parsed - Parsed datasource (mutated)
|
|
380
|
+
* @param {string[]} changes - Change log
|
|
381
|
+
* @returns {boolean}
|
|
382
|
+
*/
|
|
383
|
+
function sanitizeTestPayloadTopLevel(parsed, changes) {
|
|
384
|
+
const tp = parsed?.testPayload;
|
|
385
|
+
if (!tp || typeof tp !== 'object' || Array.isArray(tp)) return false;
|
|
386
|
+
const removed = [];
|
|
387
|
+
for (const key of Object.keys(tp)) {
|
|
388
|
+
if (!TEST_PAYLOAD_TOP_LEVEL_ALLOW.has(key)) {
|
|
389
|
+
delete tp[key];
|
|
390
|
+
removed.push(key);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
if (removed.length === 0) return false;
|
|
394
|
+
changes.push(`Removed unknown testPayload keys: [${removed.join(', ')}]`);
|
|
395
|
+
return true;
|
|
396
|
+
}
|
|
397
|
+
|
|
176
398
|
/**
|
|
177
399
|
* Builds minimal payloadTemplate and expectedResult from attribute expression paths.
|
|
178
400
|
*
|
|
179
401
|
* @param {Object} parsed - Parsed datasource (mutated)
|
|
180
|
-
* @param {string[]} changes -
|
|
402
|
+
* @param {string[]} changes - Change log
|
|
181
403
|
* @returns {boolean} True if testPayload was added or updated
|
|
182
404
|
*/
|
|
183
405
|
function repairTestPayload(parsed, changes) {
|
|
@@ -191,7 +413,10 @@ function repairTestPayload(parsed, changes) {
|
|
|
191
413
|
expectedResult[key] = placeholder;
|
|
192
414
|
const match = config?.expression?.match(/\{\{\s*([^}|]+)/);
|
|
193
415
|
if (match) {
|
|
194
|
-
|
|
416
|
+
let path = match[1].trim();
|
|
417
|
+
if (path.startsWith('raw.')) {
|
|
418
|
+
path = path.slice(4);
|
|
419
|
+
}
|
|
195
420
|
setNested(payloadTemplate, path.split('.'), placeholder);
|
|
196
421
|
}
|
|
197
422
|
}
|
|
@@ -203,7 +428,7 @@ function repairTestPayload(parsed, changes) {
|
|
|
203
428
|
}
|
|
204
429
|
|
|
205
430
|
/**
|
|
206
|
-
* Runs all requested datasource repairs.
|
|
431
|
+
* Runs all requested datasource repairs.
|
|
207
432
|
*
|
|
208
433
|
* @param {Object} parsed - Parsed datasource object (mutated)
|
|
209
434
|
* @param {Object} options - { expose?: boolean, sync?: boolean, test?: boolean }
|
|
@@ -213,23 +438,44 @@ function repairTestPayload(parsed, changes) {
|
|
|
213
438
|
function repairDatasourceFile(parsed, options = {}, changes = []) {
|
|
214
439
|
const out = Array.isArray(changes) ? changes : [];
|
|
215
440
|
let updated = false;
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
if (
|
|
219
|
-
|
|
220
|
-
|
|
441
|
+
const none = isNoneEntityType(parsed?.entityType);
|
|
442
|
+
|
|
443
|
+
if (!none) {
|
|
444
|
+
updated = repairDimensionBindingShape(parsed, out) || updated;
|
|
445
|
+
updated = repairRootDimensionsFromAttributes(parsed, out) || updated;
|
|
446
|
+
updated = repairMetadataSchemaFromAttributes(parsed, out) || updated;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
if (options.expose) {
|
|
450
|
+
updated = repairExposeFromAttributes(parsed, out) || updated;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
if (!none && options.sync) {
|
|
454
|
+
updated = repairSyncSection(parsed, out) || updated;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
if (options.test) {
|
|
458
|
+
sanitizeTestPayloadTopLevel(parsed, out);
|
|
459
|
+
updated = repairTestPayload(parsed, out) || updated;
|
|
460
|
+
updated = sanitizeTestPayloadTopLevel(parsed, out) || updated;
|
|
461
|
+
}
|
|
462
|
+
|
|
221
463
|
return { updated, changes: out };
|
|
222
464
|
}
|
|
223
465
|
|
|
224
466
|
module.exports = {
|
|
225
467
|
getAttributeKeys,
|
|
226
468
|
parsePathsFromExpressions,
|
|
227
|
-
|
|
469
|
+
repairDimensionBindingShape,
|
|
470
|
+
repairRootDimensionsFromAttributes,
|
|
228
471
|
repairMetadataSchemaFromAttributes,
|
|
229
472
|
repairExposeFromAttributes,
|
|
230
473
|
repairSyncSection,
|
|
231
474
|
repairTestPayload,
|
|
475
|
+
sanitizeTestPayloadTopLevel,
|
|
232
476
|
repairDatasourceFile,
|
|
233
477
|
DEFAULT_SYNC,
|
|
234
|
-
MINIMAL_METADATA_SCHEMA
|
|
478
|
+
MINIMAL_METADATA_SCHEMA,
|
|
479
|
+
TEST_PAYLOAD_TOP_LEVEL_ALLOW,
|
|
480
|
+
isNoneEntityType
|
|
235
481
|
};
|
|
@@ -11,10 +11,11 @@ const path = require('path');
|
|
|
11
11
|
const fs = require('fs');
|
|
12
12
|
const { systemKeyToKvPrefix, kvEnvKeyToPath, securityKeyToVar } = require('../utils/credential-secrets-env');
|
|
13
13
|
const { extractEnvTemplate } = require('../generator/split');
|
|
14
|
+
const { generateExternalEnvTemplateContent } = require('../utils/external-env-template');
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Normalizes a keyvault config entry to canonical KV_* name and path-style value.
|
|
17
|
-
* Path format: kv://<
|
|
18
|
+
* Path format: kv://<systemKey>/<variable> (e.g. kv://microsoft-teams/clientId).
|
|
18
19
|
* @param {Object} entry - Config entry with name, value, location
|
|
19
20
|
* @param {string} prefix - KV prefix (e.g. MICROSOFT_TEAMS)
|
|
20
21
|
* @param {string} systemKey - System key (e.g. microsoft-teams) for path namespace
|
|
@@ -65,7 +66,7 @@ function addFromConfiguration(effective, config, prefix, seenNames, systemKey) {
|
|
|
65
66
|
|
|
66
67
|
/**
|
|
67
68
|
* Adds effective config entries from authentication.security.
|
|
68
|
-
* Path format: kv://<
|
|
69
|
+
* Path format: kv://<systemKey>/<variable> (e.g. kv://microsoft-teams/clientId).
|
|
69
70
|
* @param {Array} effective - Mutable result array
|
|
70
71
|
* @param {Object} systemParsed - Parsed system config
|
|
71
72
|
* @param {string} prefix - KV prefix
|
|
@@ -126,20 +127,25 @@ function buildExpectedByKey(effective) {
|
|
|
126
127
|
}
|
|
127
128
|
|
|
128
129
|
/**
|
|
129
|
-
* Creates env.template when missing
|
|
130
|
+
* Creates env.template when missing using the Handlebars template (Authentication + Configuration sections).
|
|
130
131
|
* @param {string} envPath - Path to env.template
|
|
131
|
-
* @param {Map<string, string>} expectedByKey - Expected key->line map
|
|
132
|
+
* @param {Map<string, string>} expectedByKey - Expected key->line map (fallback when no systemParsed)
|
|
132
133
|
* @param {boolean} dryRun - If true, do not write
|
|
133
134
|
* @param {string[]} changes - Array to append to
|
|
135
|
+
* @param {Object} [systemParsed] - Parsed system config for template context (preferred)
|
|
134
136
|
* @returns {boolean}
|
|
135
137
|
*/
|
|
136
|
-
function createEnvTemplateIfMissing(envPath, expectedByKey, dryRun, changes) {
|
|
138
|
+
function createEnvTemplateIfMissing(envPath, expectedByKey, dryRun, changes, systemParsed) {
|
|
137
139
|
if (fs.existsSync(envPath)) return false;
|
|
138
|
-
|
|
139
|
-
const content =
|
|
140
|
-
|
|
140
|
+
if (expectedByKey.size === 0) return false;
|
|
141
|
+
const content = systemParsed
|
|
142
|
+
? generateExternalEnvTemplateContent(systemParsed)
|
|
143
|
+
: Array.from(expectedByKey.values()).join('\n');
|
|
144
|
+
if (!content || !content.trim()) return false;
|
|
145
|
+
const hasKeyValueLine = /^[A-Z_][A-Z0-9_]*=/m.test(content);
|
|
146
|
+
if (!hasKeyValueLine) return false;
|
|
141
147
|
if (!dryRun) {
|
|
142
|
-
fs.writeFileSync(envPath, content + '\n', { mode: 0o644, encoding: 'utf8' });
|
|
148
|
+
fs.writeFileSync(envPath, content + (content.endsWith('\n') ? '' : '\n'), { mode: 0o644, encoding: 'utf8' });
|
|
143
149
|
}
|
|
144
150
|
changes.push('Created env.template from system configuration');
|
|
145
151
|
return true;
|
|
@@ -236,7 +242,7 @@ function repairEnvTemplate(appPath, systemParsed, systemKey, dryRun, changes) {
|
|
|
236
242
|
const expectedByKey = buildExpectedByKey(effective);
|
|
237
243
|
const envPath = path.join(appPath, 'env.template');
|
|
238
244
|
|
|
239
|
-
if (createEnvTemplateIfMissing(envPath, expectedByKey, dryRun, changes)) {
|
|
245
|
+
if (createEnvTemplateIfMissing(envPath, expectedByKey, dryRun, changes, systemParsed)) {
|
|
240
246
|
return true;
|
|
241
247
|
}
|
|
242
248
|
if (!fs.existsSync(envPath)) {
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
|
|
11
11
|
const path = require('path');
|
|
12
12
|
const fs = require('fs');
|
|
13
|
-
const yaml = require('js-yaml');
|
|
14
13
|
const chalk = require('chalk');
|
|
15
14
|
const logger = require('../utils/logger');
|
|
16
|
-
const { loadConfigFile } = require('../utils/config-format');
|
|
15
|
+
const { loadConfigFile, writeConfigFile } = require('../utils/config-format');
|
|
16
|
+
const { resolveRbacPath } = require('../utils/app-config-resolver');
|
|
17
17
|
|
|
18
18
|
const DEFAULT_CAPABILITIES = ['list', 'get', 'create', 'update', 'delete'];
|
|
19
19
|
|
|
@@ -55,26 +55,30 @@ function collectPermissionNames(appPath, datasourceFiles) {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
|
-
* Loads existing rbac or creates empty structure.
|
|
58
|
+
* Loads existing RBAC file (rbac.yaml, rbac.yml, or rbac.json) or creates empty structure.
|
|
59
|
+
* Uses extractRbacFromSystem when no file exists. New file path respects format (rbac.json when format is 'json').
|
|
60
|
+
*
|
|
59
61
|
* @param {string} appPath - Application path
|
|
60
62
|
* @param {Object} [systemParsed] - Parsed system for extractRbacFromSystem
|
|
61
63
|
* @param {Function} extractRbacFromSystem - (system) => rbac or null
|
|
62
|
-
* @
|
|
64
|
+
* @param {string} [format] - 'json' or 'yaml'; used only when creating a new file (default 'yaml')
|
|
65
|
+
* @returns {{ rbac: Object, rbacPath: string }} rbacPath is resolved path or path.join(appPath, 'rbac.{json|yaml}') for new file
|
|
63
66
|
*/
|
|
64
|
-
function loadOrCreateRbac(appPath, systemParsed, extractRbacFromSystem) {
|
|
65
|
-
const
|
|
66
|
-
const rbacYmlPath = path.join(appPath, 'rbac.yml');
|
|
67
|
+
function loadOrCreateRbac(appPath, systemParsed, extractRbacFromSystem, format) {
|
|
68
|
+
const resolvedPath = resolveRbacPath(appPath);
|
|
67
69
|
let rbac;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
let rbacPath;
|
|
71
|
+
if (resolvedPath) {
|
|
72
|
+
rbac = loadConfigFile(resolvedPath);
|
|
73
|
+
rbacPath = resolvedPath;
|
|
72
74
|
} else {
|
|
73
75
|
rbac = extractRbacFromSystem(systemParsed) || { roles: [], permissions: [] };
|
|
74
76
|
if (!Array.isArray(rbac.roles)) rbac.roles = [];
|
|
75
77
|
if (!Array.isArray(rbac.permissions)) rbac.permissions = [];
|
|
78
|
+
const ext = (format === 'json') ? 'rbac.json' : 'rbac.yaml';
|
|
79
|
+
rbacPath = path.join(appPath, ext);
|
|
76
80
|
}
|
|
77
|
-
return { rbac, rbacPath
|
|
81
|
+
return { rbac, rbacPath };
|
|
78
82
|
}
|
|
79
83
|
|
|
80
84
|
/**
|
|
@@ -123,31 +127,33 @@ function ensureDefaultRoles(rbac, systemKey, displayName, changes) {
|
|
|
123
127
|
if (p.name && listGetPerms.includes(p.name) && !p.roles.includes(readerValue)) p.roles.push(readerValue);
|
|
124
128
|
if (!p.roles.includes(adminValue)) p.roles.push(adminValue);
|
|
125
129
|
}
|
|
126
|
-
changes.push('Added default Admin and Reader roles to rbac
|
|
130
|
+
changes.push('Added default Admin and Reader roles to rbac file');
|
|
127
131
|
return true;
|
|
128
132
|
}
|
|
129
133
|
|
|
130
134
|
/**
|
|
131
135
|
* Merges RBAC from datasources: ensures permission per resourceType:capability, adds Admin/Reader roles if none.
|
|
136
|
+
* When creating a new RBAC file, uses rbac.json if format is 'json', otherwise rbac.yaml.
|
|
137
|
+
*
|
|
132
138
|
* @param {string} appPath - Application path
|
|
133
139
|
* @param {Object} systemParsed - Parsed system (key, displayName)
|
|
134
140
|
* @param {string[]} datasourceFiles - Datasource file names
|
|
135
141
|
* @param {Function} extractRbacFromSystem - (system) => rbac or null
|
|
136
|
-
* @param {boolean}
|
|
137
|
-
* @param {string[]} changes - Array to append change descriptions to
|
|
142
|
+
* @param {{ format?: string, dryRun: boolean, changes: string[] }} options - format ('json'|'yaml'), dryRun, changes array
|
|
138
143
|
* @returns {boolean} True if rbac was updated (or would be in dry-run)
|
|
139
144
|
*/
|
|
140
|
-
function mergeRbacFromDatasources(appPath, systemParsed, datasourceFiles, extractRbacFromSystem,
|
|
145
|
+
function mergeRbacFromDatasources(appPath, systemParsed, datasourceFiles, extractRbacFromSystem, options) {
|
|
146
|
+
const { format = 'yaml', dryRun, changes } = options;
|
|
147
|
+
const rbacFormat = format === 'json' ? 'json' : 'yaml';
|
|
141
148
|
const permissionNames = collectPermissionNames(appPath, datasourceFiles);
|
|
142
149
|
if (permissionNames.size === 0) return false;
|
|
143
150
|
const systemKey = systemParsed?.key || 'system';
|
|
144
151
|
const displayName = systemParsed?.displayName || systemKey;
|
|
145
|
-
const { rbac, rbacPath
|
|
152
|
+
const { rbac, rbacPath } = loadOrCreateRbac(appPath, systemParsed, extractRbacFromSystem, rbacFormat);
|
|
146
153
|
let updated = addMissingPermissions(rbac, permissionNames, changes);
|
|
147
154
|
updated = ensureDefaultRoles(rbac, systemKey, displayName, changes) || updated;
|
|
148
155
|
if (updated && !dryRun) {
|
|
149
|
-
|
|
150
|
-
fs.writeFileSync(outPath, yaml.dump(rbac, { indent: 2, lineWidth: -1 }), { mode: 0o644, encoding: 'utf8' });
|
|
156
|
+
writeConfigFile(rbacPath, rbac);
|
|
151
157
|
}
|
|
152
158
|
return updated;
|
|
153
159
|
}
|