@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
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Exit code matrix for DatasourceTestRun after successful HTTP (plan §3.1).
|
|
3
|
+
* HTTP/transport failures are exit 3 (handled by callers).
|
|
4
|
+
* @author AI Fabrix Team
|
|
5
|
+
* @version 2.0.0
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Compute CLI exit code from parsed DatasourceTestRun envelope.
|
|
10
|
+
* Ordering: status / warnings-as-errors → require-cert (§3.1).
|
|
11
|
+
* @param {import('../api/types/validation-run.types').DatasourceTestRunLike|null|undefined} body
|
|
12
|
+
* @param {Object} [opts]
|
|
13
|
+
* @param {boolean} [opts.warningsAsErrors]
|
|
14
|
+
* @param {boolean} [opts.requireCert]
|
|
15
|
+
* @returns {number} 0 | 1 | 2 | 3 (3 = treat as parse/body unusable)
|
|
16
|
+
*/
|
|
17
|
+
function computeExitCodeFromDatasourceTestRun(body, opts = {}) {
|
|
18
|
+
if (!body || typeof body !== 'object') {
|
|
19
|
+
return 3;
|
|
20
|
+
}
|
|
21
|
+
const status = body.status;
|
|
22
|
+
if (status === 'fail') {
|
|
23
|
+
return 1;
|
|
24
|
+
}
|
|
25
|
+
if (status === 'warn' && opts.warningsAsErrors === true) {
|
|
26
|
+
return 1;
|
|
27
|
+
}
|
|
28
|
+
if (status === 'ok' || status === 'skipped' || status === 'warn') {
|
|
29
|
+
if (opts.requireCert === true) {
|
|
30
|
+
const cert = body.certificate;
|
|
31
|
+
if (!cert) {
|
|
32
|
+
return 2;
|
|
33
|
+
}
|
|
34
|
+
if (cert.status === 'not_passed') {
|
|
35
|
+
return 2;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return 0;
|
|
39
|
+
}
|
|
40
|
+
return 3;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Exit code for poll timeout with last envelope (plan §3.4).
|
|
45
|
+
* @param {import('../api/types/validation-run.types').DatasourceTestRunLike|null} lastBody
|
|
46
|
+
* @returns {number} 1 if root fail, else 3
|
|
47
|
+
*/
|
|
48
|
+
function exitCodeForPollTimeout(lastBody) {
|
|
49
|
+
if (lastBody && typeof lastBody === 'object' && lastBody.status === 'fail') {
|
|
50
|
+
return 1;
|
|
51
|
+
}
|
|
52
|
+
return 3;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
module.exports = {
|
|
56
|
+
computeExitCodeFromDatasourceTestRun,
|
|
57
|
+
exitCodeForPollTimeout
|
|
58
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Map DatasourceTestRun envelope → legacy CLI display shapes (integration + E2E).
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 2.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @param {Object|null} envelope
|
|
9
|
+
* @returns {string|null}
|
|
10
|
+
*/
|
|
11
|
+
function firstIssueMessage(envelope) {
|
|
12
|
+
const v = envelope && envelope.validation;
|
|
13
|
+
const issues = v && Array.isArray(v.issues) ? v.issues : [];
|
|
14
|
+
const first = issues.find(i => i && (i.message || i.hint));
|
|
15
|
+
if (first) return String(first.message || first.hint);
|
|
16
|
+
const integ = envelope && envelope.integration;
|
|
17
|
+
const steps = integ && Array.isArray(integ.stepResults) ? integ.stepResults : [];
|
|
18
|
+
const bad = steps.find(s => s && s.success === false && (s.message || s.error));
|
|
19
|
+
if (bad) return String(bad.message || bad.error || 'Integration step failed');
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Legacy integration result for displayIntegrationTestResults / verbose details.
|
|
25
|
+
* @param {Object|null} envelope
|
|
26
|
+
* @param {string} datasourceKey
|
|
27
|
+
* @returns {Object}
|
|
28
|
+
*/
|
|
29
|
+
function integrationResultFromEnvelope(envelope, datasourceKey) {
|
|
30
|
+
if (!envelope || typeof envelope !== 'object') {
|
|
31
|
+
return {
|
|
32
|
+
key: datasourceKey,
|
|
33
|
+
systemKey: 'unknown',
|
|
34
|
+
success: false,
|
|
35
|
+
skipped: false,
|
|
36
|
+
validationResults: {},
|
|
37
|
+
fieldMappingResults: {},
|
|
38
|
+
endpointTestResults: {},
|
|
39
|
+
error: 'No report envelope',
|
|
40
|
+
envelope: null
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const success = envelope.status !== 'fail';
|
|
44
|
+
const err = success ? undefined : firstIssueMessage(envelope) || `status: ${envelope.status}`;
|
|
45
|
+
return {
|
|
46
|
+
key: datasourceKey,
|
|
47
|
+
systemKey: envelope.systemKey || 'unknown',
|
|
48
|
+
success,
|
|
49
|
+
skipped: false,
|
|
50
|
+
error: err,
|
|
51
|
+
envelope
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Map integration.stepResults → E2E-style steps for displayE2EResults.
|
|
57
|
+
* @param {Object|null} envelope
|
|
58
|
+
* @returns {{ steps: Object[], success: boolean, status?: string, error?: string }}
|
|
59
|
+
*/
|
|
60
|
+
function e2eShapeFromEnvelope(envelope) {
|
|
61
|
+
if (!envelope || typeof envelope !== 'object') {
|
|
62
|
+
return { steps: [], success: false, error: 'No report envelope' };
|
|
63
|
+
}
|
|
64
|
+
const integ = envelope.integration;
|
|
65
|
+
const raw = integ && Array.isArray(integ.stepResults) ? integ.stepResults : [];
|
|
66
|
+
const steps = raw.map(s => ({
|
|
67
|
+
name: s.name || 'step',
|
|
68
|
+
step: s.name,
|
|
69
|
+
success: s.success !== false,
|
|
70
|
+
message: s.message,
|
|
71
|
+
error: s.success === false ? s.message || 'failed' : undefined
|
|
72
|
+
}));
|
|
73
|
+
const success = envelope.status !== 'fail';
|
|
74
|
+
let status;
|
|
75
|
+
if (envelope.status === 'fail') status = 'failed';
|
|
76
|
+
else if (envelope.reportCompleteness && envelope.reportCompleteness !== 'full') {
|
|
77
|
+
status = 'completed';
|
|
78
|
+
} else {
|
|
79
|
+
status = 'completed';
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
steps,
|
|
83
|
+
success,
|
|
84
|
+
status,
|
|
85
|
+
error: success ? undefined : firstIssueMessage(envelope) || undefined
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = {
|
|
90
|
+
integrationResultFromEnvelope,
|
|
91
|
+
e2eShapeFromEnvelope,
|
|
92
|
+
firstIssueMessage
|
|
93
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview reportVersion compatibility warnings (plan §3.15).
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 2.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** CLI-supported major reportVersion (bump when breaking). */
|
|
8
|
+
const SUPPORTED_MAJOR = 1;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Parse leading major from semver-like string (e.g. 1.1.0 → 1).
|
|
12
|
+
* @param {string} v
|
|
13
|
+
* @returns {number|null}
|
|
14
|
+
*/
|
|
15
|
+
function parseMajor(v) {
|
|
16
|
+
if (!v || typeof v !== 'string') return null;
|
|
17
|
+
const m = /^v?(\d+)/.exec(v.trim());
|
|
18
|
+
if (!m) return null;
|
|
19
|
+
return parseInt(m[1], 10);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* stderr messages for reportVersion handling.
|
|
24
|
+
* @param {string|undefined} reportVersion - From envelope
|
|
25
|
+
* @returns {{ level: 'none'|'warn'|'info', message: string }|null}
|
|
26
|
+
*/
|
|
27
|
+
function getReportVersionStderrMessage(reportVersion) {
|
|
28
|
+
const major = parseMajor(reportVersion || '');
|
|
29
|
+
if (major === null) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
if (major < SUPPORTED_MAJOR - 1) {
|
|
33
|
+
return {
|
|
34
|
+
level: 'warn',
|
|
35
|
+
message: `reportVersion unsupported (got ${reportVersion}, support ${SUPPORTED_MAJOR - 1}–${SUPPORTED_MAJOR} major)`
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
if (major > SUPPORTED_MAJOR) {
|
|
39
|
+
return {
|
|
40
|
+
level: 'info',
|
|
41
|
+
message: 'Newer reportVersion; some fields may be ignored'
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = {
|
|
48
|
+
SUPPORTED_MAJOR,
|
|
49
|
+
parseMajor,
|
|
50
|
+
getReportVersionStderrMessage
|
|
51
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview SHA-256 compare Builder vs Dataplane DatasourceTestRun JSON Schema (plan §8.1).
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 2.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const crypto = require('crypto');
|
|
8
|
+
const { nodeFs } = require('../internal/node-fs');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {string} filePath - Absolute path to file
|
|
12
|
+
* @returns {string} Lowercase hex SHA-256 of file bytes
|
|
13
|
+
*/
|
|
14
|
+
function sha256FileSync(filePath) {
|
|
15
|
+
const buf = nodeFs().readFileSync(filePath);
|
|
16
|
+
return crypto.createHash('sha256').update(buf).digest('hex');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Compare two schema files; throws on mismatch when both exist.
|
|
21
|
+
* @param {string} builderSchemaPath
|
|
22
|
+
* @param {string} dataplaneSchemaPath
|
|
23
|
+
* @returns {{ skipped: boolean, reason?: string, builderSha?: string, dataplaneSha?: string }}
|
|
24
|
+
*/
|
|
25
|
+
function assertDatasourceTestRunSchemasInSync(builderSchemaPath, dataplaneSchemaPath) {
|
|
26
|
+
if (!nodeFs().existsSync(builderSchemaPath)) {
|
|
27
|
+
throw new Error(`Builder schema not found: ${builderSchemaPath}`);
|
|
28
|
+
}
|
|
29
|
+
if (!nodeFs().existsSync(dataplaneSchemaPath)) {
|
|
30
|
+
return {
|
|
31
|
+
skipped: true,
|
|
32
|
+
reason: `Dataplane schema not found (set AIFABRIX_DATAPLANE_ROOT or checkout sibling repo): ${dataplaneSchemaPath}`
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const builderSha = sha256FileSync(builderSchemaPath);
|
|
36
|
+
let dataplaneSha;
|
|
37
|
+
try {
|
|
38
|
+
dataplaneSha = sha256FileSync(dataplaneSchemaPath);
|
|
39
|
+
} catch (err) {
|
|
40
|
+
if (err && err.code === 'ENOENT') {
|
|
41
|
+
return {
|
|
42
|
+
skipped: true,
|
|
43
|
+
reason: `Dataplane schema not found (set AIFABRIX_DATAPLANE_ROOT or checkout sibling repo): ${dataplaneSchemaPath}`
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
throw err;
|
|
47
|
+
}
|
|
48
|
+
if (builderSha !== dataplaneSha) {
|
|
49
|
+
throw new Error(
|
|
50
|
+
`DatasourceTestRun schema drift: builder ${builderSha} ≠ dataplane ${dataplaneSha}`
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
return { skipped: false, builderSha, dataplaneSha };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = {
|
|
57
|
+
sha256FileSync,
|
|
58
|
+
assertDatasourceTestRunSchemasInSync
|
|
59
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Log DatasourceTestRun to TTY — shared by datasource commands and external system server tests.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const logger = require('./logger');
|
|
9
|
+
const { getReportVersionStderrMessage } = require('./datasource-test-run-report-version');
|
|
10
|
+
const {
|
|
11
|
+
formatDatasourceTestRunSummary,
|
|
12
|
+
formatDatasourceTestRunTTY
|
|
13
|
+
} = require('./datasource-test-run-display');
|
|
14
|
+
const {
|
|
15
|
+
resolveDebugDisplayMode,
|
|
16
|
+
formatDatasourceTestRunDebugBlock
|
|
17
|
+
} = require('./datasource-test-run-debug-display');
|
|
18
|
+
const { analyzeCapabilityScope } = require('./datasource-test-run-capability-scope');
|
|
19
|
+
|
|
20
|
+
function emitReportVersionDiagnostics(envelope) {
|
|
21
|
+
if (!envelope || typeof envelope !== 'object') return;
|
|
22
|
+
const msg = getReportVersionStderrMessage(envelope.reportVersion);
|
|
23
|
+
if (!msg) return;
|
|
24
|
+
if (msg.level === 'warn') logger.warn(chalk.yellow(msg.message));
|
|
25
|
+
else if (msg.level === 'info') logger.log(chalk.gray(msg.message));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function emitCapabilityScopeDiagnostics(envelope, opts = {}) {
|
|
29
|
+
const scope = analyzeCapabilityScope(envelope, opts.requestedCapabilityKey);
|
|
30
|
+
if (scope.violated && scope.message) {
|
|
31
|
+
logger.warn(chalk.yellow(`⚠ ${scope.message}`));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Print envelope (JSON, summary, or full TTY + optional debug appendix). Does not emit reportVersion/capability diagnostics.
|
|
37
|
+
* @param {Object} envelope
|
|
38
|
+
* @param {Object} options
|
|
39
|
+
* @param {boolean} [options.json]
|
|
40
|
+
* @param {boolean} [options.summary]
|
|
41
|
+
* @param {boolean|string} [options.debug]
|
|
42
|
+
* @param {string} [options.requestedCapabilityKey]
|
|
43
|
+
*/
|
|
44
|
+
function printDatasourceTestRunForTTY(envelope, options = {}) {
|
|
45
|
+
const displayOpts = { focusCapabilityKey: options.requestedCapabilityKey };
|
|
46
|
+
if (options.json) {
|
|
47
|
+
logger.log(JSON.stringify(envelope));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (options.summary) {
|
|
51
|
+
logger.log(formatDatasourceTestRunSummary(envelope, displayOpts));
|
|
52
|
+
} else {
|
|
53
|
+
logger.log(formatDatasourceTestRunTTY(envelope, displayOpts));
|
|
54
|
+
}
|
|
55
|
+
const mode = resolveDebugDisplayMode(options.debug);
|
|
56
|
+
if (mode) {
|
|
57
|
+
const appendix = formatDatasourceTestRunDebugBlock(envelope, mode, process.stdout.isTTY);
|
|
58
|
+
if (appendix) logger.log(appendix);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Emit diagnostics + human output for one server validation run (integration / test / e2e).
|
|
64
|
+
* @param {Object|null|undefined} envelope
|
|
65
|
+
* @param {Object} options - Same flags as unified CLI (json, summary, debug, requestedCapabilityKey)
|
|
66
|
+
*/
|
|
67
|
+
function logEnvelopeForInteractiveCli(envelope, options = {}) {
|
|
68
|
+
if (!envelope || typeof envelope !== 'object') return;
|
|
69
|
+
emitReportVersionDiagnostics(envelope);
|
|
70
|
+
emitCapabilityScopeDiagnostics(envelope, {
|
|
71
|
+
requestedCapabilityKey: options.requestedCapabilityKey
|
|
72
|
+
});
|
|
73
|
+
printDatasourceTestRunForTTY(envelope, options);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
module.exports = {
|
|
77
|
+
emitReportVersionDiagnostics,
|
|
78
|
+
emitCapabilityScopeDiagnostics,
|
|
79
|
+
printDatasourceTestRunForTTY,
|
|
80
|
+
logEnvelopeForInteractiveCli
|
|
81
|
+
};
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview File watch + debounce for datasource validation CLI (plan §3.14).
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 2.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const { nodeFs } = require('../internal/node-fs');
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
const logger = require('./logger');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Resolve integration path at call time so tests' jest.mock('./paths') applies even if this module
|
|
14
|
+
* was first loaded in a worker before the mock (eager destructuring would keep the real fn).
|
|
15
|
+
* @param {string} appKey
|
|
16
|
+
* @returns {string}
|
|
17
|
+
*/
|
|
18
|
+
function getIntegrationPathForWatch(appKey) {
|
|
19
|
+
return require('./paths').getIntegrationPath(appKey);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const DEFAULT_DEBOUNCE_MS = 500;
|
|
23
|
+
const MAX_DIR_DEPTH = 14;
|
|
24
|
+
|
|
25
|
+
const SKIP_DIR_NAMES = new Set(['node_modules', '.git', 'dist', 'logs', '.turbo']);
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {Object|null|undefined} envelope
|
|
29
|
+
* @returns {string}
|
|
30
|
+
*/
|
|
31
|
+
function fingerprintForWatchDiff(envelope) {
|
|
32
|
+
if (!envelope || typeof envelope !== 'object') return '';
|
|
33
|
+
const capList = (Array.isArray(envelope.capabilities) ? envelope.capabilities : [])
|
|
34
|
+
.map(c =>
|
|
35
|
+
c && c.key !== undefined && c.key !== null ? `${c.key}:${c.status}` : '?'
|
|
36
|
+
)
|
|
37
|
+
.sort()
|
|
38
|
+
.join('|');
|
|
39
|
+
const certSt = envelope.certificate && envelope.certificate.status;
|
|
40
|
+
return `status=${envelope.status}|cert=${certSt || 'none'}|caps=${capList}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @param {string|null} prev
|
|
45
|
+
* @param {string} next
|
|
46
|
+
* @param {boolean} fullDiff
|
|
47
|
+
* @returns {string|null}
|
|
48
|
+
*/
|
|
49
|
+
function formatWatchFingerprintDiff(prev, next, fullDiff) {
|
|
50
|
+
if (prev === null || prev === undefined || prev === next) return null;
|
|
51
|
+
if (fullDiff) {
|
|
52
|
+
return `Watch diff:\n before: ${prev}\n after: ${next}`;
|
|
53
|
+
}
|
|
54
|
+
return `Watch diff: ${chalk.yellow(prev)} → ${chalk.green(next)}`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @param {string} root
|
|
59
|
+
* @param {number} maxDepth
|
|
60
|
+
* @param {number} depth
|
|
61
|
+
* @returns {string[]}
|
|
62
|
+
*/
|
|
63
|
+
function listDirectoriesRecursive(root, maxDepth, depth = 0) {
|
|
64
|
+
const out = [];
|
|
65
|
+
if (depth > maxDepth || !nodeFs().existsSync(root)) return out;
|
|
66
|
+
let st;
|
|
67
|
+
try {
|
|
68
|
+
st = nodeFs().statSync(root);
|
|
69
|
+
} catch {
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
if (!st.isDirectory()) {
|
|
73
|
+
return [root];
|
|
74
|
+
}
|
|
75
|
+
out.push(root);
|
|
76
|
+
let entries;
|
|
77
|
+
try {
|
|
78
|
+
entries = nodeFs().readdirSync(root, { withFileTypes: true });
|
|
79
|
+
} catch {
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
for (const ent of entries) {
|
|
83
|
+
if (SKIP_DIR_NAMES.has(ent.name)) continue;
|
|
84
|
+
if (ent.isDirectory()) {
|
|
85
|
+
out.push(...listDirectoriesRecursive(path.join(root, ent.name), maxDepth, depth + 1));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @param {string} appKey
|
|
93
|
+
* @param {string[]} [extraPaths]
|
|
94
|
+
* @param {boolean} [includeApplicationYaml]
|
|
95
|
+
* @returns {{ kind: 'file'|'dir', path: string }[]}
|
|
96
|
+
*/
|
|
97
|
+
function buildWatchTargetList(appKey, extraPaths = [], includeApplicationYaml = false) {
|
|
98
|
+
const integrationRoot = getIntegrationPathForWatch(appKey);
|
|
99
|
+
const seen = new Set();
|
|
100
|
+
/** @type {{ kind: 'file'|'dir', path: string }[]} */
|
|
101
|
+
const list = [];
|
|
102
|
+
|
|
103
|
+
function addFile(abs) {
|
|
104
|
+
if (!nodeFs().existsSync(abs) || seen.has(abs)) return;
|
|
105
|
+
seen.add(abs);
|
|
106
|
+
list.push({ kind: 'file', path: abs });
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function addDirTree(absRoot) {
|
|
110
|
+
if (!nodeFs().existsSync(absRoot)) return;
|
|
111
|
+
const st = nodeFs().statSync(absRoot);
|
|
112
|
+
if (st.isFile()) {
|
|
113
|
+
addFile(absRoot);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const dirs = listDirectoriesRecursive(absRoot, MAX_DIR_DEPTH);
|
|
117
|
+
for (const d of dirs) {
|
|
118
|
+
if (seen.has(d)) continue;
|
|
119
|
+
seen.add(d);
|
|
120
|
+
list.push({ kind: 'dir', path: d });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
addDirTree(integrationRoot);
|
|
125
|
+
|
|
126
|
+
for (const p of extraPaths) {
|
|
127
|
+
if (!p || typeof p !== 'string') continue;
|
|
128
|
+
const abs = path.resolve(p.trim());
|
|
129
|
+
if (!nodeFs().existsSync(abs)) continue;
|
|
130
|
+
const pst = nodeFs().statSync(abs);
|
|
131
|
+
if (pst.isFile()) {
|
|
132
|
+
addFile(abs);
|
|
133
|
+
} else {
|
|
134
|
+
addDirTree(abs);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (includeApplicationYaml) {
|
|
139
|
+
const y = path.join(integrationRoot, 'application.yaml');
|
|
140
|
+
addFile(y);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return list;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* @param {() => void} fn
|
|
148
|
+
* @param {number} ms
|
|
149
|
+
* @returns {() => void}
|
|
150
|
+
*/
|
|
151
|
+
function debounce(fn, ms) {
|
|
152
|
+
let t = null;
|
|
153
|
+
return () => {
|
|
154
|
+
if (t) clearTimeout(t);
|
|
155
|
+
t = setTimeout(() => {
|
|
156
|
+
t = null;
|
|
157
|
+
fn();
|
|
158
|
+
}, ms);
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* @param {{ kind: 'file'|'dir', path: string }[]} targets
|
|
164
|
+
* @param {() => void} onEvent
|
|
165
|
+
* @returns {() => void}
|
|
166
|
+
*/
|
|
167
|
+
function startWatchers(targets, onEvent) {
|
|
168
|
+
const handles = [];
|
|
169
|
+
for (const t of targets) {
|
|
170
|
+
try {
|
|
171
|
+
handles.push(nodeFs().watch(t.path, () => onEvent()));
|
|
172
|
+
} catch {
|
|
173
|
+
// ignore unreadable paths
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return () => {
|
|
177
|
+
for (const h of handles) {
|
|
178
|
+
try {
|
|
179
|
+
h.close();
|
|
180
|
+
} catch {
|
|
181
|
+
// ignore
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* @param {Object} opts
|
|
189
|
+
* @param {string} opts.appKey
|
|
190
|
+
* @param {string[]} [opts.extraPaths]
|
|
191
|
+
* @param {boolean} [opts.includeApplicationYaml]
|
|
192
|
+
* @param {number} [opts.debounceMs]
|
|
193
|
+
* @param {boolean} [opts.watchCi]
|
|
194
|
+
* @param {boolean} [opts.watchFullDiff]
|
|
195
|
+
* @param {() => Promise<{ exitCode: number, envelope: Object|null }>} opts.runOnce
|
|
196
|
+
* @returns {Promise<void>}
|
|
197
|
+
*/
|
|
198
|
+
async function runDatasourceValidationWatchLoop(opts) {
|
|
199
|
+
const {
|
|
200
|
+
appKey,
|
|
201
|
+
extraPaths = [],
|
|
202
|
+
includeApplicationYaml = false,
|
|
203
|
+
debounceMs = DEFAULT_DEBOUNCE_MS,
|
|
204
|
+
watchCi = false,
|
|
205
|
+
watchFullDiff = false,
|
|
206
|
+
runOnce
|
|
207
|
+
} = opts;
|
|
208
|
+
|
|
209
|
+
const targets = buildWatchTargetList(appKey, extraPaths, includeApplicationYaml);
|
|
210
|
+
if (targets.length === 0) {
|
|
211
|
+
logger.warn(chalk.yellow('Watch: no directories or files to watch; check integration path.'));
|
|
212
|
+
process.exit(4);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
let prevFp = null;
|
|
217
|
+
let running = false;
|
|
218
|
+
|
|
219
|
+
const execute = async() => {
|
|
220
|
+
if (running) return;
|
|
221
|
+
running = true;
|
|
222
|
+
try {
|
|
223
|
+
logger.log(chalk.blue('\n[watch] Running validation…'));
|
|
224
|
+
const { exitCode, envelope } = await runOnce();
|
|
225
|
+
const fp = fingerprintForWatchDiff(envelope);
|
|
226
|
+
const diffMsg = formatWatchFingerprintDiff(prevFp, fp, watchFullDiff);
|
|
227
|
+
if (diffMsg) logger.log(diffMsg);
|
|
228
|
+
prevFp = fp;
|
|
229
|
+
if (watchCi) {
|
|
230
|
+
process.exit(exitCode);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
logger.log(chalk.gray(`[watch] exit code ${exitCode} — waiting for file changes (Ctrl+C to stop)`));
|
|
234
|
+
} finally {
|
|
235
|
+
running = false;
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
await execute();
|
|
240
|
+
|
|
241
|
+
// In production, watchCi triggers process.exit inside execute; with a mocked exit (tests),
|
|
242
|
+
// still skip watcher setup so the async function can finish and no duplicate runs occur.
|
|
243
|
+
if (watchCi) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const onFs = debounce(execute, debounceMs);
|
|
248
|
+
const closeAll = startWatchers(targets, onFs);
|
|
249
|
+
|
|
250
|
+
const onSig = () => {
|
|
251
|
+
closeAll();
|
|
252
|
+
process.exit(130);
|
|
253
|
+
};
|
|
254
|
+
process.on('SIGINT', onSig);
|
|
255
|
+
process.on('SIGTERM', onSig);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
module.exports = {
|
|
259
|
+
DEFAULT_DEBOUNCE_MS,
|
|
260
|
+
fingerprintForWatchDiff,
|
|
261
|
+
formatWatchFingerprintDiff,
|
|
262
|
+
buildWatchTargetList,
|
|
263
|
+
debounce,
|
|
264
|
+
startWatchers,
|
|
265
|
+
runDatasourceValidationWatchLoop
|
|
266
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host port math for declarative url:// resolution (plan 122).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview publishedHostPort vs localHostPort from manifest port + developer-id
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {string|number|null|undefined} raw - developer-id from config
|
|
13
|
+
* @returns {number} Numeric id; non-numeric or empty → 0
|
|
14
|
+
*/
|
|
15
|
+
function parseDeveloperIdNum(raw) {
|
|
16
|
+
if (raw === null || raw === undefined || raw === '') {
|
|
17
|
+
return 0;
|
|
18
|
+
}
|
|
19
|
+
const parsed = parseInt(String(raw).trim(), 10);
|
|
20
|
+
return Number.isNaN(parsed) ? 0 : parsed;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Docker published host port: port + devId*100 (dev 0 → base port).
|
|
25
|
+
* @param {number} appPort - Manifest listen port
|
|
26
|
+
* @param {number} developerIdNum
|
|
27
|
+
* @returns {number}
|
|
28
|
+
*/
|
|
29
|
+
function publishedHostPort(appPort, developerIdNum) {
|
|
30
|
+
return appPort + developerIdNum * 100;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Local workstation host port: port + 10 + devId*100 (dev 0 → port+10).
|
|
35
|
+
* @param {number} appPort
|
|
36
|
+
* @param {number} developerIdNum
|
|
37
|
+
* @returns {number}
|
|
38
|
+
*/
|
|
39
|
+
function localHostPort(appPort, developerIdNum) {
|
|
40
|
+
return appPort + 10 + developerIdNum * 100;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = {
|
|
44
|
+
parseDeveloperIdNum,
|
|
45
|
+
publishedHostPort,
|
|
46
|
+
localHostPort
|
|
47
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derive pipeline/env segment (dev|tst|pro|miso) from MISO_CLIENTID convention.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Plan 122 — optional MISO_PIPELINE_ENV_KEY override
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const ENV_TOKENS = new Set(['dev', 'tst', 'pro', 'miso']);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {string|null|undefined} clientId - e.g. miso-controller-dev-dataplane
|
|
15
|
+
* @param {string|null|undefined} pipelineOverride - MISO_PIPELINE_ENV_KEY when set in resolved env
|
|
16
|
+
* @returns {string} Lowercase env key (default miso)
|
|
17
|
+
*/
|
|
18
|
+
function deriveEnvKeyFromClientId(clientId, pipelineOverride) {
|
|
19
|
+
const o = pipelineOverride !== undefined && pipelineOverride !== null
|
|
20
|
+
? String(pipelineOverride).trim().toLowerCase()
|
|
21
|
+
: '';
|
|
22
|
+
if (o && ENV_TOKENS.has(o)) {
|
|
23
|
+
return o;
|
|
24
|
+
}
|
|
25
|
+
if (!clientId || typeof clientId !== 'string') {
|
|
26
|
+
return 'miso';
|
|
27
|
+
}
|
|
28
|
+
const parts = clientId.split('-').filter(Boolean);
|
|
29
|
+
for (let i = parts.length - 1; i >= 0; i--) {
|
|
30
|
+
const p = parts[i].toLowerCase();
|
|
31
|
+
if (ENV_TOKENS.has(p)) {
|
|
32
|
+
return p;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return 'miso';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
module.exports = {
|
|
39
|
+
deriveEnvKeyFromClientId,
|
|
40
|
+
ENV_TOKENS
|
|
41
|
+
};
|