@aifabrix/builder 2.46.0 → 2.47.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/.npmrc.token +1 -0
- package/.temp/jest-protection-convert/run-IFN2nv/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-IvmKLO/.protection/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-convert/run-SdvblF/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-b51TsW/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-fiLmb1/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-qYGHMU/.protection/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-Mq5re8/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-f3u4YL/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-iQtd1O/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-mdmz5M/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-qbKYxQ/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-yzlJy6/hubspot-companies.yaml +17 -0
- package/.temp/validation/summary.txt +5 -0
- package/jest.isolated-projects.js +18 -2
- package/jest.projects.js +24 -0
- package/lib/api/dataplane-health.api.js +19 -7
- package/lib/api/lifecycle.api.js +22 -1
- package/lib/api/resource-types.api.js +107 -0
- package/lib/api/runtime-configuration.api.js +72 -0
- package/lib/api/types/resource-types.types.js +45 -0
- package/lib/api/user-groups.api.js +9 -9
- package/lib/api/users.api.js +8 -8
- package/lib/api/wizard.api.js +10 -2
- package/lib/app/down.js +58 -26
- package/lib/app/index.js +2 -2
- package/lib/app/run-resolve-image.js +2 -1
- package/lib/app/run-stop-containers.js +113 -0
- package/lib/app/run.js +1 -31
- package/lib/app/show-display.js +35 -0
- package/lib/app/show.js +32 -1
- package/lib/build/index.js +17 -5
- package/lib/build/miso-controller-npm-sdk-guard.js +25 -0
- package/lib/channels/add-channel.js +348 -0
- package/lib/channels/channel-artifact-generator.js +141 -0
- package/lib/channels/channel-audit.js +101 -0
- package/lib/channels/channel-auth-context.js +37 -0
- package/lib/channels/channel-credential.js +200 -0
- package/lib/channels/channel-display-name.js +64 -0
- package/lib/channels/channel-external-system.js +106 -0
- package/lib/channels/channel-integration-generator.js +274 -0
- package/lib/channels/channel-probe.js +89 -0
- package/lib/channels/channel-runtime-resolver.js +152 -0
- package/lib/channels/channel-status-display.js +141 -0
- package/lib/channels/channel-targets.js +115 -0
- package/lib/cli/index.js +18 -4
- package/lib/cli/infra-guided-auth.js +36 -12
- package/lib/cli/setup-app.js +54 -3
- package/lib/cli/setup-infra-up-dataplane-action.js +2 -2
- package/lib/cli/setup-infra-up-platform-action.js +2 -1
- package/lib/cli/setup-npm.js +59 -0
- package/lib/cli/setup-platform.js +1 -1
- package/lib/cli/setup-secrets.js +1 -1
- package/lib/cli/setup-utility-help-after.js +4 -1
- package/lib/cli/setup-utility-resolve.js +8 -5
- package/lib/commands/app-logs.js +54 -26
- package/lib/commands/app.js +41 -0
- package/lib/commands/auth-status-dataplane-version.js +97 -61
- package/lib/commands/auth-status.js +2 -7
- package/lib/commands/channel.js +58 -0
- package/lib/commands/datasource.js +1 -1
- package/lib/commands/identity-apply-sync.js +49 -8
- package/lib/commands/identity-group-cli.js +66 -26
- package/lib/commands/identity-membership-role-cache.js +58 -37
- package/lib/commands/identity-shared.js +22 -1
- package/lib/commands/identity-user-cli.js +80 -34
- package/lib/commands/login-device.js +11 -3
- package/lib/commands/login.js +8 -3
- package/lib/commands/npm-config.js +103 -0
- package/lib/commands/repair-auth-apply.js +30 -4
- package/lib/commands/repair-auth-config.js +8 -13
- package/lib/commands/repair-datasource-com-v2.js +15 -0
- package/lib/commands/repair-datasource-service-contract.js +206 -0
- package/lib/commands/repair-datasource.js +53 -18
- package/lib/commands/repair-env-template.js +12 -12
- package/lib/commands/repair-openapi-sync.js +26 -4
- package/lib/commands/repair-steps.js +28 -13
- package/lib/commands/repair-system-alignment.js +7 -4
- package/lib/commands/resource-type.js +371 -0
- package/lib/commands/setup-modes.js +1 -1
- package/lib/commands/setup-prompts-platform-mode.js +24 -21
- package/lib/commands/test-trust-external.js +39 -90
- package/lib/commands/up-common.js +33 -1
- package/lib/commands/up-dataplane.js +8 -4
- package/lib/commands/upload.js +24 -3
- package/lib/commands/verify-trust-command-action.js +4 -1
- package/lib/commands/verify-trust-external.js +12 -20
- package/lib/core/config-setup-platform-mode.js +3 -3
- package/lib/core/setup-platform-mode.js +41 -6
- package/lib/datasource/capability/capability-diff-slice.js +2 -2
- package/lib/datasource/capability/capability-manifest.js +254 -0
- package/lib/datasource/capability/capability-resolve.js +3 -4
- package/lib/datasource/capability/copy-operations.js +5 -3
- package/lib/datasource/capability/remove-operations.js +2 -1
- package/lib/datasource/capability/run-capability-copy.js +32 -4
- package/lib/datasource/capability/run-capability-diff.js +3 -3
- package/lib/datasource/capability/run-capability-dimension.js +2 -4
- package/lib/datasource/capability/run-capability-edit.js +4 -7
- package/lib/datasource/capability/run-capability-relate.js +2 -4
- package/lib/datasource/capability/run-capability-remove.js +2 -4
- package/lib/datasource/capability/validate-capability-slice.js +2 -1
- package/lib/datasource/datasource-identifier.js +2 -1
- package/lib/datasource/datasource-validate-display.js +1 -1
- package/lib/datasource/field-reference-validator.js +24 -3
- package/lib/datasource/orphan-profiles-validator.js +98 -0
- package/lib/datasource/validate.js +41 -23
- package/lib/external-system/download-helpers.js +87 -0
- package/lib/external-system/download.js +61 -122
- package/lib/external-system/generator.js +1 -59
- package/lib/external-system/test.js +10 -15
- package/lib/generator/builders.js +11 -1
- package/lib/generator/external-controller-manifest.js +5 -2
- package/lib/generator/split.js +3 -1
- package/lib/generator/wizard.js +1 -28
- package/lib/identity/fk-reference.js +65 -0
- package/lib/identity/identity-apply-core.js +13 -58
- package/lib/identity/identity-apply-phases.js +5 -1
- package/lib/identity/identity-display.js +243 -0
- package/lib/identity/identity-response-helpers.js +52 -0
- package/lib/identity/identity-sync-errors.js +62 -0
- package/lib/identity/resolve-user-id.js +129 -0
- package/lib/identity/username-default.js +31 -0
- package/lib/lifecycle/certification-progress.js +2 -2
- package/lib/lifecycle/report-display-trust.js +70 -0
- package/lib/lifecycle/report-display.js +14 -13
- package/lib/resolvers/datasource-resolver.js +2 -3
- package/lib/resolvers/resource-type-file.js +159 -0
- package/lib/schema/application-schema.json +16 -0
- package/lib/schema/deployment-rules.yaml +2 -1
- package/lib/schema/external-datasource.schema.json +372 -58
- package/lib/schema/external-system.schema.json +331 -2
- package/lib/schema/type/document-storage.json +9 -5
- package/lib/utils/api.js +2 -1
- package/lib/utils/app-run-containers.js +25 -2
- package/lib/utils/authentication-shape.js +224 -0
- package/lib/utils/build-copy.js +36 -5
- package/lib/utils/build-resolve-image.js +66 -12
- package/lib/utils/celery-companion-apps.js +53 -0
- package/lib/utils/cli-utils.js +4 -0
- package/lib/utils/compose-celery-worker.js +23 -0
- package/lib/utils/compose-generate-docker-compose.js +9 -1
- package/lib/utils/configuration-env-resolver.js +36 -0
- package/lib/utils/controller-url.js +4 -1
- package/lib/utils/credential-secrets-env-kv.js +216 -0
- package/lib/utils/credential-secrets-env.js +52 -262
- package/lib/utils/dataplane-resolver.js +4 -115
- package/lib/utils/declarative-url-ports.js +24 -1
- package/lib/utils/dev-platform-tls.js +148 -0
- package/lib/utils/docker-build.js +1 -4
- package/lib/utils/external-env-template.js +10 -3
- package/lib/utils/external-system-validators.js +8 -2
- package/lib/utils/health-check-request.js +114 -0
- package/lib/utils/health-check-url.js +3 -1
- package/lib/utils/health-check.js +1 -113
- package/lib/utils/help-builder.js +3 -0
- package/lib/utils/keycloak-realm-ready.js +5 -1
- package/lib/utils/localhost-public-host.js +31 -0
- package/lib/utils/npm-user-config.js +145 -0
- package/lib/utils/paths.js +25 -0
- package/lib/utils/platform-controller-url.js +58 -4
- package/lib/utils/platform-kv-ref.js +57 -0
- package/lib/utils/runtime-configuration-download.js +189 -0
- package/lib/utils/runtime-configuration-values.js +119 -0
- package/lib/utils/schema-loader.js +19 -4
- package/lib/utils/url-declarative-public-base.js +33 -25
- package/lib/utils/worker-sidecars.js +142 -0
- package/lib/validation/external-manifest-validator.js +2 -0
- package/lib/validation/runtime-configuration-rules.js +98 -0
- package/lib/validation/validate-display-dimensions.js +154 -0
- package/lib/validation/validate-display-sections.js +276 -0
- package/lib/validation/validate-display-steps.js +67 -0
- package/lib/validation/validate-display.js +24 -402
- package/package.json +1 -1
- package/templates/applications/dataplane/application.yaml +5 -0
- package/templates/applications/dataplane/env.template +26 -13
- package/templates/applications/dataplane/rbac.yaml +108 -1
- package/templates/applications/miso-controller/application.yaml +2 -2
- package/templates/applications/miso-controller/env.template +37 -122
- package/templates/applications/miso-controller/rbac.yaml +28 -13
- package/templates/channels/chatgpt/install.template.md.hbs +49 -0
- package/templates/channels/chatgpt/manifest.template.json.hbs +9 -0
- package/templates/channels/microsoft-copilot/install.template.md.hbs +49 -0
- package/templates/channels/microsoft-copilot/manifest.template.json.hbs +8 -0
- package/templates/channels/slack/install.template.md.hbs +49 -0
- package/templates/channels/slack/manifest.template.json.hbs +66 -0
- package/templates/channels/teams-bot/install.template.md.hbs +49 -0
- package/templates/channels/teams-bot/manifest.template.json.hbs +13 -0
- package/templates/channels/web-embed/install.template.md.hbs +49 -0
- package/templates/channels/web-embed/manifest.template.json.hbs +8 -0
- package/templates/python/docker-compose.hbs +56 -0
- package/templates/typescript/docker-compose.hbs +52 -0
|
@@ -6,9 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
|
-
const chalk = require('chalk');
|
|
10
9
|
const logger = require('../utils/logger');
|
|
11
|
-
const { formatBlockingError, formatSuccessLine
|
|
10
|
+
const { formatBlockingError, formatSuccessLine } = require('../utils/cli-layout-chalk');
|
|
12
11
|
const {
|
|
13
12
|
resolveControllerAndAuth,
|
|
14
13
|
requireNonEmpty,
|
|
@@ -21,11 +20,27 @@ const {
|
|
|
21
20
|
createUser,
|
|
22
21
|
listUserGroups
|
|
23
22
|
} = require('../api/users.api');
|
|
23
|
+
const {
|
|
24
|
+
extractPaginatedList,
|
|
25
|
+
printIdentityEmpty,
|
|
26
|
+
printIdentityListHeader,
|
|
27
|
+
printIdentityNotFound,
|
|
28
|
+
printIdentityTable,
|
|
29
|
+
printListPaginationFooter,
|
|
30
|
+
printUserGroupsTable,
|
|
31
|
+
printUserRecord,
|
|
32
|
+
USER_LIST_COLUMNS
|
|
33
|
+
} = require('../identity/identity-display');
|
|
34
|
+
const { resolveIdentityUsername } = require('../identity/username-default');
|
|
24
35
|
|
|
25
36
|
function printJson(data) {
|
|
26
37
|
logger.log(JSON.stringify(data, null, 2));
|
|
27
38
|
}
|
|
28
39
|
|
|
40
|
+
function userNotFoundHints() {
|
|
41
|
+
return ['af identity user list --search <text>', 'Check email, username, or id spelling'];
|
|
42
|
+
}
|
|
43
|
+
|
|
29
44
|
function registerUserCreate(userCmd) {
|
|
30
45
|
userCmd
|
|
31
46
|
.command('create')
|
|
@@ -38,12 +53,13 @@ function registerUserCreate(userCmd) {
|
|
|
38
53
|
.action(async(options) => {
|
|
39
54
|
try {
|
|
40
55
|
const { controllerUrl, authConfig } = await resolveControllerAndAuth();
|
|
56
|
+
const email = requireNonEmpty(options.email, 'email');
|
|
41
57
|
const res = await createUser(controllerUrl, authConfig, {
|
|
42
|
-
email
|
|
58
|
+
email,
|
|
43
59
|
firstName: options.firstName,
|
|
44
60
|
lastName: options.lastName,
|
|
45
61
|
displayName: options.displayName,
|
|
46
|
-
username: options.username,
|
|
62
|
+
username: resolveIdentityUsername({ username: options.username, email }),
|
|
47
63
|
status: 'active'
|
|
48
64
|
});
|
|
49
65
|
throwIfApiFailed(res);
|
|
@@ -62,26 +78,41 @@ function registerUserList(userCmd) {
|
|
|
62
78
|
.description('List users')
|
|
63
79
|
.option('--page <n>', 'Page', (v) => parseInt(v, 10))
|
|
64
80
|
.option('--page-size <n>', 'Page size', (v) => parseInt(v, 10))
|
|
65
|
-
.option('--search <text>', 'Search users')
|
|
81
|
+
.option('--search <text>', 'Search users (email, username, name)')
|
|
82
|
+
.option('--email <email>', 'Exact email filter')
|
|
66
83
|
.option('--json', 'JSON output')
|
|
67
84
|
.action(async(options) => {
|
|
68
85
|
try {
|
|
69
86
|
const { controllerUrl, authConfig } = await resolveControllerAndAuth();
|
|
70
|
-
const
|
|
87
|
+
const params = {
|
|
71
88
|
page: options.page,
|
|
72
89
|
pageSize: options.pageSize,
|
|
73
90
|
search: options.search
|
|
74
|
-
}
|
|
91
|
+
};
|
|
92
|
+
if (options.email) {
|
|
93
|
+
params.filter = `email:eq:${options.email}`;
|
|
94
|
+
delete params.search;
|
|
95
|
+
}
|
|
96
|
+
const res = await listUsers(controllerUrl, authConfig, params);
|
|
75
97
|
throwIfApiFailed(res);
|
|
76
|
-
const data = unwrapControllerData(res);
|
|
77
98
|
if (options.json) {
|
|
78
|
-
printJson(data);
|
|
99
|
+
printJson(res.data ?? res);
|
|
79
100
|
return;
|
|
80
101
|
}
|
|
81
|
-
const items =
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
102
|
+
const { items, meta } = extractPaginatedList(res);
|
|
103
|
+
printIdentityListHeader({
|
|
104
|
+
emoji: '👤',
|
|
105
|
+
title: 'Users',
|
|
106
|
+
context: controllerUrl,
|
|
107
|
+
shown: items.length,
|
|
108
|
+
total: meta?.totalItems ?? items.length
|
|
109
|
+
});
|
|
110
|
+
if (items.length === 0) {
|
|
111
|
+
printIdentityEmpty('No users found.', ['Try --search or --email']);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
printIdentityTable(USER_LIST_COLUMNS, items);
|
|
115
|
+
printListPaginationFooter(meta);
|
|
85
116
|
} catch (e) {
|
|
86
117
|
logger.error(formatBlockingError(e.message));
|
|
87
118
|
process.exit(1);
|
|
@@ -91,22 +122,28 @@ function registerUserList(userCmd) {
|
|
|
91
122
|
|
|
92
123
|
function registerUserGet(userCmd) {
|
|
93
124
|
userCmd
|
|
94
|
-
.command('get <
|
|
95
|
-
.description('Get user by id or
|
|
125
|
+
.command('get <userIdOrEmail>')
|
|
126
|
+
.description('Get user by id, email, or username')
|
|
96
127
|
.option('--json', 'JSON output')
|
|
97
|
-
.action(async(
|
|
128
|
+
.action(async(userIdOrEmail, options) => {
|
|
98
129
|
try {
|
|
99
130
|
const { controllerUrl, authConfig } = await resolveControllerAndAuth();
|
|
100
|
-
const
|
|
101
|
-
|
|
131
|
+
const value = requireNonEmpty(userIdOrEmail, 'userIdOrEmail');
|
|
132
|
+
const res = await getUser(controllerUrl, authConfig, value);
|
|
133
|
+
if (!res || res.success === false) {
|
|
134
|
+
printIdentityNotFound('User', value, userNotFoundHints());
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
102
137
|
const row = unwrapControllerData(res);
|
|
138
|
+
if (!row?.id) {
|
|
139
|
+
printIdentityNotFound('User', value, userNotFoundHints());
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
103
142
|
if (options.json) {
|
|
104
143
|
printJson(row);
|
|
105
144
|
return;
|
|
106
145
|
}
|
|
107
|
-
|
|
108
|
-
logger.log(headerKeyValue('Email:', row.email));
|
|
109
|
-
logger.log('');
|
|
146
|
+
printUserRecord(row);
|
|
110
147
|
} catch (e) {
|
|
111
148
|
logger.error(formatBlockingError(e.message));
|
|
112
149
|
process.exit(1);
|
|
@@ -116,26 +153,35 @@ function registerUserGet(userCmd) {
|
|
|
116
153
|
|
|
117
154
|
function registerUserGroups(userCmd) {
|
|
118
155
|
userCmd
|
|
119
|
-
.command('groups <
|
|
120
|
-
.description('List groups for a user')
|
|
156
|
+
.command('groups <userIdOrEmail>')
|
|
157
|
+
.description('List groups for a user (by id, email, or username)')
|
|
121
158
|
.option('--json', 'JSON output')
|
|
122
|
-
.action(async(
|
|
159
|
+
.action(async(userIdOrEmail, options) => {
|
|
123
160
|
try {
|
|
124
161
|
const { controllerUrl, authConfig } = await resolveControllerAndAuth();
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
162
|
+
const value = requireNonEmpty(userIdOrEmail, 'userIdOrEmail');
|
|
163
|
+
const res = await listUserGroups(controllerUrl, authConfig, value);
|
|
164
|
+
if (!res || res.success === false) {
|
|
165
|
+
printIdentityNotFound('User', value, userNotFoundHints());
|
|
166
|
+
process.exit(1);
|
|
167
|
+
}
|
|
131
168
|
const data = unwrapControllerData(res);
|
|
169
|
+
const items = Array.isArray(data) ? data : data?.data || [];
|
|
132
170
|
if (options.json) {
|
|
133
|
-
printJson(
|
|
171
|
+
printJson(items);
|
|
134
172
|
return;
|
|
135
173
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
174
|
+
printIdentityListHeader({
|
|
175
|
+
emoji: '👥',
|
|
176
|
+
title: `Groups for ${value}`,
|
|
177
|
+
shown: items.length,
|
|
178
|
+
total: items.length
|
|
179
|
+
});
|
|
180
|
+
if (items.length === 0) {
|
|
181
|
+
printIdentityEmpty('No group memberships found.');
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
printUserGroupsTable(items);
|
|
139
185
|
} catch (e) {
|
|
140
186
|
logger.error(formatBlockingError(e.message));
|
|
141
187
|
process.exit(1);
|
|
@@ -81,8 +81,11 @@ async function saveDeviceLoginConfig(controllerUrl, token, refreshToken, expires
|
|
|
81
81
|
* @returns {Promise<void>}
|
|
82
82
|
*/
|
|
83
83
|
async function saveTokenAndDisplaySuccess(controllerUrl, token, refreshToken, expiresAt, envKey, opts = {}) {
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
const storageUrl = opts.tokenControllerUrl
|
|
85
|
+
? String(opts.tokenControllerUrl).trim().replace(/\/+$/, '')
|
|
86
|
+
: controllerUrl;
|
|
87
|
+
await saveDeviceLoginConfig(storageUrl, token, refreshToken, expiresAt);
|
|
88
|
+
await setControllerUrl(storageUrl);
|
|
86
89
|
if (envKey) {
|
|
87
90
|
await setCurrentEnvironment(envKey);
|
|
88
91
|
}
|
|
@@ -219,6 +222,8 @@ function convertDeviceCodeResponse(apiResponse) {
|
|
|
219
222
|
device_code: deviceCodeData.deviceCode || deviceCodeData.device_code,
|
|
220
223
|
user_code: deviceCodeData.userCode || deviceCodeData.user_code,
|
|
221
224
|
verification_uri: deviceCodeData.verificationUri || deviceCodeData.verification_uri,
|
|
225
|
+
verification_uri_complete:
|
|
226
|
+
deviceCodeData.verificationUriComplete || deviceCodeData.verification_uri_complete,
|
|
222
227
|
expires_in: deviceCodeData.expiresIn || deviceCodeData.expires_in || 600,
|
|
223
228
|
interval: deviceCodeData.interval || 5
|
|
224
229
|
};
|
|
@@ -246,8 +251,11 @@ function logDeviceFlowError(deviceError, opts) {
|
|
|
246
251
|
}
|
|
247
252
|
|
|
248
253
|
function printCompactDeviceUrl(deviceCodeResponse) {
|
|
254
|
+
const visitUrl =
|
|
255
|
+
deviceCodeResponse.verification_uri_complete ||
|
|
256
|
+
`${deviceCodeResponse.verification_uri}?user_code=${deviceCodeResponse.user_code}`;
|
|
249
257
|
logger.log('\nOpen browser to authenticate:');
|
|
250
|
-
logger.log(chalk.yellow(`${
|
|
258
|
+
logger.log(chalk.yellow(`${visitUrl}\n`));
|
|
251
259
|
}
|
|
252
260
|
|
|
253
261
|
/**
|
package/lib/commands/login.js
CHANGED
|
@@ -86,8 +86,12 @@ async function normalizeControllerUrl(options) {
|
|
|
86
86
|
controllerUrl = await resolveControllerUrl();
|
|
87
87
|
}
|
|
88
88
|
controllerUrl = String(controllerUrl).trim().replace(/\/+$/, '');
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
if (!options.skipControllerUrlPersist) {
|
|
90
|
+
const persistUrl = options.tokenControllerUrl
|
|
91
|
+
? String(options.tokenControllerUrl).trim().replace(/\/+$/, '')
|
|
92
|
+
: controllerUrl;
|
|
93
|
+
await setControllerUrl(persistUrl);
|
|
94
|
+
}
|
|
91
95
|
if (!options.compact) {
|
|
92
96
|
logger.log(chalk.gray(`Controller URL: ${controllerUrl}`));
|
|
93
97
|
}
|
|
@@ -158,7 +162,8 @@ async function handleCredentialsLoginFlow(controllerUrl, environment, options) {
|
|
|
158
162
|
async function handleDeviceCodeLoginFlow(controllerUrl, environment, options) {
|
|
159
163
|
return await handleDeviceCodeLogin(controllerUrl, environment, options.online, options.scope, {
|
|
160
164
|
compact: Boolean(options.compact),
|
|
161
|
-
exitOnFailure: options.exitOnFailure !== false
|
|
165
|
+
exitOnFailure: options.exitOnFailure !== false,
|
|
166
|
+
tokenControllerUrl: options.tokenControllerUrl
|
|
162
167
|
});
|
|
163
168
|
}
|
|
164
169
|
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* aifabrix npm config — apply user-global npm auth from BASH_NPM_TOKEN.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview npm config command handler
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { execFile } = require('child_process');
|
|
12
|
+
const { promisify } = require('util');
|
|
13
|
+
const chalk = require('chalk');
|
|
14
|
+
const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
|
|
15
|
+
const logger = require('../utils/logger');
|
|
16
|
+
const secretsLoad = require('../core/secrets-load');
|
|
17
|
+
const { collectBashPrefixedEnv } = require('../utils/bash-secret-env');
|
|
18
|
+
const {
|
|
19
|
+
REGISTRY_URL,
|
|
20
|
+
getUserNpmrcPath,
|
|
21
|
+
writeUserNpmrcFromToken
|
|
22
|
+
} = require('../utils/npm-user-config');
|
|
23
|
+
|
|
24
|
+
const execFileAsync = promisify(execFile);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Resolve npm token from merged secrets or --from-env.
|
|
28
|
+
*
|
|
29
|
+
* @param {{ fromEnv?: boolean }} options
|
|
30
|
+
* @returns {Promise<string>}
|
|
31
|
+
*/
|
|
32
|
+
async function resolveNpmToken(options = {}) {
|
|
33
|
+
if (options.fromEnv) {
|
|
34
|
+
const fromProcess = (process.env.NPM_TOKEN || '').trim();
|
|
35
|
+
if (!fromProcess) {
|
|
36
|
+
throw new Error('NPM_TOKEN is not set in the environment (--from-env)');
|
|
37
|
+
}
|
|
38
|
+
return fromProcess;
|
|
39
|
+
}
|
|
40
|
+
const secrets = await secretsLoad.loadSecrets();
|
|
41
|
+
const bashEnv = collectBashPrefixedEnv(secrets);
|
|
42
|
+
const token = bashEnv.NPM_TOKEN;
|
|
43
|
+
if (!token) {
|
|
44
|
+
throw new Error(
|
|
45
|
+
'BASH_NPM_TOKEN is not set in merged secrets. Run: aifabrix secret set BASH_NPM_TOKEN "<token>" --shared'
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
return token;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Run npm whoami against registry.npmjs.org using the given token.
|
|
53
|
+
*
|
|
54
|
+
* @param {string} token
|
|
55
|
+
* @returns {Promise<string>} username
|
|
56
|
+
*/
|
|
57
|
+
async function npmWhoamiWithToken(token) {
|
|
58
|
+
const { stdout } = await execFileAsync(
|
|
59
|
+
'npm',
|
|
60
|
+
['whoami', `--registry=${REGISTRY_URL}`, `--//registry.npmjs.org/:_authToken=${token}`],
|
|
61
|
+
{ env: { ...process.env }, timeout: 30000 }
|
|
62
|
+
);
|
|
63
|
+
return String(stdout).trim();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @param {{ dryRun?: boolean, check?: boolean, fromEnv?: boolean }} options
|
|
68
|
+
* @returns {Promise<{ ok: boolean, npmrcPath?: string, username?: string, dryRun?: boolean }>}
|
|
69
|
+
*/
|
|
70
|
+
async function handleNpmConfig(options = {}) {
|
|
71
|
+
const dryRun = Boolean(options.dryRun);
|
|
72
|
+
const checkOnly = Boolean(options.check);
|
|
73
|
+
const token = await resolveNpmToken({ fromEnv: Boolean(options.fromEnv) });
|
|
74
|
+
const npmrcPath = getUserNpmrcPath();
|
|
75
|
+
|
|
76
|
+
if (checkOnly) {
|
|
77
|
+
const username = await npmWhoamiWithToken(token);
|
|
78
|
+
return { ok: true, npmrcPath, username };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const result = writeUserNpmrcFromToken(token, { dryRun, npmrcPath });
|
|
82
|
+
|
|
83
|
+
if (dryRun) {
|
|
84
|
+
logger.log(chalk.blue('Dry run — would update user npm config:'));
|
|
85
|
+
logger.log(` path: ${npmrcPath}`);
|
|
86
|
+
for (const key of result.managedKeys) {
|
|
87
|
+
const suffix = key.includes('_authToken') ? '=<redacted>' : '';
|
|
88
|
+
logger.log(` ${key}${suffix}`);
|
|
89
|
+
}
|
|
90
|
+
return { ok: true, npmrcPath, dryRun: true };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const username = await npmWhoamiWithToken(token);
|
|
94
|
+
logger.log(formatSuccessLine(`Updated user npm config: ${npmrcPath}`));
|
|
95
|
+
logger.log(chalk.gray(`npm whoami: ${username}`));
|
|
96
|
+
return { ok: true, npmrcPath, username };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
module.exports = {
|
|
100
|
+
resolveNpmToken,
|
|
101
|
+
npmWhoamiWithToken,
|
|
102
|
+
handleNpmConfig
|
|
103
|
+
};
|
|
@@ -10,7 +10,11 @@
|
|
|
10
10
|
|
|
11
11
|
'use strict';
|
|
12
12
|
|
|
13
|
-
const {
|
|
13
|
+
const {
|
|
14
|
+
buildAuthenticationFromMethod,
|
|
15
|
+
getAuthCredentialTemplate,
|
|
16
|
+
migrateAuthenticationToNestedSchema
|
|
17
|
+
} = require('../utils/authentication-shape');
|
|
14
18
|
|
|
15
19
|
/** Repair CLI --auth values (normalized lowercase). */
|
|
16
20
|
const ALLOWED_REPAIR_AUTH = [
|
|
@@ -95,9 +99,10 @@ const MISSING_TEST_ENDPOINT_WARNING =
|
|
|
95
99
|
* @param {string[]} warnings - Mutable warnings list
|
|
96
100
|
*/
|
|
97
101
|
function appendTestEndpointWarningIfMissing(authentication, warnings) {
|
|
98
|
-
const
|
|
102
|
+
const credential = getAuthCredentialTemplate(authentication);
|
|
103
|
+
const method = String(credential?.method || authentication?.method || '').toLowerCase();
|
|
99
104
|
if (method !== 'apikey' && method !== 'bearertoken') return;
|
|
100
|
-
const testEndpoint = String(authentication?.variables?.testEndpoint || '').trim();
|
|
105
|
+
const testEndpoint = String(credential?.variables?.testEndpoint || authentication?.variables?.testEndpoint || '').trim();
|
|
101
106
|
if (testEndpoint) return;
|
|
102
107
|
if (warnings.includes(MISSING_TEST_ENDPOINT_WARNING)) return;
|
|
103
108
|
warnings.push(MISSING_TEST_ENDPOINT_WARNING);
|
|
@@ -114,6 +119,25 @@ function auditRepairAuthenticationWarnings(systemParsed, warnings) {
|
|
|
114
119
|
appendTestEndpointWarningIfMissing(authentication, warnings);
|
|
115
120
|
}
|
|
116
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Ensures system file authentication matches nested schema (authType + credential).
|
|
124
|
+
* @param {Object} systemParsed - Parsed system config (mutated)
|
|
125
|
+
* @param {string} systemKey
|
|
126
|
+
* @param {string[]} changes
|
|
127
|
+
* @returns {boolean}
|
|
128
|
+
*/
|
|
129
|
+
function normalizeAuthenticationSchemaShape(systemParsed, systemKey, changes) {
|
|
130
|
+
const current = systemParsed.authentication || systemParsed.auth;
|
|
131
|
+
const { authentication, changed } = migrateAuthenticationToNestedSchema(current, systemKey);
|
|
132
|
+
if (!changed) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
systemParsed.authentication = authentication;
|
|
136
|
+
delete systemParsed.auth;
|
|
137
|
+
changes.push('Normalized authentication to authType + credential (schema 2.4.x)');
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
|
|
117
141
|
module.exports = {
|
|
118
142
|
ALLOWED_REPAIR_AUTH,
|
|
119
143
|
MISSING_TEST_ENDPOINT_WARNING,
|
|
@@ -123,5 +147,7 @@ module.exports = {
|
|
|
123
147
|
mergePreservedAuthVariables,
|
|
124
148
|
repairAuthChangeLabel,
|
|
125
149
|
appendTestEndpointWarningIfMissing,
|
|
126
|
-
auditRepairAuthenticationWarnings
|
|
150
|
+
auditRepairAuthenticationWarnings,
|
|
151
|
+
normalizeAuthenticationSchemaShape,
|
|
152
|
+
getAuthCredentialTemplate
|
|
127
153
|
};
|
|
@@ -8,17 +8,7 @@
|
|
|
8
8
|
'use strict';
|
|
9
9
|
|
|
10
10
|
const { systemKeyToKvPrefix, securityKeyToVar, kvEnvKeyToPath } = require('../utils/credential-secrets-env');
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Returns true if a kv value looks like legacy format (KeyVault suffix or no path segments).
|
|
14
|
-
* @param {string} val - Value from authentication.security or configuration
|
|
15
|
-
* @returns {boolean}
|
|
16
|
-
*/
|
|
17
|
-
function isLegacyKvValue(val) {
|
|
18
|
-
if (typeof val !== 'string' || !val.trim().toLowerCase().startsWith('kv://')) return false;
|
|
19
|
-
const after = val.trim().slice(5); // after 'kv://'
|
|
20
|
-
return after.includes('KeyVault') || !after.includes('/');
|
|
21
|
-
}
|
|
11
|
+
const { isLegacyKvValue } = require('../utils/platform-kv-ref');
|
|
22
12
|
|
|
23
13
|
/**
|
|
24
14
|
* Normalizes authentication.security keyvault entries to path-style kv:// values (kv://systemKey/variable).
|
|
@@ -87,7 +77,9 @@ function normalizeConfigurationSection(config, prefix, systemKey, changes) {
|
|
|
87
77
|
function normalizeSystemFileAuthAndConfig(systemParsed, systemKey, changes) {
|
|
88
78
|
const prefix = systemKeyToKvPrefix(systemKey);
|
|
89
79
|
if (!prefix) return false;
|
|
90
|
-
const
|
|
80
|
+
const { getAuthCredentialTemplate } = require('../utils/authentication-shape');
|
|
81
|
+
const credential = getAuthCredentialTemplate(systemParsed.authentication);
|
|
82
|
+
const security = credential?.security ?? systemParsed.authentication?.security;
|
|
91
83
|
let updated = (security && typeof security === 'object' && normalizeSecuritySection(security, prefix, systemKey, changes));
|
|
92
84
|
const config = systemParsed.configuration;
|
|
93
85
|
if (Array.isArray(config)) {
|
|
@@ -96,4 +88,7 @@ function normalizeSystemFileAuthAndConfig(systemParsed, systemKey, changes) {
|
|
|
96
88
|
return updated;
|
|
97
89
|
}
|
|
98
90
|
|
|
99
|
-
module.exports = {
|
|
91
|
+
module.exports = {
|
|
92
|
+
normalizeSystemFileAuthAndConfig,
|
|
93
|
+
isLegacyKvValue
|
|
94
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* COM v2 datasource manifest repair (capabilities objects, strip context).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview repair-datasource-com-v2
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { repairComV2Manifest } = require('../datasource/capability/capability-manifest');
|
|
12
|
+
|
|
13
|
+
module.exports = {
|
|
14
|
+
repairComV2Manifest
|
|
15
|
+
};
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* serviceContract repair helpers — migrate deprecated none+llm manifests (439.1).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview repair-datasource-service-contract
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const LLM_CANONICAL_METADATA_SCHEMA = {
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {
|
|
14
|
+
successContent: { type: 'string', nullable: true },
|
|
15
|
+
successEmbedding: {
|
|
16
|
+
type: 'array',
|
|
17
|
+
items: { type: 'number' },
|
|
18
|
+
nullable: true
|
|
19
|
+
},
|
|
20
|
+
successRole: { type: 'string', nullable: true },
|
|
21
|
+
successModel: { type: 'string', nullable: true },
|
|
22
|
+
successFinishReason: { type: 'string', nullable: true },
|
|
23
|
+
errorCode: { type: 'string', nullable: true },
|
|
24
|
+
errorMessage: { type: 'string', nullable: true },
|
|
25
|
+
errorType: { type: 'string', nullable: true },
|
|
26
|
+
usagePromptTokens: { type: 'integer', nullable: true },
|
|
27
|
+
usageCompletionTokens: { type: 'integer', nullable: true },
|
|
28
|
+
usageTotalTokens: { type: 'integer', nullable: true },
|
|
29
|
+
metadataProvider: { type: 'string', nullable: true },
|
|
30
|
+
metadataOperation: { type: 'string', nullable: true }
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const LLM_CANONICAL_EXPOSED_SCHEMA = {
|
|
35
|
+
success: {
|
|
36
|
+
content: 'metadata.successContent',
|
|
37
|
+
embedding: 'metadata.successEmbedding',
|
|
38
|
+
role: 'metadata.successRole',
|
|
39
|
+
model: 'metadata.successModel',
|
|
40
|
+
finishReason: 'metadata.successFinishReason'
|
|
41
|
+
},
|
|
42
|
+
error: {
|
|
43
|
+
code: 'metadata.errorCode',
|
|
44
|
+
message: 'metadata.errorMessage',
|
|
45
|
+
type: 'metadata.errorType'
|
|
46
|
+
},
|
|
47
|
+
usage: {
|
|
48
|
+
promptTokens: 'metadata.usagePromptTokens',
|
|
49
|
+
completionTokens: 'metadata.usageCompletionTokens',
|
|
50
|
+
totalTokens: 'metadata.usageTotalTokens'
|
|
51
|
+
},
|
|
52
|
+
metadata: {
|
|
53
|
+
provider: 'metadata.metadataProvider',
|
|
54
|
+
operation: 'metadata.metadataOperation'
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const LLM_STUB_FIELD_MAPPINGS = {
|
|
59
|
+
successContent: { expression: '{{raw}}' },
|
|
60
|
+
metadataProvider: { expression: '{{inline.metadataProvider}}' },
|
|
61
|
+
metadataOperation: { expression: '{{inline.metadataOperation}}' }
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @param {Object} parsed - Parsed datasource manifest
|
|
66
|
+
* @returns {boolean}
|
|
67
|
+
*/
|
|
68
|
+
function isDeprecatedNoneLlmManifest(parsed) {
|
|
69
|
+
return parsed?.entityType === 'none' && parsed?.resourceType === 'llm';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @param {Object} parsed
|
|
74
|
+
* @param {string[]} changes
|
|
75
|
+
* @returns {boolean}
|
|
76
|
+
*/
|
|
77
|
+
function stripStorageKeysForServiceContract(parsed, changes) {
|
|
78
|
+
let updated = false;
|
|
79
|
+
for (const key of ['primaryKey', 'labelKey', 'sync']) {
|
|
80
|
+
if (parsed[key] !== undefined) {
|
|
81
|
+
delete parsed[key];
|
|
82
|
+
changes.push(`Removed ${key} (not allowed on serviceContract)`);
|
|
83
|
+
updated = true;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return updated;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @param {Object} parsed
|
|
91
|
+
* @param {string} systemKey
|
|
92
|
+
* @param {string[]} changes
|
|
93
|
+
* @returns {boolean}
|
|
94
|
+
*/
|
|
95
|
+
function ensureLlmCipMapSteps(parsed, systemKey, changes) {
|
|
96
|
+
const operations = parsed?.execution?.cip?.operations;
|
|
97
|
+
if (!operations || typeof operations !== 'object') return false;
|
|
98
|
+
let updated = false;
|
|
99
|
+
for (const opKey of ['call', 'embed']) {
|
|
100
|
+
const op = operations[opKey];
|
|
101
|
+
if (!op || !Array.isArray(op.steps)) continue;
|
|
102
|
+
if (op.steps.some((step) => step && step.map)) continue;
|
|
103
|
+
const fetchIdx = op.steps.findIndex((step) => step && step.fetch);
|
|
104
|
+
if (fetchIdx < 0) continue;
|
|
105
|
+
const mapStep = {
|
|
106
|
+
map: {
|
|
107
|
+
useFieldMappings: true,
|
|
108
|
+
inputPath: '$',
|
|
109
|
+
inline: {
|
|
110
|
+
metadataProvider: systemKey || parsed.systemKey || 'provider',
|
|
111
|
+
metadataOperation: opKey
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
op.steps.splice(fetchIdx + 1, 0, mapStep);
|
|
116
|
+
if (!op.steps.some((step) => step && step.output)) {
|
|
117
|
+
op.steps.push({ output: { mode: 'records' } });
|
|
118
|
+
}
|
|
119
|
+
changes.push(`Inserted map+output steps for CIP operation "${opKey}"`);
|
|
120
|
+
updated = true;
|
|
121
|
+
}
|
|
122
|
+
return updated;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @param {Object} parsed
|
|
127
|
+
* @param {string[]} changes
|
|
128
|
+
* @returns {boolean}
|
|
129
|
+
*/
|
|
130
|
+
function stripDeprecatedServiceCategory(parsed, changes) {
|
|
131
|
+
if (parsed?.serviceCategory === undefined) return false;
|
|
132
|
+
delete parsed.serviceCategory;
|
|
133
|
+
changes.push('Removed deprecated serviceCategory (use resourceType for classification)');
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* @param {*} value
|
|
139
|
+
* @returns {*}
|
|
140
|
+
*/
|
|
141
|
+
function deepClone(value) {
|
|
142
|
+
return JSON.parse(JSON.stringify(value));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* @param {Object} parsed
|
|
147
|
+
* @param {string[]} changes
|
|
148
|
+
* @returns {boolean}
|
|
149
|
+
*/
|
|
150
|
+
function applyCanonicalLlmSchemaStubs(parsed, changes) {
|
|
151
|
+
parsed.entityType = 'serviceContract';
|
|
152
|
+
changes.push('Migrated entityType none → serviceContract');
|
|
153
|
+
|
|
154
|
+
parsed.metadataSchema = deepClone(LLM_CANONICAL_METADATA_SCHEMA);
|
|
155
|
+
changes.push('Set canonical LLM metadataSchema stub');
|
|
156
|
+
|
|
157
|
+
if (!parsed.exposed) parsed.exposed = {};
|
|
158
|
+
parsed.exposed.schema = deepClone(LLM_CANONICAL_EXPOSED_SCHEMA);
|
|
159
|
+
if (parsed.exposed.attributes !== undefined) {
|
|
160
|
+
delete parsed.exposed.attributes;
|
|
161
|
+
}
|
|
162
|
+
changes.push('Set canonical LLM exposed.schema envelope');
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @param {Object} parsed
|
|
168
|
+
* @param {string[]} changes
|
|
169
|
+
* @returns {boolean}
|
|
170
|
+
*/
|
|
171
|
+
function applyStubFieldMappingsIfMissing(parsed, changes) {
|
|
172
|
+
const attrs = parsed.fieldMappings?.attributes;
|
|
173
|
+
if (attrs && typeof attrs === 'object' && Object.keys(attrs).length > 0) {
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
if (!parsed.fieldMappings) parsed.fieldMappings = {};
|
|
177
|
+
parsed.fieldMappings.attributes = deepClone(LLM_STUB_FIELD_MAPPINGS);
|
|
178
|
+
changes.push(
|
|
179
|
+
'Added stub fieldMappings.attributes — customize provider raw.* expressions'
|
|
180
|
+
);
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Migrate deprecated none+llm manifest to serviceContract canonical stub.
|
|
186
|
+
*
|
|
187
|
+
* @param {Object} parsed - Parsed datasource (mutated)
|
|
188
|
+
* @param {string[]} changes - Change log
|
|
189
|
+
* @returns {boolean}
|
|
190
|
+
*/
|
|
191
|
+
function repairNoneLlmToServiceContract(parsed, changes) {
|
|
192
|
+
if (!isDeprecatedNoneLlmManifest(parsed)) return false;
|
|
193
|
+
let updated = applyCanonicalLlmSchemaStubs(parsed, changes);
|
|
194
|
+
updated = applyStubFieldMappingsIfMissing(parsed, changes) || updated;
|
|
195
|
+
updated = stripStorageKeysForServiceContract(parsed, changes) || updated;
|
|
196
|
+
updated = ensureLlmCipMapSteps(parsed, parsed.systemKey, changes) || updated;
|
|
197
|
+
return updated;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
module.exports = {
|
|
201
|
+
LLM_CANONICAL_METADATA_SCHEMA,
|
|
202
|
+
LLM_CANONICAL_EXPOSED_SCHEMA,
|
|
203
|
+
isDeprecatedNoneLlmManifest,
|
|
204
|
+
stripDeprecatedServiceCategory,
|
|
205
|
+
repairNoneLlmToServiceContract
|
|
206
|
+
};
|