@aifabrix/builder 2.53.1 → 2.54.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/aifabrix.js +2 -2
- package/lib/api/assistants.api.js +8 -5
- package/lib/api/channel-identity.api.js +41 -0
- package/lib/api/evidence-authoring.api.js +5 -1
- package/lib/api/evidence.api.js +2 -0
- package/lib/api/types/evidence.types.js +2 -0
- package/lib/api/work-search.api.js +136 -0
- package/lib/channels/add-channel.js +163 -126
- package/lib/channels/approval-guides/chatgpt.js +14 -18
- package/lib/channels/approval-guides/claude.js +29 -0
- package/lib/channels/approval-guides/index.js +88 -22
- package/lib/channels/approval-guides/mcp-client.js +27 -0
- package/lib/channels/approval-guides/microsoft-copilot.js +52 -3
- package/lib/channels/approval-guides/slack.js +10 -10
- package/lib/channels/approval-guides/teams-bot.js +8 -12
- package/lib/channels/channel-add-continuations.js +91 -0
- package/lib/channels/channel-add-ensure.js +124 -27
- package/lib/channels/channel-add-existing.js +160 -28
- package/lib/channels/channel-add-failure.js +60 -0
- package/lib/channels/channel-add-remaining.js +486 -0
- package/lib/channels/channel-add-tty.js +190 -0
- package/lib/channels/channel-add-wizard-config.js +138 -0
- package/lib/channels/channel-add-wizard.js +250 -0
- package/lib/channels/channel-artifact-generator.js +27 -13
- package/lib/channels/channel-cardinality.js +83 -0
- package/lib/channels/channel-catalog-icon.js +45 -0
- package/lib/channels/channel-cli-instructions.js +75 -0
- package/lib/channels/channel-configuration-map.js +213 -0
- package/lib/channels/channel-credential.js +11 -14
- package/lib/channels/channel-definition-project.js +101 -0
- package/lib/channels/channel-definition-registry.js +154 -0
- package/lib/channels/channel-description.js +59 -2
- package/lib/channels/channel-discovery.js +16 -2
- package/lib/channels/channel-external-system.js +86 -9
- package/lib/channels/channel-install-envelope-actions.js +88 -0
- package/lib/channels/channel-install-envelope-microsoft.js +155 -0
- package/lib/channels/channel-install-envelope.js +356 -0
- package/lib/channels/channel-install-help-md.js +172 -0
- package/lib/channels/channel-install-http-payload.js +62 -0
- package/lib/channels/channel-install-inventory.js +115 -0
- package/lib/channels/channel-install-profiles.js +90 -0
- package/lib/channels/channel-instance-collision.js +118 -0
- package/lib/channels/channel-instance-key.js +100 -0
- package/lib/channels/channel-instance-materialize.js +240 -0
- package/lib/channels/channel-integration-generator.js +16 -9
- package/lib/channels/channel-integration-template.js +101 -22
- package/lib/channels/channel-inventory-fetch.js +79 -0
- package/lib/channels/channel-oauth-preflight.js +104 -0
- package/lib/channels/channel-package-version.js +76 -0
- package/lib/channels/channel-predefined-client.js +154 -0
- package/lib/channels/channel-probe.js +7 -2
- package/lib/channels/channel-runtime-resolver.js +180 -72
- package/lib/channels/channel-status-display.js +86 -16
- package/lib/channels/channel-targets.js +106 -92
- package/lib/channels/chatgpt-callback.js +318 -0
- package/lib/channels/chatgpt-channel-add.js +229 -0
- package/lib/channels/chatgpt-preflight.js +396 -0
- package/lib/channels/chatgpt-runtime-contract.js +17 -0
- package/lib/channels/chatgpt-setup-values.js +124 -0
- package/lib/channels/claude-callback.js +67 -0
- package/lib/channels/claude-channel-add.js +254 -0
- package/lib/channels/claude-runtime-contract.js +40 -0
- package/lib/channels/claude-runtime.js +58 -0
- package/lib/channels/claude-setup-values.js +89 -0
- package/lib/channels/mcp-client/config-merge.js +148 -0
- package/lib/channels/mcp-client/ensure-client.js +231 -0
- package/lib/channels/mcp-client/paths.js +53 -0
- package/lib/channels/mcp-client/profiles.js +122 -0
- package/lib/channels/mcp-client/redirect-uris.js +99 -0
- package/lib/channels/mcp-client/runtime.js +59 -0
- package/lib/channels/mcp-client-channel-add.js +186 -0
- package/lib/channels/microsoft-copilot-channel-add.js +117 -7
- package/lib/channels/microsoft-copilot-entra-identifier-uris.js +187 -0
- package/lib/channels/microsoft-copilot-entra-sso-form.js +106 -18
- package/lib/channels/microsoft-copilot-entra-sso.js +31 -2
- package/lib/channels/microsoft-copilot-package-prior.js +107 -0
- package/lib/channels/microsoft-copilot-package.js +29 -28
- package/lib/channels/microsoft-provisioning/a365.js +80 -0
- package/lib/channels/microsoft-provisioning/auth-config.js +240 -0
- package/lib/channels/microsoft-provisioning/auth.js +179 -0
- package/lib/channels/microsoft-provisioning/cli.js +71 -0
- package/lib/channels/microsoft-provisioning/constants.js +75 -0
- package/lib/channels/microsoft-provisioning/errors.js +117 -0
- package/lib/channels/microsoft-provisioning/index.js +55 -0
- package/lib/channels/microsoft-provisioning/install-atk.js +158 -0
- package/lib/channels/microsoft-provisioning/install-teams.js +115 -0
- package/lib/channels/microsoft-provisioning/login-portal-device.js +236 -0
- package/lib/channels/microsoft-provisioning/login-portal-parse.js +71 -0
- package/lib/channels/microsoft-provisioning/login-portal-teams.js +193 -0
- package/lib/channels/microsoft-provisioning/login-portal.js +230 -0
- package/lib/channels/microsoft-provisioning/persist.js +110 -0
- package/lib/channels/microsoft-provisioning/teams-bot-args.js +119 -0
- package/lib/channels/microsoft-provisioning/teams-bot-controller.js +123 -0
- package/lib/channels/microsoft-provisioning/teams-bot-parse.js +134 -0
- package/lib/channels/microsoft-provisioning/teams-bot-persist.js +113 -0
- package/lib/channels/microsoft-provisioning/teams-bot-provision.js +234 -0
- package/lib/channels/microsoft-provisioning/teams-bot-secrets.js +45 -0
- package/lib/channels/microsoft-provisioning/teams-cli.js +82 -0
- package/lib/channels/runtime-tool-catalog.js +5 -2
- package/lib/channels/slack-channel-add-portal.js +130 -0
- package/lib/channels/slack-channel-add-tty-auth.js +95 -0
- package/lib/channels/slack-channel-add.js +258 -0
- package/lib/channels/slack-provisioning/apps.js +181 -0
- package/lib/channels/slack-provisioning/auth-store.js +110 -0
- package/lib/channels/slack-provisioning/auth-ticket.js +185 -0
- package/lib/channels/slack-provisioning/auth.js +115 -0
- package/lib/channels/slack-provisioning/callbacks.js +41 -0
- package/lib/channels/slack-provisioning/cli.js +226 -0
- package/lib/channels/slack-provisioning/constants.js +37 -0
- package/lib/channels/slack-provisioning/credentials.js +169 -0
- package/lib/channels/slack-provisioning/curl-shim.js +132 -0
- package/lib/channels/slack-provisioning/developer-install.js +118 -0
- package/lib/channels/slack-provisioning/env-file.js +120 -0
- package/lib/channels/slack-provisioning/errors.js +47 -0
- package/lib/channels/slack-provisioning/go-ca-bundle.js +137 -0
- package/lib/channels/slack-provisioning/index.js +250 -0
- package/lib/channels/slack-provisioning/install-cli.js +323 -0
- package/lib/channels/slack-provisioning/manifest.js +89 -0
- package/lib/channels/slack-provisioning/oauth-lock.js +33 -0
- package/lib/channels/slack-provisioning/offer-cli.js +113 -0
- package/lib/channels/slack-provisioning/onboard-members.js +122 -0
- package/lib/channels/slack-provisioning/onboard.js +89 -0
- package/lib/channels/slack-provisioning/persist.js +95 -0
- package/lib/channels/slack-provisioning/remaining-urls.js +158 -0
- package/lib/channels/slack-provisioning/with-curl-on-path.js +48 -0
- package/lib/channels/teams-bot-channel-add.js +94 -0
- package/lib/channels/vendor-dataplane-url.js +249 -0
- package/lib/cli/setup-certification.help.js +2 -0
- package/lib/cli/setup-external-system-help.js +2 -0
- package/lib/cli/setup-external-system.js +1 -1
- package/lib/commands/channel-add-help.js +366 -0
- package/lib/commands/channel-add-setup.js +162 -80
- package/lib/commands/channel-configure.js +118 -0
- package/lib/commands/channel.js +10 -1
- package/lib/commands/governance-upload-external.js +6 -3
- package/lib/commands/lifecycle-command-action.js +2 -5
- package/lib/commands/lifecycle-external.js +93 -21
- package/lib/commands/repair-datasource-test-payload.js +4 -2
- package/lib/commands/repair-datasource-webhooks-sync-bridge.js +23 -2
- package/lib/commands/repair-datasource.js +3 -0
- package/lib/commands/repair-external-run.js +59 -25
- package/lib/commands/repair-openapi-rest-runtime.js +127 -0
- package/lib/commands/repair-orchestration-tag-merge.js +339 -0
- package/lib/commands/repair-rbac-catalog-defaults.js +96 -0
- package/lib/commands/repair-rbac-platform-preset.js +26 -15
- package/lib/commands/repair-rbac-reader-roles.js +8 -21
- package/lib/commands/repair-rbac.js +10 -34
- package/lib/commands/repair-system-permissions.js +24 -22
- package/lib/commands/role-assistant-test-output.js +14 -0
- package/lib/commands/role-assistant.js +59 -21
- package/lib/commands/test-e2e-external.js +148 -21
- package/lib/commands/upload-credential-push-log.js +2 -1
- package/lib/commands/upload-publish-context.js +1 -1
- package/lib/commands/upload-role-assistant-shell.js +124 -0
- package/lib/commands/upload-sidecar-followups.js +6 -3
- package/lib/commands/upload.js +18 -3
- package/lib/core/secrets-docker-env.js +4 -1
- package/lib/core/secrets-env-content.js +17 -3
- package/lib/datasource/capability/capability-manifest.js +0 -3
- package/lib/datasource/capability/copy-test-payload.js +3 -0
- package/lib/external-system/deploy-helpers.js +26 -1
- package/lib/external-system/deploy.js +10 -6
- package/lib/external-system/download-helpers.js +29 -2
- package/lib/external-system/download-role-assistant.js +83 -4
- package/lib/external-system/download.js +40 -30
- package/lib/external-system/sync-deploy-manifest.js +3 -2
- package/lib/external-system/upload-identity.js +42 -0
- package/lib/generator/index.js +19 -15
- package/lib/generator/split.js +13 -2
- package/lib/lifecycle/role-assistant-governance.js +146 -0
- package/lib/lifecycle/scenario-upload.js +181 -30
- package/lib/programmatic/builder-api-cors.js +143 -0
- package/lib/programmatic/builder-api-request.js +6 -0
- package/lib/programmatic/builder-api-route-dispatch.js +56 -42
- package/lib/programmatic/builder-api-server.js +8 -1
- package/lib/programmatic/capability-registry.js +54 -0
- package/lib/programmatic/channel-install-help-resolve.js +359 -0
- package/lib/programmatic/channel-install-session.js +218 -0
- package/lib/programmatic/help-content/channel-onboarding.md +2 -0
- package/lib/programmatic/help-content/cip-overview.md +3 -1
- package/lib/programmatic/http-raw-response.js +62 -0
- package/lib/programmatic/openapi-channel-install-bindings.js +179 -0
- package/lib/programmatic/openapi-channel-install-schemas.js +286 -0
- package/lib/programmatic/openapi-component-schemas.js +18 -1
- package/lib/programmatic/openapi-description-enricher.js +3 -1
- package/lib/programmatic/openapi-descriptions.js +74 -3
- package/lib/programmatic/openapi-envelope-examples.js +117 -0
- package/lib/programmatic/openapi-operation-bindings.js +4 -1
- package/lib/programmatic/openapi-schema-descriptions-channel.js +316 -0
- package/lib/programmatic/openapi-spec.js +12 -8
- package/lib/programmatic/platform-rbac-catalog.js +36 -18
- package/lib/programmatic/route-handler-map.js +51 -1
- package/lib/programmatic/route-handlers-context.js +2 -1
- package/lib/programmatic/run-auth-permissions.js +54 -0
- package/lib/programmatic/run-channel-catalog.js +196 -0
- package/lib/programmatic/run-channel-install-artifacts.js +137 -0
- package/lib/programmatic/run-channel-install-copilot.js +353 -0
- package/lib/programmatic/run-channel-install-options.js +232 -0
- package/lib/programmatic/run-channel-install-teams-bot.js +204 -0
- package/lib/programmatic/run-channel-install.js +346 -0
- package/lib/programmatic/run-channel-package.js +87 -7
- package/lib/programmatic/workspace-context.js +2 -0
- package/lib/role-assistant/evidence-sync.js +4 -2
- package/lib/role-assistant/evidence-validation-issues.js +51 -0
- package/lib/role-assistant/knowledge-sync.js +10 -4
- package/lib/role-assistant/settings.js +49 -2
- package/lib/role-assistant/test-cases-evaluate.js +30 -2
- package/lib/role-assistant/test-cases-evidence.js +175 -0
- package/lib/role-assistant/test-cases-search.js +229 -0
- package/lib/role-assistant/test-cases.js +37 -4
- package/lib/role-assistant/test-runner-search.js +149 -0
- package/lib/role-assistant/test-runner-workhub-helpers.js +40 -2
- package/lib/role-assistant/test-runner-workhub-soft.js +9 -3
- package/lib/role-assistant/test-runner-workhub.js +29 -11
- package/lib/role-assistant/test-runner.js +16 -1
- package/lib/schema/external-datasource.schema.json +112 -18
- package/lib/schema/external-system.schema.json +159 -2
- package/lib/schema/mcp-client-profile.schema.json +103 -0
- package/lib/utils/app-path-resolve.js +4 -0
- package/lib/utils/authentication-env-template.js +44 -6
- package/lib/utils/credential-secrets-env.js +6 -1
- package/lib/utils/env-copy.js +19 -7
- package/lib/utils/external-env-template.js +20 -2
- package/lib/utils/paths.js +18 -1
- package/lib/utils/platform-shell-package.js +69 -0
- package/lib/utils/port-resolver.js +50 -1
- package/lib/utils/rewrite-name-flag.js +20 -0
- package/lib/utils/role-assistant-paths.js +13 -10
- package/lib/utils/schema-resolver.js +11 -1
- package/lib/utils/secrets-helpers.js +12 -21
- package/lib/utils/token-manager.js +10 -5
- package/lib/validation/validate.js +40 -0
- package/package.json +1 -1
- package/templates/README.md +1 -1
- package/templates/applications/builder-api/Dockerfile +1 -1
- package/templates/applications/builder-api/env.template +7 -0
- package/templates/applications/dataplane/application.yaml +6 -5
- package/templates/applications/dataplane/env.template +2 -2
- package/templates/applications/dataplane/rbac.yaml +7 -2
- package/templates/applications/keycloak/Dockerfile +30 -4
- package/templates/applications/keycloak/application.yaml +2 -2
- package/templates/applications/keycloak/cimd-lenient-parse/AbstractClientIdMetadataDocumentExecutor.java +896 -0
- package/templates/applications/keycloak/cimd-lenient-parse/SOURCE.md +19 -0
- package/templates/applications/keycloak/env.template +3 -0
- package/templates/applications/miso-controller/application.yaml +1 -2
- package/templates/applications/miso-controller/env.template +2 -0
- package/templates/channels/README.md +5 -5
- package/templates/channels/chatgpt/TROUBLESHOOTING.md +51 -0
- package/templates/channels/chatgpt/channel.json +59 -0
- package/templates/channels/chatgpt/icon.svg +1 -0
- package/templates/channels/chatgpt/install.template.md.hbs +20 -95
- package/templates/channels/chatgpt/integration/README.md +1 -1
- package/templates/channels/chatgpt/integration/application.json +2 -2
- package/templates/channels/chatgpt/integration/chatgpt-system.json +49 -4
- package/templates/channels/chatgpt/integration/env.template +2 -4
- package/templates/channels/chatgpt/integration/rbac.json +13 -0
- package/templates/channels/claude/TROUBLESHOOTING.md +41 -0
- package/templates/channels/claude/channel.json +59 -0
- package/templates/channels/claude/icon.svg +1 -0
- package/templates/channels/claude/install.template.md.hbs +21 -0
- package/templates/channels/claude/integration/README.md +14 -0
- package/templates/channels/claude/integration/application.json +15 -0
- package/templates/channels/claude/integration/claude-system.json +59 -0
- package/templates/channels/claude/integration/env.template +2 -0
- package/templates/channels/claude/integration/rbac.json +13 -0
- package/templates/channels/claude/manifest.template.json.hbs +40 -0
- package/templates/channels/mcp-client/channel.json +72 -0
- package/templates/channels/mcp-client/icon.svg +1 -0
- package/templates/channels/mcp-client/install.template.md.hbs +24 -0
- package/templates/channels/mcp-client/integration/README.md +13 -0
- package/templates/channels/mcp-client/integration/application.json +15 -0
- package/templates/channels/mcp-client/integration/env.template +2 -0
- package/templates/channels/mcp-client/integration/mcp-client-system.json +72 -0
- package/templates/channels/mcp-client/integration/rbac.json +13 -0
- package/templates/channels/mcp-client/manifest.template.json.hbs +41 -0
- package/templates/channels/mcp-client/profiles/cursor.json +26 -0
- package/templates/channels/mcp-client/profiles/github-copilot.json +29 -0
- package/templates/channels/mcp-client/profiles/vscode.json +29 -0
- package/templates/channels/microsoft-copilot/channel.json +73 -0
- package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +8 -4
- package/templates/channels/microsoft-copilot/entra-sso-registration.template.md.hbs +65 -5
- package/templates/channels/microsoft-copilot/icon.svg +1 -0
- package/templates/channels/microsoft-copilot/install.template.md.hbs +9 -9
- package/templates/channels/microsoft-copilot/integration/README.md +1 -1
- package/templates/channels/microsoft-copilot/integration/application.json +2 -2
- package/templates/channels/microsoft-copilot/integration/env.template +3 -6
- package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +63 -4
- package/templates/channels/microsoft-copilot/integration/rbac.json +13 -0
- package/templates/channels/microsoft-copilot/oauth-plugin-vault-required.template.md.hbs +5 -5
- package/templates/channels/slack/channel.json +223 -0
- package/templates/channels/slack/icon.svg +1 -0
- package/templates/channels/slack/install.template.md.hbs +36 -28
- package/templates/channels/slack/integration/README.md +245 -22
- package/templates/channels/slack/integration/application.json +44 -7
- package/templates/channels/slack/integration/env.template +15 -6
- package/templates/channels/slack/integration/openapi/openapi.json +126 -0
- package/templates/channels/slack/integration/rbac.json +84 -0
- package/templates/channels/slack/integration/slack-datasource-commands.json +154 -0
- package/templates/channels/slack/integration/slack-datasource-conversations.json +28 -3
- package/templates/channels/slack/integration/slack-datasource-events.json +154 -0
- package/templates/channels/slack/integration/slack-datasource-interactive.json +154 -0
- package/templates/channels/slack/integration/slack-datasource-messages.json +40 -2
- package/templates/channels/slack/integration/slack-system.json +155 -77
- package/templates/channels/slack/manifest.template.json.hbs +5 -2
- package/templates/channels/teams-bot/channel.json +161 -0
- package/templates/channels/teams-bot/icon.svg +1 -0
- package/templates/channels/teams-bot/install.template.md.hbs +12 -13
- package/templates/channels/teams-bot/integration/README.md +5 -4
- package/templates/channels/teams-bot/integration/application.json +6 -4
- package/templates/channels/teams-bot/integration/env.template +5 -4
- package/templates/channels/teams-bot/integration/openapi/openapi.json +68 -0
- package/templates/channels/teams-bot/integration/rbac.json +21 -0
- package/templates/channels/teams-bot/integration/teams-bot-datasource-activities.json +154 -0
- package/templates/channels/teams-bot/integration/teams-bot-system.json +128 -23
- package/templates/channels/web-embed/channel.json +60 -0
- package/templates/channels/web-embed/install.template.md.hbs +1 -1
- package/templates/channels/web-embed/integration/README.md +2 -2
- package/templates/channels/web-embed/integration/application.json +2 -2
- package/templates/channels/web-embed/integration/env.template +1 -1
- package/templates/channels/web-embed/integration/rbac.json +13 -0
- package/templates/channels/web-embed/integration/web-embed-system.json +50 -4
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic channel install profiles (optional `profile` on the same POST).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Catalog profiles from CHANNEL_TARGETS or mcp-client templates
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { CHANNEL_TARGETS } = require('./channel-targets');
|
|
12
|
+
const { listMcpClientProfileChoices } = require('./mcp-client/profiles');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {{ key?: string, displayLabel?: string, name?: string, value?: string }} row
|
|
16
|
+
* @returns {{ key: string, displayLabel: string }}
|
|
17
|
+
*/
|
|
18
|
+
function toProfileRow(row) {
|
|
19
|
+
return {
|
|
20
|
+
key: row.key || row.value,
|
|
21
|
+
displayLabel: row.displayLabel || row.name || row.key || row.value
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @returns {{ key: string, displayLabel: string }[]}
|
|
27
|
+
*/
|
|
28
|
+
function mcpClientProfiles() {
|
|
29
|
+
try {
|
|
30
|
+
return listMcpClientProfileChoices().map(toProfileRow);
|
|
31
|
+
} catch {
|
|
32
|
+
return [
|
|
33
|
+
{ key: 'cursor', displayLabel: 'Cursor' },
|
|
34
|
+
{ key: 'vscode', displayLabel: 'VS Code' },
|
|
35
|
+
{ key: 'github-copilot', displayLabel: 'GitHub Copilot' }
|
|
36
|
+
];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Profiles accepted on POST install.
|
|
42
|
+
* @param {string} channelKey
|
|
43
|
+
* @returns {{ key: string, displayLabel: string }[]}
|
|
44
|
+
*/
|
|
45
|
+
function profilesForInstall(channelKey) {
|
|
46
|
+
const target = CHANNEL_TARGETS[channelKey];
|
|
47
|
+
if (target && Array.isArray(target.profiles) && target.profiles.length > 0) {
|
|
48
|
+
return target.profiles.map(toProfileRow);
|
|
49
|
+
}
|
|
50
|
+
if (channelKey === 'mcp-client') {
|
|
51
|
+
return mcpClientProfiles();
|
|
52
|
+
}
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Profiles advertised on GET /channels when the target is live.
|
|
58
|
+
* @param {string} channelKey
|
|
59
|
+
* @returns {{ key: string, displayLabel: string }[]}
|
|
60
|
+
*/
|
|
61
|
+
function profilesForCatalogRow(channelKey) {
|
|
62
|
+
if (!CHANNEL_TARGETS[channelKey]) {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
return profilesForInstall(channelKey);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @param {string} channelKey
|
|
70
|
+
* @returns {boolean}
|
|
71
|
+
*/
|
|
72
|
+
function installRequiresProfile(channelKey) {
|
|
73
|
+
return profilesForInstall(channelKey).length > 0;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @param {string} channelKey
|
|
78
|
+
* @param {string} profile
|
|
79
|
+
* @returns {boolean}
|
|
80
|
+
*/
|
|
81
|
+
function isAllowedInstallProfile(channelKey, profile) {
|
|
82
|
+
return profilesForInstall(channelKey).some((row) => row.key === profile);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
module.exports = {
|
|
86
|
+
profilesForCatalogRow,
|
|
87
|
+
profilesForInstall,
|
|
88
|
+
installRequiresProfile,
|
|
89
|
+
isAllowedInstallProfile
|
|
90
|
+
};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP install collision: instance key already on Dataplane → 409.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Existing instance becomes continue/update; CLI skip stays on add-channel
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { getExternalSystem } = require('../api/external-systems.api');
|
|
12
|
+
const { unwrapApiData } = require('../utils/external-system-readiness-core');
|
|
13
|
+
const { httpError } = require('../programmatic/channel-install-session');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {unknown} err
|
|
17
|
+
* @returns {boolean}
|
|
18
|
+
*/
|
|
19
|
+
function isNotFoundError(err) {
|
|
20
|
+
const status = Number(
|
|
21
|
+
err && (err.statusCode || err.status || (err.errorData && err.errorData.status))
|
|
22
|
+
);
|
|
23
|
+
return status === 404;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* True only when Dataplane returned that Connected System key.
|
|
28
|
+
* Envelopes, RFC 7807 bodies, leftover catalog keys, and empty objects are not collisions.
|
|
29
|
+
*
|
|
30
|
+
* @param {unknown} system
|
|
31
|
+
* @param {string} instanceKey
|
|
32
|
+
* @returns {boolean}
|
|
33
|
+
*/
|
|
34
|
+
function isExistingChannelInstance(system, instanceKey) {
|
|
35
|
+
if (!system || typeof system !== 'object' || Array.isArray(system)) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
const status = Number(system.status || system.statusCode);
|
|
39
|
+
if (status === 404) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
const key =
|
|
43
|
+
(typeof system.key === 'string' && system.key) ||
|
|
44
|
+
(typeof system.systemKey === 'string' && system.systemKey) ||
|
|
45
|
+
null;
|
|
46
|
+
return key === instanceKey;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @param {Object} ctx
|
|
51
|
+
* @param {string} [instanceKey]
|
|
52
|
+
* @param {Object} [deps]
|
|
53
|
+
* @returns {Promise<void>}
|
|
54
|
+
*/
|
|
55
|
+
async function assertChannelInstanceAvailable(ctx, instanceKey, deps = {}) {
|
|
56
|
+
if (!instanceKey || deps.continueInstall === true || deps.force === true) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const getSystem = deps.getExternalSystem || getExternalSystem;
|
|
60
|
+
let system = null;
|
|
61
|
+
try {
|
|
62
|
+
const res = await getSystem(ctx.dataplaneUrl, instanceKey, {
|
|
63
|
+
type: 'bearer',
|
|
64
|
+
token: ctx.bearerToken,
|
|
65
|
+
preserveBearer: true
|
|
66
|
+
});
|
|
67
|
+
system = unwrapApiData(res);
|
|
68
|
+
} catch (err) {
|
|
69
|
+
if (isNotFoundError(err)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
throw err;
|
|
73
|
+
}
|
|
74
|
+
if (!isExistingChannelInstance(system, instanceKey)) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const displayName = typeof system.displayName === 'string' ? system.displayName.trim() : '';
|
|
78
|
+
const named = displayName && displayName !== instanceKey ? ` ("${displayName}")` : '';
|
|
79
|
+
throw httpError(`Channel instance "${instanceKey}"${named} already exists.`, 409);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Same Connected System key is an in-place update, not a 409.
|
|
84
|
+
* @param {Object} ctx
|
|
85
|
+
* @param {Object} addOptions
|
|
86
|
+
* @param {Object} [body]
|
|
87
|
+
* @param {Object} [deps]
|
|
88
|
+
* @returns {Promise<void>}
|
|
89
|
+
*/
|
|
90
|
+
async function adoptExistingInstanceAsContinue(ctx, addOptions, body, deps = {}) {
|
|
91
|
+
if (addOptions.continueInstall === true || addOptions.force === true) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (body && (body.continueInstall === true || body.force === true)) {
|
|
95
|
+
addOptions.continueInstall = true;
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
await assertChannelInstanceAvailable(ctx, addOptions.systemKey, {
|
|
100
|
+
getExternalSystem: deps.getExternalSystem
|
|
101
|
+
});
|
|
102
|
+
} catch (err) {
|
|
103
|
+
if (Number(err.statusCode) !== 409) {
|
|
104
|
+
throw err;
|
|
105
|
+
}
|
|
106
|
+
addOptions.continueInstall = true;
|
|
107
|
+
if (body && typeof body === 'object') {
|
|
108
|
+
body.continueInstall = true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
module.exports = {
|
|
114
|
+
assertChannelInstanceAvailable,
|
|
115
|
+
adoptExistingInstanceAsContinue,
|
|
116
|
+
isExistingChannelInstance,
|
|
117
|
+
isNotFoundError
|
|
118
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derive and validate Connected System instance keys for channel install.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview definition key ≠ instance key
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const INSTANCE_KEY_RE = /^[a-z0-9-]+$/;
|
|
12
|
+
const MAX_KEY_LENGTH = 40;
|
|
13
|
+
const INSTANCE_EQUALS_CATALOG =
|
|
14
|
+
'Connected System key cannot equal the catalog key.';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {string} definitionKey
|
|
18
|
+
* @param {string} instanceKey
|
|
19
|
+
* @returns {void}
|
|
20
|
+
*/
|
|
21
|
+
function assertInstanceKeyNotCatalogKey(definitionKey, instanceKey) {
|
|
22
|
+
if (String(instanceKey) === String(definitionKey)) {
|
|
23
|
+
throw new Error(
|
|
24
|
+
`${INSTANCE_EQUALS_CATALOG} Use ${definitionKey}-<name-slug>, not "${definitionKey}".`
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param {string} name
|
|
31
|
+
* @returns {string}
|
|
32
|
+
*/
|
|
33
|
+
function slugDisplayName(name) {
|
|
34
|
+
return String(name || '')
|
|
35
|
+
.trim()
|
|
36
|
+
.toLowerCase()
|
|
37
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
38
|
+
.replace(/^-+|-+$/g, '');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @param {string} key
|
|
43
|
+
* @returns {string}
|
|
44
|
+
*/
|
|
45
|
+
function clipInstanceKey(key) {
|
|
46
|
+
if (key.length <= MAX_KEY_LENGTH) {
|
|
47
|
+
return key;
|
|
48
|
+
}
|
|
49
|
+
return key.slice(0, MAX_KEY_LENGTH).replace(/-+$/g, '');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @param {string} definitionKey
|
|
54
|
+
* @param {string} name
|
|
55
|
+
* @param {string} [explicitKey]
|
|
56
|
+
* @returns {string}
|
|
57
|
+
*/
|
|
58
|
+
function deriveChannelInstanceKey(definitionKey, name, explicitKey) {
|
|
59
|
+
let instanceKey;
|
|
60
|
+
if (typeof explicitKey === 'string' && explicitKey.trim()) {
|
|
61
|
+
const trimmed = explicitKey.trim().toLowerCase();
|
|
62
|
+
if (!INSTANCE_KEY_RE.test(trimmed) || trimmed.length < 3 || trimmed.length > MAX_KEY_LENGTH) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
'systemKey must be 3–40 lowercase letters, digits, or hyphens.'
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
instanceKey = trimmed;
|
|
68
|
+
} else {
|
|
69
|
+
const slug = slugDisplayName(name);
|
|
70
|
+
if (!slug) {
|
|
71
|
+
throw new Error('name is required to derive a Connected System key.');
|
|
72
|
+
}
|
|
73
|
+
instanceKey = clipInstanceKey(`${definitionKey}-${slug}`);
|
|
74
|
+
}
|
|
75
|
+
assertInstanceKeyNotCatalogKey(definitionKey, instanceKey);
|
|
76
|
+
return instanceKey;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Derive the instance key and persist it on options.systemKey (never the catalog key).
|
|
81
|
+
* @param {string} definitionKey
|
|
82
|
+
* @param {Object} [options]
|
|
83
|
+
* @returns {string}
|
|
84
|
+
*/
|
|
85
|
+
function resolveChannelInstanceKey(definitionKey, options = {}) {
|
|
86
|
+
const key = deriveChannelInstanceKey(definitionKey, options.name, options.systemKey);
|
|
87
|
+
options.systemKey = key;
|
|
88
|
+
return key;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
module.exports = {
|
|
92
|
+
slugDisplayName,
|
|
93
|
+
clipInstanceKey,
|
|
94
|
+
deriveChannelInstanceKey,
|
|
95
|
+
resolveChannelInstanceKey,
|
|
96
|
+
assertInstanceKeyNotCatalogKey,
|
|
97
|
+
INSTANCE_KEY_RE,
|
|
98
|
+
MAX_KEY_LENGTH,
|
|
99
|
+
INSTANCE_EQUALS_CATALOG
|
|
100
|
+
};
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Materialize a channel instance package from the definition template.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Swap instance key; keep channel.definitionKey
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const { isCommentOrEmptyLine } = require('../utils/secrets-kv-refs');
|
|
14
|
+
|
|
15
|
+
const DEFERRED_CHANNEL_ENV_KV =
|
|
16
|
+
/kv:\/\/\S+\/(clientId|clientSecret|tokenUrl|authorizationUrl|botAppId|signingSecret)(\b|$)/i;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {string} integrationDir
|
|
20
|
+
* @param {string} definitionKey
|
|
21
|
+
* @param {string} instanceKey
|
|
22
|
+
* @returns {void}
|
|
23
|
+
*/
|
|
24
|
+
function applyInstanceKeyToApplication(integrationDir, definitionKey, instanceKey) {
|
|
25
|
+
const appPath = path.join(integrationDir, 'application.json');
|
|
26
|
+
if (!fs.existsSync(appPath)) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const app = JSON.parse(fs.readFileSync(appPath, 'utf8'));
|
|
30
|
+
if (app.app && typeof app.app === 'object') {
|
|
31
|
+
app.app.key = instanceKey;
|
|
32
|
+
}
|
|
33
|
+
if (app.externalIntegration && Array.isArray(app.externalIntegration.systems)) {
|
|
34
|
+
app.externalIntegration.systems = app.externalIntegration.systems.map((name) =>
|
|
35
|
+
name === `${definitionKey}-system.json` ? `${instanceKey}-system.json` : name
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
fs.writeFileSync(appPath, `${JSON.stringify(app, null, 2)}\n`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Stamp catalog identity on the instance ES (channel.definitionKey only).
|
|
43
|
+
* Package JSON must not include `config` (not in the External System schema).
|
|
44
|
+
* @param {Object} doc
|
|
45
|
+
* @param {string} definitionKey
|
|
46
|
+
* @returns {void}
|
|
47
|
+
*/
|
|
48
|
+
function stampInstanceDefinitionKey(doc, definitionKey) {
|
|
49
|
+
const channel = doc.channel && typeof doc.channel === 'object' ? { ...doc.channel } : {};
|
|
50
|
+
channel.definitionKey = definitionKey;
|
|
51
|
+
doc.channel = channel;
|
|
52
|
+
delete doc.config;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Bind datasources to the instance key so vendor OpenAPI resolves to openapi/*.json.
|
|
57
|
+
* Catalog documentKey `{definition}-openapi` + instance systemKey looks for the wrong file.
|
|
58
|
+
* @param {Object} doc
|
|
59
|
+
* @param {string} definitionKey
|
|
60
|
+
* @param {string} instanceKey
|
|
61
|
+
* @returns {void}
|
|
62
|
+
*/
|
|
63
|
+
function rewriteDatasourceInstanceIdentity(doc, definitionKey, instanceKey) {
|
|
64
|
+
if (!doc || typeof doc !== 'object') {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
doc.systemKey = instanceKey;
|
|
68
|
+
if (!doc.openapi || typeof doc.openapi !== 'object') {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const catalogDoc = `${definitionKey}-openapi`;
|
|
72
|
+
if (doc.openapi.documentKey === catalogDoc) {
|
|
73
|
+
doc.openapi.documentKey = `${instanceKey}-openapi`;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @param {string} integrationDir
|
|
79
|
+
* @param {string} definitionKey
|
|
80
|
+
* @param {string} instanceKey
|
|
81
|
+
* @returns {void}
|
|
82
|
+
*/
|
|
83
|
+
function applyInstanceKeyToDatasources(integrationDir, definitionKey, instanceKey) {
|
|
84
|
+
if (!fs.existsSync(integrationDir)) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
for (const name of fs.readdirSync(integrationDir)) {
|
|
88
|
+
if (!name.includes('-datasource-') || !name.endsWith('.json')) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const filePath = path.join(integrationDir, name);
|
|
92
|
+
const doc = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
93
|
+
rewriteDatasourceInstanceIdentity(doc, definitionKey, instanceKey);
|
|
94
|
+
fs.writeFileSync(filePath, `${JSON.stringify(doc, null, 2)}\n`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Secrets written during channel add (Entra/OAuth, Teams botAppId) must not block upload.
|
|
100
|
+
* @param {string} integrationDir
|
|
101
|
+
* @returns {void}
|
|
102
|
+
*/
|
|
103
|
+
function commentStaleOauthEnvTemplateLines(integrationDir) {
|
|
104
|
+
const envPath = path.join(integrationDir, 'env.template');
|
|
105
|
+
if (!fs.existsSync(envPath)) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const original = fs.readFileSync(envPath, 'utf8');
|
|
109
|
+
const next = original
|
|
110
|
+
.split('\n')
|
|
111
|
+
.map((line) => {
|
|
112
|
+
if (isCommentOrEmptyLine(line)) {
|
|
113
|
+
return line;
|
|
114
|
+
}
|
|
115
|
+
return DEFERRED_CHANNEL_ENV_KV.test(line) ? `# ${line.trim()}` : line;
|
|
116
|
+
})
|
|
117
|
+
.join('\n');
|
|
118
|
+
if (next !== original) {
|
|
119
|
+
fs.writeFileSync(envPath, next.endsWith('\n') ? next : `${next}\n`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @param {string} integrationDir
|
|
125
|
+
* @param {string} definitionKey
|
|
126
|
+
* @param {string} instanceKey
|
|
127
|
+
* @returns {string}
|
|
128
|
+
*/
|
|
129
|
+
function resolveInstanceSystemSource(integrationDir, definitionKey, instanceKey) {
|
|
130
|
+
const src = path.join(integrationDir, `${definitionKey}-system.json`);
|
|
131
|
+
const dest = path.join(integrationDir, `${instanceKey}-system.json`);
|
|
132
|
+
if (fs.existsSync(src)) {
|
|
133
|
+
return src;
|
|
134
|
+
}
|
|
135
|
+
return fs.existsSync(dest) ? dest : '';
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* @param {string} integrationDir
|
|
140
|
+
* @param {string} definitionKey
|
|
141
|
+
* @param {string} instanceKey
|
|
142
|
+
* @returns {string}
|
|
143
|
+
*/
|
|
144
|
+
function removeLeftoverCatalogDeployJson(integrationDir, definitionKey, instanceKey) {
|
|
145
|
+
if (definitionKey === instanceKey) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const leftover = path.join(integrationDir, `${definitionKey}-deploy.json`);
|
|
149
|
+
if (fs.existsSync(leftover)) {
|
|
150
|
+
fs.unlinkSync(leftover);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* @param {string} integrationDir
|
|
156
|
+
* @param {string} instanceKey
|
|
157
|
+
* @returns {string[]}
|
|
158
|
+
*/
|
|
159
|
+
function collectDatasourceIdentityErrors(integrationDir, instanceKey) {
|
|
160
|
+
const errors = [];
|
|
161
|
+
for (const name of fs.readdirSync(integrationDir)) {
|
|
162
|
+
if (!name.includes('-datasource-') || !name.endsWith('.json')) {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
const doc = JSON.parse(fs.readFileSync(path.join(integrationDir, name), 'utf8'));
|
|
166
|
+
if (doc.systemKey !== instanceKey) {
|
|
167
|
+
errors.push(`${name} systemKey '${doc.systemKey}'`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return errors;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* @param {string} integrationDir
|
|
175
|
+
* @param {string} instanceKey
|
|
176
|
+
* @returns {void}
|
|
177
|
+
*/
|
|
178
|
+
function assertMaterializedInstanceIdentity(integrationDir, instanceKey) {
|
|
179
|
+
const app = JSON.parse(fs.readFileSync(path.join(integrationDir, 'application.json'), 'utf8'));
|
|
180
|
+
const system = JSON.parse(
|
|
181
|
+
fs.readFileSync(path.join(integrationDir, `${instanceKey}-system.json`), 'utf8')
|
|
182
|
+
);
|
|
183
|
+
const errors = [];
|
|
184
|
+
if (app.app && app.app.key !== instanceKey) {
|
|
185
|
+
errors.push(`application.app.key '${app.app.key}'`);
|
|
186
|
+
}
|
|
187
|
+
if (system.key !== instanceKey) {
|
|
188
|
+
errors.push(`system.key '${system.key}'`);
|
|
189
|
+
}
|
|
190
|
+
errors.push(...collectDatasourceIdentityErrors(integrationDir, instanceKey));
|
|
191
|
+
if (errors.length > 0) {
|
|
192
|
+
throw new Error(
|
|
193
|
+
`Channel instance identity must be '${instanceKey}': ${errors.join('; ')}`
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function maybeAssertMaterializedInstanceIdentity(integrationDir, instanceKey) {
|
|
199
|
+
const appPath = path.join(integrationDir, 'application.json');
|
|
200
|
+
const systemPath = path.join(integrationDir, `${instanceKey}-system.json`);
|
|
201
|
+
if (!fs.existsSync(appPath) || !fs.existsSync(systemPath)) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
assertMaterializedInstanceIdentity(integrationDir, instanceKey);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function writeInstanceSystemFile(from, dest, definitionKey, instanceKey) {
|
|
208
|
+
const doc = JSON.parse(fs.readFileSync(from, 'utf8'));
|
|
209
|
+
doc.key = instanceKey;
|
|
210
|
+
stampInstanceDefinitionKey(doc, definitionKey);
|
|
211
|
+
fs.writeFileSync(dest, `${JSON.stringify(doc, null, 2)}\n`);
|
|
212
|
+
if (from !== dest && fs.existsSync(from)) {
|
|
213
|
+
fs.unlinkSync(from);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function materializeChannelInstanceSystem(integrationDir, definitionKey, instanceKey) {
|
|
218
|
+
commentStaleOauthEnvTemplateLines(integrationDir);
|
|
219
|
+
applyInstanceKeyToDatasources(integrationDir, definitionKey, instanceKey);
|
|
220
|
+
const dest = path.join(integrationDir, `${instanceKey}-system.json`);
|
|
221
|
+
const from = resolveInstanceSystemSource(integrationDir, definitionKey, instanceKey);
|
|
222
|
+
if (from) {
|
|
223
|
+
writeInstanceSystemFile(from, dest, definitionKey, instanceKey);
|
|
224
|
+
}
|
|
225
|
+
applyInstanceKeyToApplication(integrationDir, definitionKey, instanceKey);
|
|
226
|
+
removeLeftoverCatalogDeployJson(integrationDir, definitionKey, instanceKey);
|
|
227
|
+
maybeAssertMaterializedInstanceIdentity(integrationDir, instanceKey);
|
|
228
|
+
return dest;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
module.exports = {
|
|
232
|
+
materializeChannelInstanceSystem,
|
|
233
|
+
applyInstanceKeyToApplication,
|
|
234
|
+
applyInstanceKeyToDatasources,
|
|
235
|
+
commentStaleOauthEnvTemplateLines,
|
|
236
|
+
rewriteDatasourceInstanceIdentity,
|
|
237
|
+
stampInstanceDefinitionKey,
|
|
238
|
+
assertMaterializedInstanceIdentity,
|
|
239
|
+
removeLeftoverCatalogDeployJson
|
|
240
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Scaffold integration/<channelTarget>/ from published templates (plan 152).
|
|
3
|
-
* Manifest SSOT:
|
|
3
|
+
* Manifest SSOT: templates/channels/{target}/integration/.
|
|
4
4
|
* Builder generates only *-deploy.json at scaffold time.
|
|
5
5
|
*
|
|
6
6
|
* @fileoverview Channel integration scaffold — template copy + deploy JSON
|
|
@@ -10,11 +10,13 @@
|
|
|
10
10
|
|
|
11
11
|
'use strict';
|
|
12
12
|
|
|
13
|
-
const fs = require('fs');
|
|
14
13
|
const path = require('path');
|
|
15
14
|
const { getChannelTarget } = require('./channel-targets');
|
|
16
15
|
const { getIntegrationPath } = require('../utils/paths');
|
|
17
|
-
const {
|
|
16
|
+
const {
|
|
17
|
+
copyChannelIntegrationTemplate,
|
|
18
|
+
hasChannelIntegrationFiles
|
|
19
|
+
} = require('./channel-integration-template');
|
|
18
20
|
const { generateDeployJson } = require('../generator/index');
|
|
19
21
|
|
|
20
22
|
/**
|
|
@@ -33,16 +35,20 @@ async function scaffoldChannelIntegration(channelTarget, options = {}) {
|
|
|
33
35
|
);
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
const integrationDir = options.
|
|
37
|
-
? path.
|
|
38
|
-
:
|
|
39
|
-
|
|
38
|
+
const integrationDir = options.integrationDir
|
|
39
|
+
? path.resolve(options.integrationDir)
|
|
40
|
+
: options.projectRoot
|
|
41
|
+
? path.join(path.resolve(options.projectRoot), 'integration', channelTarget)
|
|
42
|
+
: getIntegrationPath(channelTarget);
|
|
43
|
+
if (hasChannelIntegrationFiles(integrationDir, channelTarget) && !options.force) {
|
|
40
44
|
throw new Error(
|
|
41
45
|
`Integration folder already exists: ${integrationDir}. Use --force to overwrite generated files.`
|
|
42
46
|
);
|
|
43
47
|
}
|
|
44
48
|
|
|
45
|
-
const copied = copyChannelIntegrationTemplate(channelTarget, integrationDir
|
|
49
|
+
const copied = copyChannelIntegrationTemplate(channelTarget, integrationDir, {
|
|
50
|
+
overwrite: options.force === true
|
|
51
|
+
});
|
|
46
52
|
const deployPath = await generateDeployJson(channelTarget, { appPath: integrationDir });
|
|
47
53
|
const files = [...copied, deployPath];
|
|
48
54
|
|
|
@@ -53,5 +59,6 @@ async function scaffoldChannelIntegration(channelTarget, options = {}) {
|
|
|
53
59
|
}
|
|
54
60
|
|
|
55
61
|
module.exports = {
|
|
56
|
-
scaffoldChannelIntegration
|
|
62
|
+
scaffoldChannelIntegration,
|
|
63
|
+
hasChannelIntegrationFiles
|
|
57
64
|
};
|