@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
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External AI Discovery mapping for channel packaging (plan 167.0).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Pure discovery → package context; optional Dataplane fetch
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { ApiClient } = require('../api');
|
|
12
|
+
const { RUNTIME_ORCHESTRATION_SYSTEM_KEY } = require('./chatgpt-runtime-contract');
|
|
13
|
+
const { normalizeBaseUrl, joinUrl } = require('./channel-runtime-resolver');
|
|
14
|
+
|
|
15
|
+
const GATEWAY_TOOLS_CATALOG_MARKER = '/api/v1/mcp/servers/tools';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {string} pathOrUrl
|
|
19
|
+
* @returns {boolean}
|
|
20
|
+
*/
|
|
21
|
+
function isGatewayToolsCatalogUrl(pathOrUrl) {
|
|
22
|
+
const value = String(pathOrUrl || '');
|
|
23
|
+
return value.includes(GATEWAY_TOOLS_CATALOG_MARKER);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Normalize discovery paths that include a public `/data` prefix.
|
|
28
|
+
* @param {string} dataplaneBaseUrl
|
|
29
|
+
* @param {string|null|undefined} pathOrUrl
|
|
30
|
+
* @returns {string|null}
|
|
31
|
+
*/
|
|
32
|
+
function resolveDiscoveryUrl(dataplaneBaseUrl, pathOrUrl) {
|
|
33
|
+
if (!pathOrUrl || typeof pathOrUrl !== 'string') {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
const trimmed = pathOrUrl.trim();
|
|
37
|
+
if (!trimmed) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
if (isGatewayToolsCatalogUrl(trimmed)) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
'Gateway tools catalog must not be used as MCP server URL for channel packages'
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
if (/^https?:\/\//i.test(trimmed)) {
|
|
46
|
+
return trimmed;
|
|
47
|
+
}
|
|
48
|
+
let relative = trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
|
|
49
|
+
if (relative.startsWith('/data/api/')) {
|
|
50
|
+
relative = relative.slice('/data'.length);
|
|
51
|
+
}
|
|
52
|
+
return joinUrl(normalizeBaseUrl(dataplaneBaseUrl), relative);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @param {Object} discovery
|
|
57
|
+
* @param {string} key
|
|
58
|
+
* @returns {Object|null}
|
|
59
|
+
*/
|
|
60
|
+
function findEntryPoint(discovery, key) {
|
|
61
|
+
const entries = Array.isArray(discovery?.entryPoints) ? discovery.entryPoints : [];
|
|
62
|
+
return entries.find((ep) => ep && ep.key === key) || null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @param {Object} discovery
|
|
67
|
+
* @returns {string[]}
|
|
68
|
+
*/
|
|
69
|
+
function extractGovernedToolNames(discovery) {
|
|
70
|
+
const fromRuntime = discovery?.runtimeDiscovery?.governedToolNames;
|
|
71
|
+
if (Array.isArray(fromRuntime) && fromRuntime.length > 0) {
|
|
72
|
+
return fromRuntime.map((name) => String(name)).filter(Boolean);
|
|
73
|
+
}
|
|
74
|
+
const tools = Array.isArray(discovery?.tools) ? discovery.tools : [];
|
|
75
|
+
return tools.map((tool) => (tool && tool.name ? String(tool.name) : '')).filter(Boolean);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @param {Object} discovery
|
|
80
|
+
* @param {Object|null} adapter
|
|
81
|
+
* @param {string} dataplaneBaseUrl
|
|
82
|
+
* @returns {{ mcpServerUrl: string|null, installReady: boolean, blocker: string|null }}
|
|
83
|
+
*/
|
|
84
|
+
function resolveMcpConnection(discovery, adapter, dataplaneBaseUrl) {
|
|
85
|
+
const adapterUrl = adapter?.connection?.mcpServerUrl || null;
|
|
86
|
+
const remote = findEntryPoint(discovery, 'remoteMcp');
|
|
87
|
+
const fromEntry =
|
|
88
|
+
resolveDiscoveryUrl(dataplaneBaseUrl, remote?.absoluteUrl) ||
|
|
89
|
+
resolveDiscoveryUrl(dataplaneBaseUrl, remote?.path);
|
|
90
|
+
const mcpServerUrl = resolveDiscoveryUrl(dataplaneBaseUrl, adapterUrl) || fromEntry;
|
|
91
|
+
if (mcpServerUrl && isGatewayToolsCatalogUrl(mcpServerUrl)) {
|
|
92
|
+
throw new Error(
|
|
93
|
+
'Gateway tools catalog must not be used as MCP server URL for channel packages'
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
const mcpReady = discovery?.publication?.mcpReady === true;
|
|
97
|
+
const connectable = adapter ? adapter.connectable === true : mcpReady;
|
|
98
|
+
const remoteAvailable = discovery?.transport?.remoteMcp?.status === 'available';
|
|
99
|
+
const installReady = Boolean(mcpReady && connectable && remoteAvailable && mcpServerUrl);
|
|
100
|
+
const blocker =
|
|
101
|
+
adapter?.blocker ||
|
|
102
|
+
(!installReady ? 'remoteMcpUnavailable' : null);
|
|
103
|
+
return { mcpServerUrl, installReady, blocker };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @param {Object} branding
|
|
108
|
+
* @param {Object} identity
|
|
109
|
+
* @param {Object|null} adapter
|
|
110
|
+
* @returns {string}
|
|
111
|
+
*/
|
|
112
|
+
function resolvePackageDisplayName(branding, identity, adapter) {
|
|
113
|
+
if (typeof branding.displayName === 'string' && branding.displayName.trim()) {
|
|
114
|
+
return branding.displayName.trim();
|
|
115
|
+
}
|
|
116
|
+
return (
|
|
117
|
+
identity.displayName ||
|
|
118
|
+
adapter?.nameForHuman ||
|
|
119
|
+
adapter?.displayName ||
|
|
120
|
+
identity.systemKey ||
|
|
121
|
+
RUNTIME_ORCHESTRATION_SYSTEM_KEY
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @param {Object} branding
|
|
127
|
+
* @param {Object} identity
|
|
128
|
+
* @param {Object|null} adapter
|
|
129
|
+
* @param {Object} discovery
|
|
130
|
+
* @returns {string}
|
|
131
|
+
*/
|
|
132
|
+
function resolvePackageDescription(branding, identity, adapter, discovery) {
|
|
133
|
+
if (typeof branding.description === 'string' && branding.description.trim()) {
|
|
134
|
+
return branding.description.trim();
|
|
135
|
+
}
|
|
136
|
+
return (
|
|
137
|
+
identity.description ||
|
|
138
|
+
adapter?.descriptionForHuman ||
|
|
139
|
+
adapter?.description ||
|
|
140
|
+
discovery.operatingModel?.summary ||
|
|
141
|
+
''
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* @param {Object|null} auth
|
|
147
|
+
* @returns {Object|null}
|
|
148
|
+
*/
|
|
149
|
+
function mapAdapterAuthentication(auth) {
|
|
150
|
+
if (!auth) return null;
|
|
151
|
+
return {
|
|
152
|
+
recommendedCapability: auth.recommendedCapability || null,
|
|
153
|
+
issuer: auth.issuer || null,
|
|
154
|
+
openidConfigurationUrl: auth.openidConfigurationUrl || null,
|
|
155
|
+
authorizationServerMetadataUrl: auth.authorizationServerMetadataUrl || null,
|
|
156
|
+
protectedResourceMetadataUrl: auth.protectedResourceMetadataUrl || null,
|
|
157
|
+
resource: auth.resource || auth.apiResource || null,
|
|
158
|
+
audience: auth.audience !== undefined && auth.audience !== null ? auth.audience : null,
|
|
159
|
+
scopes: Array.isArray(auth.scopes)
|
|
160
|
+
? [...auth.scopes]
|
|
161
|
+
: Array.isArray(auth.allowedScopes)
|
|
162
|
+
? [...auth.allowedScopes]
|
|
163
|
+
: [],
|
|
164
|
+
operatorNote: auth.operatorNote || null,
|
|
165
|
+
pkceRequired: auth.pkceRequired === true,
|
|
166
|
+
clientRegistrationModes: Array.isArray(auth.clientRegistrationModes)
|
|
167
|
+
? [...auth.clientRegistrationModes]
|
|
168
|
+
: []
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* @param {Object} branding
|
|
174
|
+
* @returns {boolean}
|
|
175
|
+
*/
|
|
176
|
+
function isBrandingApplied(branding) {
|
|
177
|
+
return Boolean(
|
|
178
|
+
(branding.displayName && String(branding.displayName).trim()) ||
|
|
179
|
+
(branding.description && String(branding.description).trim())
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Map discovery (+ optional adapter) into packaging fields.
|
|
185
|
+
*
|
|
186
|
+
* @param {Object} params
|
|
187
|
+
* @param {Object} params.discovery
|
|
188
|
+
* @param {Object} [params.adapter]
|
|
189
|
+
* @param {string} params.dataplaneBaseUrl
|
|
190
|
+
* @param {Object} [params.branding]
|
|
191
|
+
* @returns {Object}
|
|
192
|
+
*/
|
|
193
|
+
function mapDiscoveryToPackageContext(params) {
|
|
194
|
+
const discovery = params.discovery;
|
|
195
|
+
if (!discovery || typeof discovery !== 'object') {
|
|
196
|
+
throw new Error('discovery document is required');
|
|
197
|
+
}
|
|
198
|
+
const identity = discovery.identity || {};
|
|
199
|
+
const branding = params.branding && typeof params.branding === 'object' ? params.branding : {};
|
|
200
|
+
const adapter = params.adapter || null;
|
|
201
|
+
const connection = resolveMcpConnection(discovery, adapter, params.dataplaneBaseUrl);
|
|
202
|
+
const authCaps = Array.isArray(discovery.authenticationCapabilities)
|
|
203
|
+
? discovery.authenticationCapabilities.map((c) => c.capability || c).filter(Boolean)
|
|
204
|
+
: [];
|
|
205
|
+
return {
|
|
206
|
+
systemKey: identity.systemKey || RUNTIME_ORCHESTRATION_SYSTEM_KEY,
|
|
207
|
+
displayName: resolvePackageDisplayName(branding, identity, adapter),
|
|
208
|
+
description: resolvePackageDescription(branding, identity, adapter, discovery),
|
|
209
|
+
governedToolNames: extractGovernedToolNames(discovery),
|
|
210
|
+
mcpServerUrl: connection.mcpServerUrl,
|
|
211
|
+
installReady: connection.installReady,
|
|
212
|
+
blocker: connection.blocker,
|
|
213
|
+
authentication: mapAdapterAuthentication(adapter?.authentication || null),
|
|
214
|
+
authenticationCapabilities: authCaps,
|
|
215
|
+
publication: {
|
|
216
|
+
mcpReady: discovery.publication?.mcpReady === true,
|
|
217
|
+
environment: discovery.publication?.environment || null
|
|
218
|
+
},
|
|
219
|
+
brandingApplied: isBrandingApplied(branding)
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* @param {Object} response
|
|
225
|
+
* @returns {Object}
|
|
226
|
+
*/
|
|
227
|
+
function unwrapApiData(response) {
|
|
228
|
+
if (response && typeof response === 'object' && response.data && typeof response.data === 'object') {
|
|
229
|
+
if (response.data.kind || response.data.identity || response.data.adapter) {
|
|
230
|
+
return response.data;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return response;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* @param {string} dataplaneBaseUrl
|
|
238
|
+
* @param {Object} authConfig
|
|
239
|
+
* @param {string} [systemKey]
|
|
240
|
+
* @returns {Promise<Object>}
|
|
241
|
+
*/
|
|
242
|
+
async function fetchExternalAiDiscovery(
|
|
243
|
+
dataplaneBaseUrl,
|
|
244
|
+
authConfig,
|
|
245
|
+
systemKey = RUNTIME_ORCHESTRATION_SYSTEM_KEY
|
|
246
|
+
) {
|
|
247
|
+
const client = new ApiClient(normalizeBaseUrl(dataplaneBaseUrl), authConfig || {});
|
|
248
|
+
const response = await client.get(`/api/v1/external/systems/${systemKey}/discovery`);
|
|
249
|
+
const discovery = unwrapApiData(response);
|
|
250
|
+
if (!discovery || !discovery.kind) {
|
|
251
|
+
throw new Error(`Discovery document missing for systemKey=${systemKey}`);
|
|
252
|
+
}
|
|
253
|
+
return discovery;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* @param {string} dataplaneBaseUrl
|
|
258
|
+
* @param {Object} authConfig
|
|
259
|
+
* @param {string} adapterKey microsoft-plugin | chatgpt-setup
|
|
260
|
+
* @param {string} [systemKey]
|
|
261
|
+
* @returns {Promise<Object>}
|
|
262
|
+
*/
|
|
263
|
+
async function fetchExternalAiDiscoveryAdapter(
|
|
264
|
+
dataplaneBaseUrl,
|
|
265
|
+
authConfig,
|
|
266
|
+
adapterKey,
|
|
267
|
+
systemKey = RUNTIME_ORCHESTRATION_SYSTEM_KEY
|
|
268
|
+
) {
|
|
269
|
+
const client = new ApiClient(normalizeBaseUrl(dataplaneBaseUrl), authConfig || {});
|
|
270
|
+
const response = await client.get(
|
|
271
|
+
`/api/v1/external/systems/${systemKey}/discovery/adapters/${adapterKey}`
|
|
272
|
+
);
|
|
273
|
+
return unwrapApiData(response);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* @param {string} channelTarget
|
|
278
|
+
* @returns {string|null}
|
|
279
|
+
*/
|
|
280
|
+
function adapterKeyForChannel(channelTarget) {
|
|
281
|
+
if (channelTarget === 'microsoft-copilot') return 'microsoft-plugin';
|
|
282
|
+
if (channelTarget === 'chatgpt') return 'chatgpt-setup';
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Fetch discovery (+ adapter when known) and map package context.
|
|
288
|
+
*
|
|
289
|
+
* @param {Object} params
|
|
290
|
+
* @returns {Promise<Object>}
|
|
291
|
+
*/
|
|
292
|
+
async function loadChannelPackageContext(params) {
|
|
293
|
+
const systemKey = params.runtimeSystemKey || RUNTIME_ORCHESTRATION_SYSTEM_KEY;
|
|
294
|
+
const discovery = await fetchExternalAiDiscovery(
|
|
295
|
+
params.dataplaneBaseUrl,
|
|
296
|
+
params.authConfig,
|
|
297
|
+
systemKey
|
|
298
|
+
);
|
|
299
|
+
const adapterKey = adapterKeyForChannel(params.channelTarget);
|
|
300
|
+
let adapter = null;
|
|
301
|
+
if (adapterKey) {
|
|
302
|
+
try {
|
|
303
|
+
adapter = await fetchExternalAiDiscoveryAdapter(
|
|
304
|
+
params.dataplaneBaseUrl,
|
|
305
|
+
params.authConfig,
|
|
306
|
+
adapterKey,
|
|
307
|
+
systemKey
|
|
308
|
+
);
|
|
309
|
+
} catch {
|
|
310
|
+
adapter = null;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return mapDiscoveryToPackageContext({
|
|
314
|
+
discovery,
|
|
315
|
+
adapter,
|
|
316
|
+
dataplaneBaseUrl: params.dataplaneBaseUrl,
|
|
317
|
+
branding: params.branding
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
module.exports = {
|
|
322
|
+
GATEWAY_TOOLS_CATALOG_MARKER,
|
|
323
|
+
isGatewayToolsCatalogUrl,
|
|
324
|
+
resolveDiscoveryUrl,
|
|
325
|
+
mapDiscoveryToPackageContext,
|
|
326
|
+
fetchExternalAiDiscovery,
|
|
327
|
+
fetchExternalAiDiscoveryAdapter,
|
|
328
|
+
adapterKeyForChannel,
|
|
329
|
+
loadChannelPackageContext
|
|
330
|
+
};
|
|
@@ -72,7 +72,7 @@ async function fetchCommunicationSystem(ctx) {
|
|
|
72
72
|
if (!system || typeof system !== 'object') {
|
|
73
73
|
throw new Error(
|
|
74
74
|
`Communication external system "${ctx.channelTarget}" was not found. ` +
|
|
75
|
-
`Run: aifabrix
|
|
75
|
+
`Run: aifabrix channel add ${ctx.channelTarget} --name "…" --force`
|
|
76
76
|
);
|
|
77
77
|
}
|
|
78
78
|
const kind = system.systemKind || system.systemKindKey;
|
|
@@ -19,6 +19,12 @@ const {
|
|
|
19
19
|
COPILOT_RUNTIME_TRANSPORT,
|
|
20
20
|
COPILOT_RUNTIME_AUTH_MODE
|
|
21
21
|
} = require('./chatgpt-runtime-contract');
|
|
22
|
+
const { applyMicrosoftCopilotDisplayLimits } = require('./microsoft-copilot-limits');
|
|
23
|
+
const {
|
|
24
|
+
resolveCopilotEntraScopes,
|
|
25
|
+
evaluateCopilotEntraSsoReadiness
|
|
26
|
+
} = require('./microsoft-copilot-entra-sso');
|
|
27
|
+
const { applyCopilotEntraSsoFormFields } = require('./microsoft-copilot-entra-sso-form');
|
|
22
28
|
|
|
23
29
|
/** Default Slack slash prefix — matches dataplane `templates/slack/command_catalog.yaml`. */
|
|
24
30
|
const DEFAULT_SLACK_COMMAND_PREFIX = 'af';
|
|
@@ -152,15 +158,62 @@ function buildDeterministicGuid(seed) {
|
|
|
152
158
|
* @param {Object} resolved
|
|
153
159
|
* @param {Object} params
|
|
154
160
|
*/
|
|
155
|
-
|
|
161
|
+
/**
|
|
162
|
+
* Apply discovery-driven package context (plan 167.0).
|
|
163
|
+
* @param {Object} resolved
|
|
164
|
+
* @param {Object} [packageContext]
|
|
165
|
+
*/
|
|
166
|
+
function applyDiscoveryPackageContext(resolved, packageContext) {
|
|
167
|
+
if (!packageContext || typeof packageContext !== 'object') {
|
|
168
|
+
resolved.installReady = false;
|
|
169
|
+
resolved.discoveryBlocker = resolved.discoveryBlocker || 'discoveryUnavailable';
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (Array.isArray(packageContext.governedToolNames) && packageContext.governedToolNames.length > 0) {
|
|
173
|
+
resolved.layerBToolNames = [...packageContext.governedToolNames];
|
|
174
|
+
}
|
|
175
|
+
if (packageContext.mcpServerUrl) {
|
|
176
|
+
resolved.mcpUrl = packageContext.mcpServerUrl;
|
|
177
|
+
}
|
|
178
|
+
if (packageContext.displayName && !resolved.brandingNameOverride) {
|
|
179
|
+
// Keep CLI --name as appName; discovery fills defaults only when requested upstream.
|
|
180
|
+
}
|
|
181
|
+
if (packageContext.description && !resolved.appDescription) {
|
|
182
|
+
resolved.appDescription = packageContext.description;
|
|
183
|
+
}
|
|
184
|
+
resolved.installReady = packageContext.installReady === true;
|
|
185
|
+
resolved.discoveryBlocker = packageContext.blocker || null;
|
|
186
|
+
resolved.discoveryAuthentication = packageContext.authentication || null;
|
|
187
|
+
resolved.discoveryAuthenticationCapabilities = packageContext.authenticationCapabilities || [];
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* @param {Object} resolved
|
|
192
|
+
* @returns {void}
|
|
193
|
+
*/
|
|
194
|
+
function applyCopilotRuntimeDomain(resolved) {
|
|
195
|
+
resolved.runtimeDomain = '';
|
|
196
|
+
try {
|
|
197
|
+
resolved.runtimeDomain = new URL(resolved.mcpUrl).hostname;
|
|
198
|
+
} catch {
|
|
199
|
+
try {
|
|
200
|
+
resolved.runtimeDomain = new URL(resolved.dataplaneBaseUrl).hostname;
|
|
201
|
+
} catch {
|
|
202
|
+
resolved.runtimeDomain = '';
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* @param {Object} resolved
|
|
209
|
+
* @param {Object} params
|
|
210
|
+
* @returns {void}
|
|
211
|
+
*/
|
|
212
|
+
function applyCopilotPackageIdentity(resolved, params) {
|
|
156
213
|
resolved.runtimeSystemKey = COPILOT_RUNTIME_SYSTEM_KEY;
|
|
157
214
|
resolved.runtimeTransport = COPILOT_RUNTIME_TRANSPORT;
|
|
158
215
|
resolved.runtimeAuthMode = COPILOT_RUNTIME_AUTH_MODE;
|
|
159
216
|
resolved.layerBToolNames = Array.isArray(params.layerBToolNames) ? [...params.layerBToolNames] : [];
|
|
160
|
-
resolved.scopes = Array.isArray(params.scopes)
|
|
161
|
-
? [...params.scopes]
|
|
162
|
-
: ['openid', 'profile', 'offline_access'];
|
|
163
|
-
resolved.scopesJson = JSON.stringify(resolved.scopes);
|
|
164
217
|
resolved.packageVersion = typeof params.packageVersion === 'string' ? params.packageVersion : '1.0.0';
|
|
165
218
|
resolved.packageAppId = buildDeterministicGuid(
|
|
166
219
|
`${resolved.channelTarget}:${resolved.baseName}:${resolved.environment}:app`
|
|
@@ -168,16 +221,49 @@ function applyMicrosoftCopilotRuntimeValues(resolved, params) {
|
|
|
168
221
|
resolved.pluginId = buildDeterministicGuid(
|
|
169
222
|
`${resolved.channelTarget}:${resolved.baseName}:${resolved.environment}:plugin`
|
|
170
223
|
);
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
224
|
+
const referenceId =
|
|
225
|
+
typeof params.oauthPluginVaultReferenceId === 'string' &&
|
|
226
|
+
params.oauthPluginVaultReferenceId.trim()
|
|
227
|
+
? params.oauthPluginVaultReferenceId.trim()
|
|
228
|
+
: '';
|
|
229
|
+
resolved.oauthPluginVaultReferenceId = referenceId || null;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* @param {Object} resolved
|
|
234
|
+
* @param {Object} params
|
|
235
|
+
* @returns {void}
|
|
236
|
+
*/
|
|
237
|
+
function applyMicrosoftCopilotRuntimeValues(resolved, params) {
|
|
238
|
+
applyCopilotPackageIdentity(resolved, params);
|
|
239
|
+
applyDiscoveryPackageContext(resolved, params.packageContext);
|
|
240
|
+
resolved.scopes = resolveCopilotEntraScopes({
|
|
241
|
+
explicitScopes: params.scopes,
|
|
242
|
+
packageContext: params.packageContext,
|
|
243
|
+
entraProvider: params.entraProvider
|
|
244
|
+
});
|
|
245
|
+
resolved.scopesJson = JSON.stringify(resolved.scopes);
|
|
246
|
+
const readiness = evaluateCopilotEntraSsoReadiness({
|
|
247
|
+
packageContext: params.packageContext,
|
|
248
|
+
oauthPluginVaultReferenceId: resolved.oauthPluginVaultReferenceId,
|
|
249
|
+
scopes: resolved.scopes,
|
|
250
|
+
entraProvider: params.entraProvider || null,
|
|
251
|
+
mcpServerUrl: resolved.mcpUrl || null
|
|
252
|
+
});
|
|
253
|
+
resolved.installReady = readiness.installReady;
|
|
254
|
+
resolved.discoveryBlocker = readiness.blocker;
|
|
255
|
+
resolved.packageReady = readiness.packageReady;
|
|
256
|
+
resolved.packageBlocker = readiness.packageBlocker;
|
|
257
|
+
resolved.microsoftPublicationPending = readiness.microsoftPublicationPending !== false;
|
|
258
|
+
resolved.discoveryAuthentication = readiness.packageAuthentication;
|
|
259
|
+
if (params.entraProvider?.issuer) {
|
|
260
|
+
resolved.entraIssuer = params.entraProvider.issuer;
|
|
180
261
|
}
|
|
262
|
+
if (params.iconColorPath) resolved.iconColorPath = params.iconColorPath;
|
|
263
|
+
if (params.iconOutlinePath) resolved.iconOutlinePath = params.iconOutlinePath;
|
|
264
|
+
applyCopilotRuntimeDomain(resolved);
|
|
265
|
+
applyCopilotEntraSsoFormFields(resolved, params);
|
|
266
|
+
applyMicrosoftCopilotDisplayLimits(resolved);
|
|
181
267
|
}
|
|
182
268
|
|
|
183
269
|
/**
|
|
@@ -254,6 +340,7 @@ function resolveChannelRuntimeValues(params) {
|
|
|
254
340
|
|
|
255
341
|
if (params.channelTarget === 'slack') {
|
|
256
342
|
applySlackRuntimeValues(resolved, params);
|
|
343
|
+
applyDiscoveryPackageContext(resolved, params.packageContext);
|
|
257
344
|
}
|
|
258
345
|
|
|
259
346
|
if (params.channelTarget === 'microsoft-copilot') {
|
|
@@ -262,6 +349,11 @@ function resolveChannelRuntimeValues(params) {
|
|
|
262
349
|
|
|
263
350
|
if (params.channelTarget === 'chatgpt') {
|
|
264
351
|
applyChatGptRuntimeValues(resolved, params);
|
|
352
|
+
applyDiscoveryPackageContext(resolved, params.packageContext);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (params.channelTarget === 'teams-bot') {
|
|
356
|
+
applyDiscoveryPackageContext(resolved, params.packageContext);
|
|
265
357
|
}
|
|
266
358
|
|
|
267
359
|
return resolved;
|
|
@@ -277,6 +369,7 @@ module.exports = {
|
|
|
277
369
|
applySlackRuntimeValues,
|
|
278
370
|
applyMicrosoftCopilotRuntimeValues,
|
|
279
371
|
applyChatGptRuntimeValues,
|
|
372
|
+
applyDiscoveryPackageContext,
|
|
280
373
|
resolveSlackOAuthManifestFields,
|
|
281
374
|
resolveChannelRuntimeValues,
|
|
282
375
|
DEFAULT_SLACK_COMMAND_PREFIX
|
|
@@ -55,10 +55,10 @@ function displayApprovalGuideSection(approvalGuide) {
|
|
|
55
55
|
const heading =
|
|
56
56
|
approvalGuide.approvalRequired === false
|
|
57
57
|
? 'Go-live steps'
|
|
58
|
-
: '
|
|
58
|
+
: 'Organisation publish / Teams admin approval required';
|
|
59
59
|
logger.log(formatWarningLine(heading));
|
|
60
60
|
if (approvalGuide.portalUrl) {
|
|
61
|
-
logger.log(metadata('
|
|
61
|
+
logger.log(metadata('Developer Portal:'));
|
|
62
62
|
logger.log(chalk.cyan(approvalGuide.portalUrl));
|
|
63
63
|
}
|
|
64
64
|
logger.log('');
|
|
@@ -125,7 +125,40 @@ function displayChannelCoreFields(result) {
|
|
|
125
125
|
logger.log(metadata(`Artifact: ${result.artifactPath}`));
|
|
126
126
|
}
|
|
127
127
|
if (result.installGuidePath) {
|
|
128
|
-
logger.log(metadata(`Install guide: ${result.installGuidePath}`));
|
|
128
|
+
logger.log(metadata(`Install guide (README): ${result.installGuidePath}`));
|
|
129
|
+
}
|
|
130
|
+
if (result.zipPath) {
|
|
131
|
+
logger.log(metadata(`Package ZIP: ${result.zipPath}`));
|
|
132
|
+
}
|
|
133
|
+
displayReadinessLines(result);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Split package/Runtime readiness from Microsoft organisation publication.
|
|
138
|
+
* @param {Object} result
|
|
139
|
+
*/
|
|
140
|
+
function displayReadinessLines(result) {
|
|
141
|
+
const packageReady =
|
|
142
|
+
result.packageReady === true ||
|
|
143
|
+
(result.packageReady === undefined && result.installReady === true);
|
|
144
|
+
const packageBlocker = result.packageBlocker || result.blocker || null;
|
|
145
|
+
if (packageReady) {
|
|
146
|
+
logger.log(metadata('Package / Runtime ready: yes'));
|
|
147
|
+
} else if (packageBlocker) {
|
|
148
|
+
logger.log(metadata(`Package / Runtime ready: no (${packageBlocker})`));
|
|
149
|
+
} else if (result.installReady === false) {
|
|
150
|
+
logger.log(metadata('Package / Runtime ready: no'));
|
|
151
|
+
}
|
|
152
|
+
if (result.microsoftPublicationPending === true) {
|
|
153
|
+
logger.log(
|
|
154
|
+
metadata(
|
|
155
|
+
'Microsoft publication: pending (Developer Portal import → Publish to your org → Teams admin approval)'
|
|
156
|
+
)
|
|
157
|
+
);
|
|
158
|
+
} else if (result.microsoftPublicationPending === false) {
|
|
159
|
+
logger.log(metadata('Microsoft publication: cleared'));
|
|
160
|
+
} else if (result.installReady === false && result.blocker && !packageBlocker) {
|
|
161
|
+
logger.log(metadata(`Install ready: no (${result.blocker})`));
|
|
129
162
|
}
|
|
130
163
|
}
|
|
131
164
|
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* microsoft-copilot channel-add helpers (Entra SSO form context for operator errors).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Keep add-channel.js under size limits
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { resolveChannelAuthContext } = require('./channel-auth-context');
|
|
12
|
+
const {
|
|
13
|
+
normalizeBaseChannelName,
|
|
14
|
+
resolveChannelDisplayName
|
|
15
|
+
} = require('./channel-display-name');
|
|
16
|
+
const { getDefaultChannelDescription } = require('./channel-targets');
|
|
17
|
+
const { resolveAppDescription } = require('./channel-description');
|
|
18
|
+
const { loadChannelPackageContext } = require('./channel-discovery');
|
|
19
|
+
const { getInboundMicrosoftEntraIdProvider } = require('../api/token-providers.api');
|
|
20
|
+
const { getKeycloakEntraIdentityProvider } = require('../api/keycloak.api');
|
|
21
|
+
const { resolveChannelRuntimeValues } = require('./channel-runtime-resolver');
|
|
22
|
+
const { assertOauthPluginVaultReferenceId } = require('./microsoft-copilot-entra-sso');
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param {Object} options
|
|
26
|
+
* @returns {boolean}
|
|
27
|
+
*/
|
|
28
|
+
function hasOauthPluginVaultReference(options) {
|
|
29
|
+
return (
|
|
30
|
+
typeof options.oauthPluginVaultReferenceId === 'string' &&
|
|
31
|
+
Boolean(options.oauthPluginVaultReferenceId.trim())
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Load Trust source + Keycloak Entra IdP for Copilot packaging (null on miss/error).
|
|
37
|
+
* @param {Object} ctx
|
|
38
|
+
* @returns {Promise<{ entraProvider: Object|null, entraIdentityProvider: Object|null }>}
|
|
39
|
+
*/
|
|
40
|
+
async function loadMicrosoftCopilotEntraContext(ctx) {
|
|
41
|
+
let entraProvider = null;
|
|
42
|
+
let entraIdentityProvider = null;
|
|
43
|
+
if (!ctx?.controllerUrl) {
|
|
44
|
+
return { entraProvider, entraIdentityProvider };
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
entraProvider = await getInboundMicrosoftEntraIdProvider(ctx.controllerUrl, ctx.authConfig);
|
|
48
|
+
} catch {
|
|
49
|
+
entraProvider = null;
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
entraIdentityProvider = await getKeycloakEntraIdentityProvider(
|
|
53
|
+
ctx.controllerUrl,
|
|
54
|
+
ctx.authConfig
|
|
55
|
+
);
|
|
56
|
+
} catch {
|
|
57
|
+
entraIdentityProvider = null;
|
|
58
|
+
}
|
|
59
|
+
return { entraProvider, entraIdentityProvider };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @param {Object} params
|
|
64
|
+
* @returns {Promise<Object>}
|
|
65
|
+
*/
|
|
66
|
+
async function resolveCopilotFormContextForError(params) {
|
|
67
|
+
const { options, ctx, name, baseName, description } = params;
|
|
68
|
+
let packageContext = null;
|
|
69
|
+
try {
|
|
70
|
+
packageContext = await loadChannelPackageContext({
|
|
71
|
+
dataplaneBaseUrl: ctx.dataplaneUrl,
|
|
72
|
+
authConfig: ctx.authConfig,
|
|
73
|
+
channelTarget: 'microsoft-copilot',
|
|
74
|
+
branding: { displayName: name, description }
|
|
75
|
+
});
|
|
76
|
+
} catch {
|
|
77
|
+
packageContext = null;
|
|
78
|
+
}
|
|
79
|
+
const { entraProvider, entraIdentityProvider } = await loadMicrosoftCopilotEntraContext(ctx);
|
|
80
|
+
return resolveChannelRuntimeValues({
|
|
81
|
+
dataplaneBaseUrl: ctx.dataplaneUrl,
|
|
82
|
+
channelTarget: 'microsoft-copilot',
|
|
83
|
+
appName: name,
|
|
84
|
+
baseName,
|
|
85
|
+
environment: ctx.environment,
|
|
86
|
+
appDescription: description,
|
|
87
|
+
packageContext,
|
|
88
|
+
entraProvider,
|
|
89
|
+
entraIdentityProvider,
|
|
90
|
+
oauthPluginVaultReferenceId: options.oauthPluginVaultReferenceId
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param {Object} params
|
|
96
|
+
* @throws {Error}
|
|
97
|
+
*/
|
|
98
|
+
async function assertMicrosoftCopilotOauthReference(params) {
|
|
99
|
+
const { options } = params;
|
|
100
|
+
if (hasOauthPluginVaultReference(options)) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const formContext = await resolveCopilotFormContextForError(params);
|
|
104
|
+
assertOauthPluginVaultReferenceId({ ...options, formContext });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Fail before force upload when Teams Entra SSO auth-config id is missing.
|
|
109
|
+
* @param {Object} options
|
|
110
|
+
* @throws {Error}
|
|
111
|
+
*/
|
|
112
|
+
async function assertMicrosoftCopilotOauthReferenceBeforeForce(options) {
|
|
113
|
+
if (hasOauthPluginVaultReference(options)) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const ctx = await resolveChannelAuthContext('microsoft-copilot', { silent: options.quiet });
|
|
117
|
+
const baseName = normalizeBaseChannelName(options.name);
|
|
118
|
+
const name = resolveChannelDisplayName(baseName, ctx.environment);
|
|
119
|
+
const rawDescription =
|
|
120
|
+
options.description && String(options.description).trim()
|
|
121
|
+
? String(options.description).trim()
|
|
122
|
+
: getDefaultChannelDescription();
|
|
123
|
+
await assertMicrosoftCopilotOauthReference({
|
|
124
|
+
options,
|
|
125
|
+
ctx,
|
|
126
|
+
name,
|
|
127
|
+
baseName,
|
|
128
|
+
description: resolveAppDescription('microsoft-copilot', rawDescription)
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
module.exports = {
|
|
133
|
+
hasOauthPluginVaultReference,
|
|
134
|
+
loadMicrosoftCopilotEntraContext,
|
|
135
|
+
resolveCopilotFormContextForError,
|
|
136
|
+
assertMicrosoftCopilotOauthReference,
|
|
137
|
+
assertMicrosoftCopilotOauthReferenceBeforeForce
|
|
138
|
+
};
|