@aifabrix/builder 2.52.0 → 2.53.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/lib/api/datasources-extended.api.js +8 -8
- package/lib/api/keycloak.api.js +92 -0
- package/lib/api/token-providers.api.js +77 -0
- package/lib/api/types/keycloak.types.js +23 -0
- package/lib/api/types/token-providers.types.js +65 -0
- package/lib/app/deploy-config.js +3 -2
- package/lib/app/down.js +16 -1
- package/lib/channels/add-channel.js +134 -57
- package/lib/channels/approval-guides/chatgpt.js +1 -1
- package/lib/channels/approval-guides/index.js +3 -0
- package/lib/channels/approval-guides/microsoft-copilot.js +27 -14
- package/lib/channels/channel-add-ensure.js +128 -0
- package/lib/channels/channel-add-existing.js +72 -0
- package/lib/channels/channel-artifact-generator.js +11 -1
- package/lib/channels/channel-branding.js +94 -0
- package/lib/channels/channel-credential.js +8 -0
- package/lib/channels/channel-discovery.js +330 -0
- package/lib/channels/channel-external-system.js +1 -1
- package/lib/channels/channel-runtime-resolver.js +107 -14
- package/lib/channels/channel-status-display.js +36 -3
- package/lib/channels/microsoft-copilot-channel-add.js +138 -0
- package/lib/channels/microsoft-copilot-entra-sso-form.js +251 -0
- package/lib/channels/microsoft-copilot-entra-sso.js +285 -0
- package/lib/channels/microsoft-copilot-icons.js +74 -0
- package/lib/channels/microsoft-copilot-limits.js +103 -0
- package/lib/channels/microsoft-copilot-package.js +178 -52
- package/lib/channels/microsoft-copilot-validate.js +227 -0
- package/lib/cli/attach-default-help-examples.js +102 -0
- package/lib/cli/index.js +4 -0
- package/lib/cli/infra-guided.js +13 -6
- package/lib/cli/setup-credential-deployment.js +7 -5
- package/lib/cli/setup-infra.js +31 -4
- package/lib/cli/setup-utility-validate.js +1 -0
- package/lib/commands/channel-add-setup.js +28 -9
- package/lib/commands/channel.js +14 -10
- package/lib/commands/credential-push.js +37 -5
- package/lib/commands/integration-definition.js +158 -0
- package/lib/commands/package-score.js +72 -0
- package/lib/commands/repair-auth-apply.js +19 -5
- package/lib/commands/repair-datasource-sync-operations.js +4 -1
- package/lib/commands/role-assistant-test-output.js +200 -0
- package/lib/commands/role-assistant.js +163 -166
- package/lib/datasource/capability/capability-resolve.js +15 -5
- package/lib/datasource/capability/copy-operations.js +14 -4
- package/lib/deployment/deployer-poll-run.js +2 -2
- package/lib/deployment/deployer.js +1 -1
- package/lib/deployment/environment.js +2 -2
- package/lib/external-system/deploy.js +11 -21
- package/lib/infrastructure/index.js +19 -4
- package/lib/integration-definition/apply.js +476 -0
- package/lib/integration-definition/canonical-json.js +51 -0
- package/lib/integration-definition/emit-suite-bid.js +94 -0
- package/lib/integration-definition/enrich-crm-field-mappings.js +240 -0
- package/lib/integration-definition/enrich-openapi-operations.js +433 -0
- package/lib/integration-definition/from-discovery.js +339 -0
- package/lib/integration-definition/hash.js +37 -0
- package/lib/integration-definition/index.js +37 -0
- package/lib/integration-definition/resource-type-catalog.js +59 -0
- package/lib/integration-definition/system-kind-enum.js +40 -0
- package/lib/integration-definition/validate.js +148 -0
- package/lib/lab/package-parity-score.js +417 -0
- package/lib/programmatic/builder-api-request.js +5 -1
- package/lib/programmatic/builder-help-governance.js +3 -2
- package/lib/programmatic/capability-registry.js +20 -0
- package/lib/programmatic/help-content/channel-onboarding.md +35 -0
- package/lib/programmatic/help-content/cip-overview.md +27 -0
- package/lib/programmatic/help-content/connected-system-ui.md +70 -0
- package/lib/programmatic/help-content/dimensions-guide.md +23 -0
- package/lib/programmatic/help-content/enterprise-sync-fabrix.md +123 -0
- package/lib/programmatic/help-content/overview.md +25 -0
- package/lib/programmatic/help-content/subscription-guide.md +27 -0
- package/lib/programmatic/help-content/workflow.md +50 -0
- package/lib/programmatic/openapi-component-schemas.js +7 -1
- package/lib/programmatic/openapi-descriptions.js +46 -0
- package/lib/programmatic/openapi-envelope-examples.js +280 -0
- package/lib/programmatic/openapi-operation-bindings.js +50 -0
- package/lib/programmatic/openapi-request-schemas.js +40 -0
- package/lib/programmatic/openapi-result-schemas-overflow.js +101 -0
- package/lib/programmatic/openapi-result-schemas.js +76 -99
- package/lib/programmatic/openapi-schema-descriptions-core.js +25 -4
- package/lib/programmatic/openapi-schema-descriptions-help.js +1 -1
- package/lib/programmatic/openapi-schema-descriptions-operations.js +43 -0
- package/lib/programmatic/openapi-schema-helpers.js +9 -9
- package/lib/programmatic/openapi-spec.js +11 -1
- package/lib/programmatic/orchestration-openapi-meta.js +10 -0
- package/lib/programmatic/persist-supplied-openapi.js +180 -0
- package/lib/programmatic/route-handler-map.js +35 -1
- package/lib/programmatic/run-channel-package.js +236 -0
- package/lib/programmatic/run-integration-definition.js +77 -0
- package/lib/role-assistant/evidence-sync.js +55 -7
- package/lib/role-assistant/knowledge-sync-logging.js +58 -0
- package/lib/role-assistant/knowledge-sync.js +88 -93
- package/lib/role-assistant/test-cases-bid.js +155 -0
- package/lib/role-assistant/test-cases-evaluate.js +9 -1
- package/lib/role-assistant/test-cases-honesty.js +24 -10
- package/lib/role-assistant/test-cases.js +28 -0
- package/lib/role-assistant/test-runner-attachments.js +118 -0
- package/lib/role-assistant/test-runner-bid-apply.js +201 -0
- package/lib/role-assistant/test-runner-bid-document.js +278 -0
- package/lib/role-assistant/test-runner-start-payload.js +96 -0
- package/lib/role-assistant/test-runner-workhub-answers.js +249 -20
- package/lib/role-assistant/test-runner-workhub-helpers.js +100 -0
- package/lib/role-assistant/test-runner-workhub-soft.js +86 -0
- package/lib/role-assistant/test-runner-workhub.js +152 -107
- package/lib/role-assistant/test-runner.js +5 -63
- package/lib/role-assistant/test-suite.js +112 -0
- package/lib/schema/application-schema.json +56 -6
- package/lib/schema/external-datasource.schema.json +103 -17
- package/lib/schema/external-system.schema.json +54 -3
- package/lib/schema/integration-definition.schema.json +195 -0
- package/lib/utils/authentication-shape.js +6 -0
- package/lib/utils/compose-generator.js +10 -1
- package/lib/utils/compose-traefik-extra-routes.js +107 -0
- package/lib/utils/docker-build.js +2 -2
- package/lib/utils/help-builder.js +3 -1
- package/lib/utils/promote-dev-docker-image.js +102 -18
- package/lib/utils/transient-developer-id.js +28 -0
- package/package.json +14 -16
- package/templates/README.md +12 -1
- package/templates/applications/dataplane/application.yaml +10 -2
- package/templates/applications/dataplane/env.template +7 -6
- package/templates/applications/miso-controller/application.yaml +23 -8
- package/templates/applications/miso-controller/env.template +8 -2
- package/templates/applications/miso-controller/rbac.yaml +1 -0
- package/templates/channels/README.md +11 -1
- package/templates/channels/brand/color-192.png +0 -0
- package/templates/channels/brand/dark/128.png +0 -0
- package/templates/channels/brand/dark/192.png +0 -0
- package/templates/channels/brand/dark/256.png +0 -0
- package/templates/channels/brand/dark/32.png +0 -0
- package/templates/channels/brand/dark/512.png +0 -0
- package/templates/channels/brand/dark/64.png +0 -0
- package/templates/channels/brand/light/128.png +0 -0
- package/templates/channels/brand/light/192.png +0 -0
- package/templates/channels/brand/light/256.png +0 -0
- package/templates/channels/brand/light/32.png +0 -0
- package/templates/channels/brand/light/512.png +0 -0
- package/templates/channels/brand/light/64.png +0 -0
- package/templates/channels/brand/mono-white/128.png +0 -0
- package/templates/channels/brand/mono-white/192.png +0 -0
- package/templates/channels/brand/mono-white/256.png +0 -0
- package/templates/channels/brand/mono-white/32.png +0 -0
- package/templates/channels/brand/mono-white/512.png +0 -0
- package/templates/channels/brand/mono-white/64.png +0 -0
- package/templates/channels/brand/outline-32.png +0 -0
- package/templates/channels/chatgpt/install.template.md.hbs +6 -4
- package/templates/channels/chatgpt/integration/README.md +4 -5
- package/templates/channels/chatgpt/integration/chatgpt-system.json +1 -16
- package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +14 -16
- package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +5 -3
- package/templates/channels/microsoft-copilot/entra-sso-registration.template.md.hbs +30 -0
- package/templates/channels/microsoft-copilot/fi-fi.template.json.hbs +7 -0
- package/templates/channels/microsoft-copilot/install.template.md.hbs +93 -22
- package/templates/channels/microsoft-copilot/integration/README.md +2 -3
- package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +1 -22
- package/templates/channels/microsoft-copilot/manifest.template.json.hbs +34 -19
- package/templates/channels/microsoft-copilot/oauth-plugin-vault-required.template.md.hbs +15 -0
- package/templates/channels/slack/integration/README.md +2 -4
- package/templates/channels/teams-bot/install.template.md.hbs +4 -0
- package/templates/channels/teams-bot/integration/README.md +3 -5
- package/templates/channels/web-embed/integration/web-embed-system.json +1 -16
- package/templates/python/docker-compose.hbs +36 -0
- package/templates/typescript/docker-compose.hbs +36 -0
- package/.cursor/plans/Done/157.1-security-quality-violations-by-type.csv +0 -374
- package/.cursor/process/README.md +0 -9
- package/.cursor/rules/anchor-docs.mdc +0 -15
- package/.cursor/rules/assistant-driven-integration-build.mdc +0 -40
- package/.cursor/rules/cli-layout.mdc +0 -81
- package/.cursor/rules/cli-product-neutral.mdc +0 -43
- package/.cursor/rules/deploy-rules/docker-image-ip-policy.mdc +0 -49
- package/.cursor/rules/docs-rules.mdc +0 -32
- package/.cursor/rules/plan-rules/application-lifecycle.mdc +0 -30
- package/.cursor/rules/plan-rules/plan-frontmatter.mdc +0 -35
- package/.cursor/rules/plan-rules/plan-lifecycle.mdc +0 -31
- package/.cursor/rules/plan-rules/plan-validation-gate.mdc +0 -34
- package/.cursor/rules/project-rules.mdc +0 -913
- package/.cursor/skills/README.md +0 -15
- package/.dockerignore +0 -52
- package/.eslintignore +0 -22
- package/.markdownlint.json +0 -14
- package/anchor-docs/README.md +0 -10
- package/anchor-docs/_TEMPLATE +0 -24
- package/babel.config.js +0 -6
- package/bin/builder-api-cleanup.js +0 -26
- package/bin/builder-api-nest.js +0 -10
- package/bin/builder-api-spike.js +0 -19
- package/enterprise-knowledge/README.md +0 -50
- package/enterprise-knowledge/enterprise-integration-lifecycle/README.md +0 -22
- package/enterprise-knowledge/enterprise-integration-lifecycle/application.json +0 -15
- package/enterprise-knowledge/enterprise-integration-lifecycle/deploy.js +0 -69
- package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-deploy.json +0 -52
- package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-system.json +0 -29
- package/enterprise-knowledge/enterprise-integration-lifecycle/env.template +0 -2
- package/integration/README.md +0 -81
- package/integration/github/README.md +0 -53
- package/integration/github/application.json +0 -21
- package/integration/github/deploy.js +0 -72
- package/integration/github/env.template +0 -11
- package/integration/github/github-datasource-issue-comments.json +0 -239
- package/integration/github/github-datasource-issues.json +0 -399
- package/integration/github/github-datasource-repository.json +0 -354
- package/integration/github/github-deploy.json +0 -1202
- package/integration/github/github-system.json +0 -82
- package/integration/hubspot-test/README.md +0 -159
- package/integration/hubspot-test/application.json +0 -54
- package/integration/hubspot-test/companies.json +0 -2048
- package/integration/hubspot-test/create-hubspot.js +0 -523
- package/integration/hubspot-test/env.template +0 -4
- package/integration/hubspot-test/hubspot-test-datasource-company.json +0 -138
- package/integration/hubspot-test/hubspot-test-datasource-contact.json +0 -146
- package/integration/hubspot-test/hubspot-test-datasource-deal.json +0 -146
- package/integration/hubspot-test/hubspot-test-datasource-users.json +0 -76
- package/integration/hubspot-test/hubspot-test-deploy.json +0 -2160
- package/integration/hubspot-test/hubspot-test-system.json +0 -74
- package/integration/hubspot-test/rbac.json +0 -166
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +0 -20
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +0 -9
- package/integration/hubspot-test/test-artifacts/wizard-invalid-add-datasource.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-app-name.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-credential-create.yaml +0 -7
- package/integration/hubspot-test/test-artifacts/wizard-invalid-credential-select.yaml +0 -7
- package/integration/hubspot-test/test-artifacts/wizard-invalid-known-platform.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-app.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-source.yaml +0 -2
- package/integration/hubspot-test/test-artifacts/wizard-invalid-mode.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-openapi-file.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-openapi-url.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-invalid-source.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-array-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-key-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-path-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-rbac-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +0 -5
- package/integration/hubspot-test/test-dataplane-down-helpers.js +0 -249
- package/integration/hubspot-test/test-dataplane-down-tests.js +0 -386
- package/integration/hubspot-test/test-dataplane-down.js +0 -209
- package/integration/hubspot-test/test.js +0 -1588
- package/integration/hubspot-test/wizard-hubspot-e2e.yaml +0 -16
- package/integration/hubspot-test/wizard-hubspot-platform.yaml +0 -8
- package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +0 -23
- package/integration/roundtrip-test-local/README.md +0 -143
- package/integration/roundtrip-test-local/application.yaml +0 -13
- package/integration/roundtrip-test-local/env.template +0 -15
- package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +0 -14
- package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +0 -61
- package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +0 -25
- package/integration/roundtrip-test-local2/README.md +0 -143
- package/integration/roundtrip-test-local2/application.yaml +0 -13
- package/integration/roundtrip-test-local2/env.template +0 -15
- package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +0 -31
- package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +0 -86
- package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +0 -25
- package/integration/test/wizard.yaml +0 -8
- package/jest.config.coverage.js +0 -37
- package/jest.config.default.js +0 -11
- package/jest.config.integration.fixtures.js +0 -22
- package/jest.config.integration.js +0 -33
- package/jest.config.isolated.js +0 -11
- package/jest.config.manual.js +0 -30
- package/jest.global-live-fabrix-hooks.js +0 -36
- package/jest.isolated-projects.js +0 -260
- package/jest.projects.js +0 -76
- package/packages/builder-api/README.md +0 -120
- package/packages/builder-api/package.json +0 -30
- package/packages/builder-api/src/app.module.ts +0 -7
- package/packages/builder-api/src/auth/auth.module.ts +0 -5
- package/packages/builder-api/src/external-system/external-system.module.ts +0 -5
- package/packages/builder-api/src/main.ts +0 -16
- package/packages/builder-api/tsconfig.json +0 -15
- package/scripts/check-builder-api-architecture-grep.js +0 -79
- package/scripts/check-datasource-test-run-schema-sync.js +0 -34
- package/scripts/ci-fix.sh +0 -19
- package/scripts/ci-simulate.sh +0 -19
- package/scripts/diagnose-cli.js +0 -150
- package/scripts/docker_image_content_gate.js +0 -47
- package/scripts/docker_image_content_gate.sh +0 -5
- package/scripts/export-builder-api-evidence.js +0 -262
- package/scripts/install-local.js +0 -490
- package/scripts/lib/builder-api-docker-staging-copy.js +0 -60
- package/scripts/lib/builder-api-docker-staging-core.js +0 -183
- package/scripts/lib/docker-image-content-gate-core.js +0 -166
- package/scripts/lib/plan-actor.js +0 -109
- package/scripts/lib/plan-config.js +0 -20
- package/scripts/lib/plan-gates.js +0 -154
- package/scripts/lib/plan-meta.js +0 -104
- package/scripts/lib/plan-parse.js +0 -162
- package/scripts/lib/plan-prevalidate-gates.js +0 -337
- package/scripts/lib/plan-run-core.js +0 -125
- package/scripts/lib/plan-run-report.js +0 -119
- package/scripts/plan-approve.js +0 -24
- package/scripts/plan-archive.js +0 -49
- package/scripts/plan-run.js +0 -13
- package/scripts/plan-set-actor.js +0 -21
- package/scripts/plan-validate.js +0 -80
- package/scripts/pnpm/af.mjs +0 -110
- package/scripts/pnpm/check-quiet.mjs +0 -32
- package/scripts/pnpm/dev-install.mjs +0 -29
- package/scripts/pnpm/dev-reload.mjs +0 -18
- package/scripts/pnpm/help.mjs +0 -55
- package/scripts/pnpm/lib/dev-reload-core.mjs +0 -189
- package/scripts/pnpm/lib/dev-reload-log-capture.mjs +0 -67
- package/scripts/pnpm/lib/dev-reload-log-utils.mjs +0 -32
- package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +0 -124
- package/scripts/pnpm/lib/resolve-app-url.mjs +0 -183
- package/scripts/pnpm/lib/spinner.mjs +0 -42
- package/scripts/pnpm-global-remove.js +0 -48
- package/scripts/stage_builder_api_for_docker.js +0 -65
- package/scripts/sync-builder-api-template.js +0 -44
- package/scripts/test-dataplane-bootstrap.js +0 -331
|
@@ -7,7 +7,11 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
const { rewriteCapabilityReferences } = require('./reference-rewrite');
|
|
10
|
-
const {
|
|
10
|
+
const {
|
|
11
|
+
capabilityKeyFromEntry,
|
|
12
|
+
capabilitiesIncludes,
|
|
13
|
+
buildCapabilityObject
|
|
14
|
+
} = require('./capability-manifest');
|
|
11
15
|
const { jsonPointerPath } = require('./json-pointer');
|
|
12
16
|
const { buildBasicExposureProfileArray } = require('./basic-exposure');
|
|
13
17
|
const {
|
|
@@ -256,14 +260,20 @@ function appendCapabilityList(doc, resolvedAs, patchOperations, updatedSections)
|
|
|
256
260
|
if (!Array.isArray(doc.capabilities)) {
|
|
257
261
|
doc.capabilities = [];
|
|
258
262
|
}
|
|
259
|
-
if (doc.capabilities
|
|
263
|
+
if (capabilitiesIncludes(doc.capabilities, resolvedAs)) {
|
|
260
264
|
return;
|
|
261
265
|
}
|
|
262
|
-
doc.capabilities.
|
|
266
|
+
const usesObjects = doc.capabilities.some(
|
|
267
|
+
(entry) => entry && typeof entry === 'object' && !Array.isArray(entry)
|
|
268
|
+
);
|
|
269
|
+
const value = usesObjects
|
|
270
|
+
? buildCapabilityObject(resolvedAs, doc.displayName || doc.key || 'records')
|
|
271
|
+
: resolvedAs;
|
|
272
|
+
doc.capabilities.push(value);
|
|
263
273
|
patchOperations.push({
|
|
264
274
|
op: 'add',
|
|
265
275
|
path: '/capabilities/-',
|
|
266
|
-
value
|
|
276
|
+
value
|
|
267
277
|
});
|
|
268
278
|
updatedSections.push(`capabilities[]: ${resolvedAs}`);
|
|
269
279
|
}
|
|
@@ -31,7 +31,7 @@ const { createDeployPollHandlers } = require('./deploy-poll-ui');
|
|
|
31
31
|
*/
|
|
32
32
|
async function pollDeploymentStatus(deploymentId, controllerUrl, envKey, authConfig, options = {}) {
|
|
33
33
|
const interval = options.interval || 5000;
|
|
34
|
-
const maxAttempts = options.maxAttempts ||
|
|
34
|
+
const maxAttempts = options.maxAttempts || 300;
|
|
35
35
|
|
|
36
36
|
const validatedEnvKey = validateEnvironmentKey(envKey);
|
|
37
37
|
const pipelineAuthConfig = convertToPipelineAuthConfig(authConfig);
|
|
@@ -74,7 +74,7 @@ async function pollDeployment(result, url, validatedEnvKey, authConfig, options)
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
const resolvedInterval = await resolvePollIntervalFromController(url, options.pollInterval);
|
|
77
|
-
const maxAttempts = options.pollMaxAttempts ||
|
|
77
|
+
const maxAttempts = options.pollMaxAttempts || 300;
|
|
78
78
|
const ownsPollUi = !options.pollUi;
|
|
79
79
|
const pollUi =
|
|
80
80
|
options.pollUi ||
|
|
@@ -387,7 +387,7 @@ async function deployToController(manifest, controllerUrl, envKey, authConfig, o
|
|
|
387
387
|
|
|
388
388
|
const usePollUi = options.poll !== false && options.silentPoll !== true;
|
|
389
389
|
const pollUi = usePollUi
|
|
390
|
-
? createDeployPollHandlers(options.pollMaxAttempts ||
|
|
390
|
+
? createDeployPollHandlers(options.pollMaxAttempts || 300, { silent: false })
|
|
391
391
|
: null;
|
|
392
392
|
const deployOpts = pollUi ? { ...options, pollUi } : options;
|
|
393
393
|
|
|
@@ -253,7 +253,7 @@ async function pollEnvironmentStatus(deploymentId, controllerUrl, envKey, authCo
|
|
|
253
253
|
const validatedUrl = validateControllerUrl(controllerUrl);
|
|
254
254
|
const validatedEnvKey = validateEnvironmentKey(envKey);
|
|
255
255
|
const pollInterval = options.pollInterval || 5000;
|
|
256
|
-
const maxAttempts = options.maxAttempts ||
|
|
256
|
+
const maxAttempts = options.maxAttempts || 300;
|
|
257
257
|
const apiAuthConfig = { type: 'bearer', token: authConfig.token };
|
|
258
258
|
|
|
259
259
|
logger.log(chalk.blue(`⏳ Polling environment status (${pollInterval}ms intervals)...`));
|
|
@@ -398,7 +398,7 @@ async function pollDeploymentStatusIfEnabled(result, validatedControllerUrl, env
|
|
|
398
398
|
authConfig,
|
|
399
399
|
{
|
|
400
400
|
pollInterval,
|
|
401
|
-
maxAttempts: options.pollMaxAttempts ||
|
|
401
|
+
maxAttempts: options.pollMaxAttempts || 300
|
|
402
402
|
}
|
|
403
403
|
);
|
|
404
404
|
result.status = pollResult.status;
|
|
@@ -131,19 +131,6 @@ async function fetchDataplaneDeployReadiness(controllerUrl, environment, authCon
|
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
/**
|
|
135
|
-
* Deploys via controller and prints readiness summary (config / deployment / runtime layers).
|
|
136
|
-
* @async
|
|
137
|
-
* @param {Object} manifest - Controller manifest
|
|
138
|
-
* @param {string} controllerUrl - Controller base URL
|
|
139
|
-
* @param {string} environment - Environment key
|
|
140
|
-
* @param {Object} authConfig - Authentication configuration
|
|
141
|
-
* @param {Object} options - Deployment options (poll, probe, probeTimeout)
|
|
142
|
-
* @returns {Promise<Object>} Deployment result
|
|
143
|
-
*/
|
|
144
|
-
/**
|
|
145
|
-
* @param {Object} deploymentOutcome - from parseControllerDeploymentOutcome
|
|
146
|
-
*/
|
|
147
134
|
/**
|
|
148
135
|
* Optional dataplane validation/run after external deploy (--probe).
|
|
149
136
|
* @async
|
|
@@ -202,12 +189,21 @@ function logImmediateControllerDeploymentOutcome(deploymentOutcome) {
|
|
|
202
189
|
logger.log(chalk.gray(' Check the controller deployment job or logs for details.'));
|
|
203
190
|
}
|
|
204
191
|
|
|
192
|
+
/** External deploy waits on controller → dataplane publish job (may run prove gates / tests). */
|
|
193
|
+
const EXTERNAL_DEPLOY_POLL_INTERVAL_MS = 2000;
|
|
194
|
+
/** 300 × 2s ≈ 10 minutes — must cover controller publish-job max wait with gates. */
|
|
195
|
+
const EXTERNAL_DEPLOY_POLL_MAX_ATTEMPTS = 300;
|
|
196
|
+
|
|
205
197
|
function buildExternalDeployPollOpts(options) {
|
|
206
198
|
return {
|
|
207
199
|
...options,
|
|
208
200
|
poll: true,
|
|
209
|
-
pollInterval:
|
|
210
|
-
|
|
201
|
+
pollInterval:
|
|
202
|
+
options.pollInterval !== undefined ? options.pollInterval : EXTERNAL_DEPLOY_POLL_INTERVAL_MS,
|
|
203
|
+
pollMaxAttempts:
|
|
204
|
+
options.pollMaxAttempts !== undefined
|
|
205
|
+
? options.pollMaxAttempts
|
|
206
|
+
: EXTERNAL_DEPLOY_POLL_MAX_ATTEMPTS,
|
|
211
207
|
silentPoll: options.silentPoll === true
|
|
212
208
|
};
|
|
213
209
|
}
|
|
@@ -381,12 +377,6 @@ function wrapDeployExternalSystemError(error, appName) {
|
|
|
381
377
|
return new Error(message);
|
|
382
378
|
}
|
|
383
379
|
|
|
384
|
-
/**
|
|
385
|
-
* @async
|
|
386
|
-
* @param {string} appName
|
|
387
|
-
* @param {Object} options
|
|
388
|
-
* @returns {Promise<Object>}
|
|
389
|
-
*/
|
|
390
380
|
/**
|
|
391
381
|
* @param {string} appName
|
|
392
382
|
* @param {Object} options
|
|
@@ -203,12 +203,26 @@ async function removeAppVolumes(appNames, devId) {
|
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
+
/**
|
|
207
|
+
* Resolve developer id for stop paths. Optional override is transient (not config).
|
|
208
|
+
* @param {string|number|null|undefined} developerId
|
|
209
|
+
* @returns {Promise<string>}
|
|
210
|
+
*/
|
|
211
|
+
async function resolveStopDeveloperId(developerId) {
|
|
212
|
+
if (developerId === undefined || developerId === null || developerId === '') {
|
|
213
|
+
return config.getDeveloperId();
|
|
214
|
+
}
|
|
215
|
+
const { validateAndNormalizeDeveloperId } = require('../core/config-normalize');
|
|
216
|
+
return validateAndNormalizeDeveloperId(developerId);
|
|
217
|
+
}
|
|
218
|
+
|
|
206
219
|
/**
|
|
207
220
|
* Stops and removes local infrastructure services and all application containers
|
|
208
221
|
* on the same network. Cleanly shuts down infra and app containers.
|
|
209
222
|
*
|
|
210
223
|
* @async
|
|
211
224
|
* @function stopInfra
|
|
225
|
+
* @param {string|number|null|undefined} [developerId] - Optional target developer (does not change config)
|
|
212
226
|
* @returns {Promise<void>} Resolves when infrastructure is stopped
|
|
213
227
|
* @throws {Error} If Docker compose fails
|
|
214
228
|
*
|
|
@@ -216,8 +230,8 @@ async function removeAppVolumes(appNames, devId) {
|
|
|
216
230
|
* await stopInfra();
|
|
217
231
|
* // All infrastructure and app containers on the same network are stopped and removed
|
|
218
232
|
*/
|
|
219
|
-
async function stopInfra() {
|
|
220
|
-
const devId = await
|
|
233
|
+
async function stopInfra(developerId) {
|
|
234
|
+
const devId = await resolveStopDeveloperId(developerId);
|
|
221
235
|
const { infraDir, adminSecretsPath } = resolveInfraStatePaths(devId);
|
|
222
236
|
const composePath = path.join(infraDir, 'compose.yaml');
|
|
223
237
|
const hasCompose = fs.existsSync(composePath);
|
|
@@ -279,6 +293,7 @@ async function stopAllAppContainersAndVolumes(devId) {
|
|
|
279
293
|
*
|
|
280
294
|
* @async
|
|
281
295
|
* @function stopInfraWithVolumes
|
|
296
|
+
* @param {string|number|null|undefined} [developerId] - Optional target developer (does not change config)
|
|
282
297
|
* @returns {Promise<void>} Resolves when infrastructure is stopped and volumes removed
|
|
283
298
|
* @throws {Error} If Docker compose fails
|
|
284
299
|
*
|
|
@@ -286,8 +301,8 @@ async function stopAllAppContainersAndVolumes(devId) {
|
|
|
286
301
|
* await stopInfraWithVolumes();
|
|
287
302
|
* // All infrastructure and app containers and volumes are removed
|
|
288
303
|
*/
|
|
289
|
-
async function stopInfraWithVolumes() {
|
|
290
|
-
const devId = await
|
|
304
|
+
async function stopInfraWithVolumes(developerId) {
|
|
305
|
+
const devId = await resolveStopDeveloperId(developerId);
|
|
291
306
|
const { infraDir, adminSecretsPath } = resolveInfraStatePaths(devId);
|
|
292
307
|
const composePath = path.join(infraDir, 'compose.yaml');
|
|
293
308
|
const hasCompose = fs.existsSync(composePath);
|
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apply Builder Integration Definition to integration/<systemKey>/.
|
|
3
|
+
* @fileoverview Idempotent BID → package materialization (no AI)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const fsReal = require('../internal/fs-real-sync');
|
|
10
|
+
const { getIntegrationPath } = require('../utils/paths');
|
|
11
|
+
const { validateIntegrationDefinition } = require('./validate');
|
|
12
|
+
|
|
13
|
+
const STAMP_FILE = '.aifabrix-integration-definition.json';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {string} dir
|
|
17
|
+
* @returns {Promise<Record<string, unknown> | null>}
|
|
18
|
+
*/
|
|
19
|
+
async function readStamp(dir) {
|
|
20
|
+
const stampPath = path.join(dir, STAMP_FILE);
|
|
21
|
+
try {
|
|
22
|
+
const raw = fsReal.readFileSync(stampPath, 'utf8');
|
|
23
|
+
return JSON.parse(raw);
|
|
24
|
+
} catch (err) {
|
|
25
|
+
if (err && err.code === 'ENOENT') {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
throw err;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param {Record<string, unknown>} bid
|
|
34
|
+
* @param {Record<string, unknown>} stamp
|
|
35
|
+
* @returns {void}
|
|
36
|
+
*/
|
|
37
|
+
function assertApplyAllowed(bid, stamp) {
|
|
38
|
+
if (!stamp) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const meta = /** @type {Record<string, unknown>} */ (bid.meta || {});
|
|
42
|
+
if (stamp.definitionId === bid.definitionId && stamp.definitionHash === bid.definitionHash) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (stamp.definitionId === bid.definitionId) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (stamp.systemKey === /** @type {any} */ (bid.packageIdentity).systemKey && !meta.replaceSystemKey) {
|
|
49
|
+
const err = new Error(
|
|
50
|
+
`systemKey ${stamp.systemKey} already bound to definitionId ${stamp.definitionId}; ` +
|
|
51
|
+
'set meta.replaceSystemKey true to replace'
|
|
52
|
+
);
|
|
53
|
+
err.code = 'BID_SYSTEM_KEY_CONFLICT';
|
|
54
|
+
throw err;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function buildDatasourceCapabilities(caps, key) {
|
|
59
|
+
return caps.map((capability) => ({
|
|
60
|
+
key: capability,
|
|
61
|
+
description: `${capability} ${key}`,
|
|
62
|
+
riskLevel:
|
|
63
|
+
capability === 'delete'
|
|
64
|
+
? 'high'
|
|
65
|
+
: capability.startsWith('create') || capability.startsWith('update')
|
|
66
|
+
? 'medium'
|
|
67
|
+
: 'low',
|
|
68
|
+
approvalRequired: false
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function buildDatasourceSchema(labelField) {
|
|
73
|
+
return {
|
|
74
|
+
metadataSchema: {
|
|
75
|
+
type: 'object',
|
|
76
|
+
properties: {
|
|
77
|
+
externalId: { type: 'string', index: true, description: 'Stable external join identity' },
|
|
78
|
+
id: { type: 'string', index: true, description: 'Vendor record id' },
|
|
79
|
+
[labelField]: { type: 'string', index: true, filter: true, description: 'Display label' }
|
|
80
|
+
},
|
|
81
|
+
required: ['externalId', 'id']
|
|
82
|
+
},
|
|
83
|
+
fieldMappings: {
|
|
84
|
+
attributes: {
|
|
85
|
+
id: { expression: '{{raw.id}}', description: 'Vendor record id' },
|
|
86
|
+
externalId: {
|
|
87
|
+
expression: '{{raw.id}}',
|
|
88
|
+
description: 'Stable join identity (defaults to vendor id until enrichment)'
|
|
89
|
+
},
|
|
90
|
+
[labelField]: {
|
|
91
|
+
expression: `{{raw.${labelField}}}`,
|
|
92
|
+
description: 'Display label (enrich from OpenAPI raw paths as needed)'
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function enrichDatasourceFile(body, ds, enrichOptions) {
|
|
100
|
+
const { enrichDatasourceFromOpenApi } = require('./enrich-openapi-operations');
|
|
101
|
+
const openapiSourceRef =
|
|
102
|
+
(typeof ds.openapiSourceRef === 'string' && ds.openapiSourceRef.trim()) ||
|
|
103
|
+
(typeof enrichOptions.systemOpenapiSourceRef === 'string' &&
|
|
104
|
+
enrichOptions.systemOpenapiSourceRef.trim()) ||
|
|
105
|
+
'';
|
|
106
|
+
if (openapiSourceRef) {
|
|
107
|
+
enrichDatasourceFromOpenApi(body, openapiSourceRef, {
|
|
108
|
+
baseDir: enrichOptions.baseDir,
|
|
109
|
+
associationTargets: enrichOptions.associationTargets
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* @param {Record<string, unknown>} ds
|
|
116
|
+
* @param {string} systemKey
|
|
117
|
+
* @param {Record<string, string[]>} capabilities
|
|
118
|
+
* @param {Record<string, unknown>} sync
|
|
119
|
+
* @returns {Record<string, unknown>}
|
|
120
|
+
*/
|
|
121
|
+
function buildDatasourceFile(ds, systemKey, capabilities, sync, enrichOptions = {}) {
|
|
122
|
+
const key = String(ds.key);
|
|
123
|
+
const caps = capabilities[key] || ds.capabilityKeys || ['list', 'get'];
|
|
124
|
+
const labelField = ds.labelField || 'name';
|
|
125
|
+
const { repairSyncOperationsFromCapabilities } = require('../commands/repair-datasource-sync-operations');
|
|
126
|
+
const { seedPropertyKeysOnDatasource } = require('./enrich-crm-field-mappings');
|
|
127
|
+
const body = {
|
|
128
|
+
key,
|
|
129
|
+
displayName: ds.displayName || key,
|
|
130
|
+
description: ds.description || `${ds.displayName || key} datasource`,
|
|
131
|
+
enabled: true,
|
|
132
|
+
systemKey,
|
|
133
|
+
entityType: ds.entityType || 'recordStorage',
|
|
134
|
+
resourceType: ds.resourceType,
|
|
135
|
+
version: '1.0.0',
|
|
136
|
+
capabilities: buildDatasourceCapabilities(caps, key),
|
|
137
|
+
// Schema sync is mode/schedule/batchSize only; BID sync.mode=incremental is operational intent.
|
|
138
|
+
sync: { mode: 'pull', schedule: /** @type {any} */ (sync).schedule || '0 */6 * * *', batchSize: 100 },
|
|
139
|
+
primaryKey: ['id'],
|
|
140
|
+
labelKey: [labelField],
|
|
141
|
+
...buildDatasourceSchema(labelField)
|
|
142
|
+
};
|
|
143
|
+
// Mirror capabilities → openapi.operations + execution.cip.operations stubs (154.7).
|
|
144
|
+
repairSyncOperationsFromCapabilities(body, []);
|
|
145
|
+
seedPropertyKeysOnDatasource(body, ds.propertyKeys);
|
|
146
|
+
enrichDatasourceFile(body, ds, enrichOptions);
|
|
147
|
+
return body;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Collect vendor object-type segments from each datasource OpenAPI ref.
|
|
152
|
+
* Used so list/get can request associations to sibling collections.
|
|
153
|
+
* @param {any[]} datasources
|
|
154
|
+
* @param {string} systemOpenapiSourceRef
|
|
155
|
+
* @param {{ baseDir?: string }} enrichOptions
|
|
156
|
+
* @returns {string[]}
|
|
157
|
+
*/
|
|
158
|
+
function collectAssociationObjectTypes(datasources, systemOpenapiSourceRef, enrichOptions = {}) {
|
|
159
|
+
const {
|
|
160
|
+
loadOpenApiDocument,
|
|
161
|
+
indexOpenApiOperations,
|
|
162
|
+
objectTypeFromOpenApiPath
|
|
163
|
+
} = require('./enrich-openapi-operations');
|
|
164
|
+
const types = new Set();
|
|
165
|
+
for (const ds of datasources || []) {
|
|
166
|
+
// BID datasource keys are the named collection segments CRM association
|
|
167
|
+
// queries expect (opaque OpenAPI paths like /objects/0-3 omit these).
|
|
168
|
+
const dsKey = String(ds.key || '').trim();
|
|
169
|
+
if (dsKey) {
|
|
170
|
+
types.add(dsKey);
|
|
171
|
+
}
|
|
172
|
+
const ref =
|
|
173
|
+
(typeof ds.openapiSourceRef === 'string' && ds.openapiSourceRef.trim()) ||
|
|
174
|
+
systemOpenapiSourceRef ||
|
|
175
|
+
'';
|
|
176
|
+
if (!ref) {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
try {
|
|
180
|
+
const doc = loadOpenApiDocument(ref, enrichOptions.baseDir);
|
|
181
|
+
const ops = indexOpenApiOperations(doc);
|
|
182
|
+
for (const op of ops) {
|
|
183
|
+
const objectType = objectTypeFromOpenApiPath(op.path);
|
|
184
|
+
if (objectType) {
|
|
185
|
+
types.add(objectType);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
} catch {
|
|
189
|
+
// Skip unreadable refs; enrichment still binds per-datasource.
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return [...types];
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* @param {Record<string, unknown>} bid
|
|
197
|
+
* @returns {Record<string, unknown>}
|
|
198
|
+
*/
|
|
199
|
+
function buildSystemFile(bid) {
|
|
200
|
+
const system = /** @type {Record<string, unknown>} */ (bid.system);
|
|
201
|
+
const identity = /** @type {Record<string, unknown>} */ (bid.packageIdentity);
|
|
202
|
+
const refs = /** @type {Record<string, string>} */ (system.connectionRefs || {});
|
|
203
|
+
const tokenRef = refs.token || refs.apiKey || Object.values(refs)[0] || `kv://${identity.systemKey}/token`;
|
|
204
|
+
return {
|
|
205
|
+
key: system.key,
|
|
206
|
+
displayName: system.displayName || identity.displayName,
|
|
207
|
+
description: system.description || identity.displayName,
|
|
208
|
+
type: system.type || 'openapi',
|
|
209
|
+
enabled: true,
|
|
210
|
+
systemKind: system.systemKind || 'crm',
|
|
211
|
+
authentication: {
|
|
212
|
+
authType: 'credential',
|
|
213
|
+
credential: {
|
|
214
|
+
credentialKey: `${identity.systemKey}-cred`,
|
|
215
|
+
method: 'bearerToken',
|
|
216
|
+
variables: {
|
|
217
|
+
baseUrl: refs.baseUrl || 'https://example.invalid',
|
|
218
|
+
headerName: 'Authorization',
|
|
219
|
+
prefix: 'Bearer'
|
|
220
|
+
},
|
|
221
|
+
security: {
|
|
222
|
+
token: tokenRef
|
|
223
|
+
},
|
|
224
|
+
writeOnce: true
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
dataSources: (/** @type {any[]} */ (bid.datasources) || []).map((d) => d.key)
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* @param {Record<string, unknown>} bid
|
|
233
|
+
* @param {string[]} datasourceFiles
|
|
234
|
+
* @param {string} systemFile
|
|
235
|
+
* @returns {Record<string, unknown>}
|
|
236
|
+
*/
|
|
237
|
+
function buildApplicationFile(bid, datasourceFiles, systemFile) {
|
|
238
|
+
const identity = /** @type {Record<string, unknown>} */ (bid.packageIdentity);
|
|
239
|
+
return {
|
|
240
|
+
app: {
|
|
241
|
+
key: identity.systemKey,
|
|
242
|
+
displayName: identity.displayName,
|
|
243
|
+
description: `${identity.displayName} (BT BID-applied)`,
|
|
244
|
+
type: 'external'
|
|
245
|
+
},
|
|
246
|
+
externalIntegration: {
|
|
247
|
+
schemaBasePath: './',
|
|
248
|
+
systems: [systemFile],
|
|
249
|
+
dataSources: datasourceFiles,
|
|
250
|
+
autopublish: true,
|
|
251
|
+
version: identity.packageVersion
|
|
252
|
+
},
|
|
253
|
+
integrationDefinition: {
|
|
254
|
+
schemaName: bid.schemaName,
|
|
255
|
+
schemaVersion: bid.schemaVersion,
|
|
256
|
+
definitionId: bid.definitionId,
|
|
257
|
+
definitionHash: bid.definitionHash,
|
|
258
|
+
suiteRunId: /** @type {any} */ (bid.meta).suiteRunId
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* @param {Record<string, unknown>} bid
|
|
265
|
+
* @returns {string}
|
|
266
|
+
*/
|
|
267
|
+
function buildEnvTemplate(bid) {
|
|
268
|
+
const identity = /** @type {Record<string, unknown>} */ (bid.packageIdentity);
|
|
269
|
+
const systemKey = String(identity.systemKey);
|
|
270
|
+
const system = /** @type {Record<string, unknown>} */ (bid.system || {});
|
|
271
|
+
const refs = /** @type {Record<string, string>} */ (system.connectionRefs || {});
|
|
272
|
+
const tokenRef = refs.token || refs.apiKey || `kv://${systemKey}/token`;
|
|
273
|
+
return [
|
|
274
|
+
`# Environment for ${systemKey} (BID-applied). No plaintext secrets.`,
|
|
275
|
+
`# Resolve with aifabrix secret set ${systemKey}/token "<value>" --shared`,
|
|
276
|
+
`KV_TOKEN=${tokenRef}`,
|
|
277
|
+
''
|
|
278
|
+
].join('\n');
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* @param {Record<string, unknown>} bid
|
|
283
|
+
* @param {string} systemKey
|
|
284
|
+
* @returns {{
|
|
285
|
+
* systemFile: string,
|
|
286
|
+
* datasourceFiles: string[],
|
|
287
|
+
* application: Record<string, unknown>,
|
|
288
|
+
* system: Record<string, unknown>,
|
|
289
|
+
* dsFiles: Array<{ name: string, body: Record<string, unknown> }>,
|
|
290
|
+
* nextStamp: Record<string, unknown>
|
|
291
|
+
* }}
|
|
292
|
+
*/
|
|
293
|
+
function buildPackageArtifacts(bid, systemKey, enrichOptions = {}) {
|
|
294
|
+
const identity = /** @type {Record<string, unknown>} */ (bid.packageIdentity);
|
|
295
|
+
const datasources = /** @type {Record<string, unknown>[]} */ (bid.datasources || []);
|
|
296
|
+
const capabilities = /** @type {Record<string, string[]>} */ (bid.capabilities || {});
|
|
297
|
+
const sync = /** @type {Record<string, unknown>} */ (bid.sync || {});
|
|
298
|
+
const system = /** @type {Record<string, unknown>} */ (bid.system || {});
|
|
299
|
+
const systemOpenapiSourceRef =
|
|
300
|
+
typeof system.openapiSourceRef === 'string' ? system.openapiSourceRef : '';
|
|
301
|
+
const associationTargets = collectAssociationObjectTypes(
|
|
302
|
+
datasources,
|
|
303
|
+
systemOpenapiSourceRef,
|
|
304
|
+
enrichOptions
|
|
305
|
+
);
|
|
306
|
+
const systemFile = `${systemKey}-system.json`;
|
|
307
|
+
const datasourceFiles = datasources.map((ds) => `${systemKey}-datasource-${ds.key}.json`);
|
|
308
|
+
return {
|
|
309
|
+
systemFile,
|
|
310
|
+
datasourceFiles,
|
|
311
|
+
application: buildApplicationFile(bid, datasourceFiles, systemFile),
|
|
312
|
+
system: buildSystemFile(bid),
|
|
313
|
+
dsFiles: datasources.map((ds) => ({
|
|
314
|
+
name: `${systemKey}-datasource-${ds.key}.json`,
|
|
315
|
+
body: buildDatasourceFile(ds, systemKey, capabilities, sync, {
|
|
316
|
+
...enrichOptions,
|
|
317
|
+
systemOpenapiSourceRef,
|
|
318
|
+
associationTargets
|
|
319
|
+
})
|
|
320
|
+
})),
|
|
321
|
+
envTemplate: buildEnvTemplate(bid),
|
|
322
|
+
nextStamp: {
|
|
323
|
+
schemaName: bid.schemaName,
|
|
324
|
+
schemaVersion: bid.schemaVersion,
|
|
325
|
+
definitionId: bid.definitionId,
|
|
326
|
+
definitionHash: bid.definitionHash,
|
|
327
|
+
suiteRunId: /** @type {any} */ (bid.meta).suiteRunId,
|
|
328
|
+
systemKey,
|
|
329
|
+
packageVersion: identity.packageVersion,
|
|
330
|
+
appliedAt: new Date().toISOString()
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* @param {string} outDir
|
|
337
|
+
* @param {ReturnType<typeof buildPackageArtifacts>} artifacts
|
|
338
|
+
* @returns {Promise<void>}
|
|
339
|
+
*/
|
|
340
|
+
async function writePackageArtifacts(outDir, artifacts) {
|
|
341
|
+
fsReal.mkdirSync(outDir, { recursive: true });
|
|
342
|
+
fsReal.writeFileSync(
|
|
343
|
+
path.join(outDir, 'application.json'),
|
|
344
|
+
JSON.stringify(artifacts.application, null, 2),
|
|
345
|
+
'utf8'
|
|
346
|
+
);
|
|
347
|
+
fsReal.writeFileSync(
|
|
348
|
+
path.join(outDir, artifacts.systemFile),
|
|
349
|
+
JSON.stringify(artifacts.system, null, 2),
|
|
350
|
+
'utf8'
|
|
351
|
+
);
|
|
352
|
+
for (const file of artifacts.dsFiles) {
|
|
353
|
+
fsReal.writeFileSync(path.join(outDir, file.name), JSON.stringify(file.body, null, 2), 'utf8');
|
|
354
|
+
}
|
|
355
|
+
fsReal.writeFileSync(path.join(outDir, 'env.template'), artifacts.envTemplate, 'utf8');
|
|
356
|
+
fsReal.writeFileSync(
|
|
357
|
+
path.join(outDir, STAMP_FILE),
|
|
358
|
+
JSON.stringify(artifacts.nextStamp, null, 2),
|
|
359
|
+
'utf8'
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* @param {unknown} bidInput
|
|
365
|
+
* @returns {Record<string, unknown>}
|
|
366
|
+
*/
|
|
367
|
+
function requireValidBid(bidInput) {
|
|
368
|
+
const result = validateIntegrationDefinition(bidInput);
|
|
369
|
+
if (!result.valid) {
|
|
370
|
+
const err = new Error(`Invalid BID: ${result.errors.join('; ')}`);
|
|
371
|
+
err.code = 'BID_INVALID';
|
|
372
|
+
err.errors = result.errors;
|
|
373
|
+
throw err;
|
|
374
|
+
}
|
|
375
|
+
return result.bid;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* @param {Record<string, unknown> | null} stamp
|
|
380
|
+
* @param {Record<string, unknown>} bid
|
|
381
|
+
* @param {string} outDir
|
|
382
|
+
* @param {string} systemKey
|
|
383
|
+
* @returns {Record<string, unknown> | null}
|
|
384
|
+
*/
|
|
385
|
+
function idempotentResult(stamp, bid, outDir, systemKey) {
|
|
386
|
+
const identity = /** @type {Record<string, unknown>} */ (bid.packageIdentity);
|
|
387
|
+
if (
|
|
388
|
+
!(
|
|
389
|
+
stamp &&
|
|
390
|
+
stamp.definitionId === bid.definitionId &&
|
|
391
|
+
stamp.definitionHash === bid.definitionHash &&
|
|
392
|
+
fsReal.existsSync(path.join(outDir, 'application.json'))
|
|
393
|
+
)
|
|
394
|
+
) {
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
397
|
+
return {
|
|
398
|
+
status: 'idempotent',
|
|
399
|
+
systemKey,
|
|
400
|
+
outputDir: outDir,
|
|
401
|
+
definitionId: bid.definitionId,
|
|
402
|
+
definitionHash: bid.definitionHash,
|
|
403
|
+
packageVersion: identity.packageVersion
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Apply a validated BID to the integration workspace.
|
|
409
|
+
* @async
|
|
410
|
+
* @param {Record<string, unknown>} bidInput
|
|
411
|
+
* @param {{
|
|
412
|
+
* outputDir?: string,
|
|
413
|
+
* workspaceRoot?: string,
|
|
414
|
+
* dryRun?: boolean,
|
|
415
|
+
* force?: boolean,
|
|
416
|
+
* openapiBaseDir?: string,
|
|
417
|
+
* baseDir?: string
|
|
418
|
+
* }} [options]
|
|
419
|
+
* @returns {Promise<Record<string, unknown>>}
|
|
420
|
+
*/
|
|
421
|
+
async function applyIntegrationDefinition(bidInput, options = {}) {
|
|
422
|
+
const bid = requireValidBid(bidInput);
|
|
423
|
+
const identity = /** @type {Record<string, unknown>} */ (bid.packageIdentity);
|
|
424
|
+
const systemKey = String(identity.systemKey);
|
|
425
|
+
const outDir =
|
|
426
|
+
options.outputDir ||
|
|
427
|
+
(options.workspaceRoot
|
|
428
|
+
? path.join(options.workspaceRoot, 'integration', systemKey)
|
|
429
|
+
: getIntegrationPath(systemKey));
|
|
430
|
+
const stamp = await readStamp(outDir);
|
|
431
|
+
const early = options.force ? null : idempotentResult(stamp, bid, outDir, systemKey);
|
|
432
|
+
if (early) {
|
|
433
|
+
return early;
|
|
434
|
+
}
|
|
435
|
+
assertApplyAllowed(bid, stamp);
|
|
436
|
+
// Prefer explicit openapiBaseDir (workspace integration/<systemKey>/openapi
|
|
437
|
+
// from 517.2 persist). Do not default product apply to ship-local enrichment.
|
|
438
|
+
const artifacts = buildPackageArtifacts(bid, systemKey, {
|
|
439
|
+
baseDir: options.openapiBaseDir || options.baseDir
|
|
440
|
+
});
|
|
441
|
+
const fileList = [
|
|
442
|
+
'application.json',
|
|
443
|
+
artifacts.systemFile,
|
|
444
|
+
...artifacts.datasourceFiles,
|
|
445
|
+
'env.template',
|
|
446
|
+
STAMP_FILE
|
|
447
|
+
];
|
|
448
|
+
if (options.dryRun) {
|
|
449
|
+
return {
|
|
450
|
+
status: 'dryRun',
|
|
451
|
+
systemKey,
|
|
452
|
+
outputDir: outDir,
|
|
453
|
+
files: fileList,
|
|
454
|
+
stamp: artifacts.nextStamp
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
await writePackageArtifacts(outDir, artifacts);
|
|
458
|
+
return {
|
|
459
|
+
status: stamp ? 'updated' : 'created',
|
|
460
|
+
systemKey,
|
|
461
|
+
outputDir: outDir,
|
|
462
|
+
definitionId: bid.definitionId,
|
|
463
|
+
definitionHash: bid.definitionHash,
|
|
464
|
+
packageVersion: identity.packageVersion,
|
|
465
|
+
files: fileList
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
module.exports = {
|
|
470
|
+
applyIntegrationDefinition,
|
|
471
|
+
STAMP_FILE,
|
|
472
|
+
buildApplicationFile,
|
|
473
|
+
buildSystemFile,
|
|
474
|
+
buildDatasourceFile,
|
|
475
|
+
buildEnvTemplate
|
|
476
|
+
};
|