@aifabrix/builder 2.10.0 → 2.10.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/lib/app-config.js +39 -8
- package/lib/app-register.js +28 -13
- package/lib/templates.js +8 -3
- package/package.json +1 -1
package/lib/app-config.js
CHANGED
|
@@ -46,23 +46,54 @@ async function generateVariablesYamlFile(appPath, appName, config) {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Generates env.template content for external systems based on authentication type
|
|
51
|
+
* @param {Object} config - Application configuration with authType and systemKey
|
|
52
|
+
* @param {string} appName - Application name (used as fallback for systemKey)
|
|
53
|
+
* @returns {string} Environment template content
|
|
54
|
+
*/
|
|
55
|
+
function generateExternalSystemEnvTemplate(config, appName) {
|
|
56
|
+
const systemKey = config.systemKey || appName;
|
|
57
|
+
const authType = config.authType || 'apikey';
|
|
58
|
+
const lines = [
|
|
59
|
+
`# ${systemKey} ${authType.toUpperCase()} Configuration`,
|
|
60
|
+
'# These values are set via the Miso Controller interface or Dataplane portal',
|
|
61
|
+
'# Values are stored in Key Vault automatically by the platform',
|
|
62
|
+
''
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
if (authType === 'oauth2') {
|
|
66
|
+
lines.push('CLIENTID=kv://' + systemKey + '-clientidKeyVault');
|
|
67
|
+
lines.push('CLIENTSECRET=kv://' + systemKey + '-clientsecretKeyVault');
|
|
68
|
+
lines.push('TOKENURL=https://api.example.com/oauth/token');
|
|
69
|
+
lines.push('REDIRECT_URI=kv://' + systemKey + '-redirect-uriKeyVault');
|
|
70
|
+
} else if (authType === 'apikey') {
|
|
71
|
+
lines.push('API_KEY=kv://' + systemKey + '-api-keyKeyVault');
|
|
72
|
+
} else if (authType === 'basic') {
|
|
73
|
+
lines.push('USERNAME=kv://' + systemKey + '-usernameKeyVault');
|
|
74
|
+
lines.push('PASSWORD=kv://' + systemKey + '-passwordKeyVault');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return lines.join('\n');
|
|
78
|
+
}
|
|
79
|
+
|
|
49
80
|
/**
|
|
50
81
|
* Generates env.template file if it doesn't exist
|
|
51
82
|
* @async
|
|
52
83
|
* @param {string} appPath - Path to application directory
|
|
84
|
+
* @param {string} appName - Application name
|
|
53
85
|
* @param {Object} config - Application configuration
|
|
54
86
|
* @param {Object} existingEnv - Existing environment variables
|
|
55
87
|
*/
|
|
56
|
-
async function generateEnvTemplateFile(appPath, config, existingEnv) {
|
|
57
|
-
// Skip env.template for external type
|
|
58
|
-
if (config.type === 'external') {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
|
|
88
|
+
async function generateEnvTemplateFile(appPath, appName, config, existingEnv) {
|
|
62
89
|
const envTemplatePath = path.join(appPath, 'env.template');
|
|
63
90
|
if (!(await fileExists(envTemplatePath))) {
|
|
64
91
|
let envTemplate;
|
|
65
|
-
|
|
92
|
+
|
|
93
|
+
if (config.type === 'external') {
|
|
94
|
+
// Generate env.template for external systems based on authType
|
|
95
|
+
envTemplate = generateExternalSystemEnvTemplate(config, appName);
|
|
96
|
+
} else if (existingEnv) {
|
|
66
97
|
const envResult = await generateEnvTemplateFromReader(config, existingEnv);
|
|
67
98
|
envTemplate = envResult.template;
|
|
68
99
|
|
|
@@ -155,7 +186,7 @@ async function generateDeployJsonFile(appPath, appName, config) {
|
|
|
155
186
|
async function generateConfigFiles(appPath, appName, config, existingEnv) {
|
|
156
187
|
try {
|
|
157
188
|
await generateVariablesYamlFile(appPath, appName, config);
|
|
158
|
-
await generateEnvTemplateFile(appPath, config, existingEnv);
|
|
189
|
+
await generateEnvTemplateFile(appPath, appName, config, existingEnv);
|
|
159
190
|
await generateRbacYamlFile(appPath, appName, config);
|
|
160
191
|
await generateDeployJsonFile(appPath, appName, config);
|
|
161
192
|
await generateReadmeMdFile(appPath, appName, config);
|
package/lib/app-register.js
CHANGED
|
@@ -21,6 +21,7 @@ const { updateEnvTemplate } = require('./utils/env-template');
|
|
|
21
21
|
const { getOrRefreshDeviceToken } = require('./utils/token-manager');
|
|
22
22
|
const { detectAppType } = require('./utils/paths');
|
|
23
23
|
const { generateEnvFile } = require('./secrets');
|
|
24
|
+
const applicationSchema = require('./schema/application-schema.json');
|
|
24
25
|
|
|
25
26
|
// Import createApp to auto-generate config if missing
|
|
26
27
|
let createApp;
|
|
@@ -30,8 +31,17 @@ try {
|
|
|
30
31
|
createApp = null;
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
// Extract valid enum values from application schema
|
|
35
|
+
const validTypes = applicationSchema.properties.type.enum || [];
|
|
36
|
+
const validRegistryModes = applicationSchema.properties.registryMode.enum || [];
|
|
37
|
+
const portConstraints = {
|
|
38
|
+
minimum: applicationSchema.properties.port?.minimum || 1,
|
|
39
|
+
maximum: applicationSchema.properties.port?.maximum || 65535
|
|
40
|
+
};
|
|
41
|
+
|
|
33
42
|
/**
|
|
34
43
|
* Validation schema for application registration
|
|
44
|
+
* Validates according to application-schema.json
|
|
35
45
|
*/
|
|
36
46
|
const registerApplicationSchema = {
|
|
37
47
|
environmentId: (val) => {
|
|
@@ -44,10 +54,12 @@ const registerApplicationSchema = {
|
|
|
44
54
|
if (!val || val.length < 1) {
|
|
45
55
|
throw new Error('Application key is required');
|
|
46
56
|
}
|
|
47
|
-
|
|
48
|
-
|
|
57
|
+
const keyPattern = applicationSchema.properties.key.pattern;
|
|
58
|
+
const keyMaxLength = applicationSchema.properties.key.maxLength || 50;
|
|
59
|
+
if (val.length > keyMaxLength) {
|
|
60
|
+
throw new Error(`Application key must be at most ${keyMaxLength} characters`);
|
|
49
61
|
}
|
|
50
|
-
if (
|
|
62
|
+
if (keyPattern && !new RegExp(keyPattern).test(val)) {
|
|
51
63
|
throw new Error('Application key must contain only lowercase letters, numbers, and hyphens');
|
|
52
64
|
}
|
|
53
65
|
return val;
|
|
@@ -56,25 +68,28 @@ const registerApplicationSchema = {
|
|
|
56
68
|
if (!val || val.length < 1) {
|
|
57
69
|
throw new Error('Display name is required');
|
|
58
70
|
}
|
|
59
|
-
|
|
60
|
-
|
|
71
|
+
const displayNameMaxLength = applicationSchema.properties.displayName.maxLength || 100;
|
|
72
|
+
if (val.length > displayNameMaxLength) {
|
|
73
|
+
throw new Error(`Display name must be at most ${displayNameMaxLength} characters`);
|
|
61
74
|
}
|
|
62
75
|
return val;
|
|
63
76
|
},
|
|
64
77
|
description: (val) => val || undefined,
|
|
65
78
|
configuration: (val) => {
|
|
66
|
-
const validTypes = ['webapp', 'api', 'service', 'functionapp'];
|
|
67
|
-
const validRegistryModes = ['acr', 'external', 'public'];
|
|
68
|
-
|
|
69
79
|
if (!val || !val.type || !validTypes.includes(val.type)) {
|
|
70
|
-
throw new Error(
|
|
80
|
+
throw new Error(`Configuration type must be one of: ${validTypes.join(', ')}`);
|
|
71
81
|
}
|
|
72
82
|
if (!val.registryMode || !validRegistryModes.includes(val.registryMode)) {
|
|
73
|
-
throw new Error(
|
|
83
|
+
throw new Error(`Registry mode must be one of: ${validRegistryModes.join(', ')}`);
|
|
74
84
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
85
|
+
// Port validation: skip for external type (external systems don't need ports)
|
|
86
|
+
// For other types, port is required and must be valid
|
|
87
|
+
if (val.type !== 'external') {
|
|
88
|
+
if (val.port === undefined || val.port === null) {
|
|
89
|
+
throw new Error('Port is required for non-external application types');
|
|
90
|
+
}
|
|
91
|
+
if (!Number.isInteger(val.port) || val.port < portConstraints.minimum || val.port > portConstraints.maximum) {
|
|
92
|
+
throw new Error(`Port must be an integer between ${portConstraints.minimum} and ${portConstraints.maximum}`);
|
|
78
93
|
}
|
|
79
94
|
}
|
|
80
95
|
return val;
|
package/lib/templates.js
CHANGED
|
@@ -20,11 +20,16 @@ function generateVariablesYaml(appName, config) {
|
|
|
20
20
|
|
|
21
21
|
// For external type, create minimal variables.yaml
|
|
22
22
|
if (appType === 'external') {
|
|
23
|
+
// Use config values if provided, otherwise use defaults consistent with prompts
|
|
24
|
+
const systemKey = config.systemKey || appName;
|
|
25
|
+
const systemDisplayName = config.systemDisplayName || displayName;
|
|
26
|
+
const systemDescription = config.systemDescription || `External system integration for ${appName}`;
|
|
27
|
+
|
|
23
28
|
const variables = {
|
|
24
29
|
app: {
|
|
25
|
-
key:
|
|
26
|
-
displayName:
|
|
27
|
-
description:
|
|
30
|
+
key: systemKey,
|
|
31
|
+
displayName: systemDisplayName,
|
|
32
|
+
description: systemDescription,
|
|
28
33
|
type: 'external'
|
|
29
34
|
},
|
|
30
35
|
deployment: {
|