@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 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
- if (existingEnv) {
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);
@@ -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
- if (val.length > 50) {
48
- throw new Error('Application key must be at most 50 characters');
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 (!/^[a-z0-9-]+$/.test(val)) {
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
- if (val.length > 100) {
60
- throw new Error('Display name must be at most 100 characters');
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('Configuration type must be one of: webapp, api, service, functionapp');
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('Registry mode must be one of: acr, external, public');
83
+ throw new Error(`Registry mode must be one of: ${validRegistryModes.join(', ')}`);
74
84
  }
75
- if (val.port !== undefined) {
76
- if (!Number.isInteger(val.port) || val.port < 1 || val.port > 65535) {
77
- throw new Error('Port must be an integer between 1 and 65535');
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: appName,
26
- displayName: displayName,
27
- description: `${appName.replace(/-/g, ' ')} external system`,
30
+ key: systemKey,
31
+ displayName: systemDisplayName,
32
+ description: systemDescription,
28
33
  type: 'external'
29
34
  },
30
35
  deployment: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aifabrix/builder",
3
- "version": "2.10.0",
3
+ "version": "2.10.1",
4
4
  "description": "AI Fabrix Local Fabric & Deployment SDK",
5
5
  "main": "lib/index.js",
6
6
  "bin": {