@aifabrix/builder 2.7.0 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,50 @@
1
1
  {
2
2
  "$schema":"https://json-schema.org/draft/2020-12/schema",
3
- "$id":"https://aifabrix.ai/schemas/external-datasource.schema.json",
3
+ "$id":"https://raw.githubusercontent.com/esystemsdev/aifabrix-builder/refs/heads/main/lib/schema/external-datasource.schema.json",
4
4
  "title":"External Data Source",
5
5
  "description":"Configuration for AI Fabrix ExternalDataSource entities. Includes metadata schema, ABAC access fields, transformation mappings, OpenAPI/MCP exposure, and sync behavior.",
6
+ "metadata":{
7
+ "key":"external-datasource-schema",
8
+ "name":"External Data Source Configuration Schema",
9
+ "description":"JSON schema for validating ExternalDataSource configuration files",
10
+ "version":"1.0.0",
11
+ "type":"schema",
12
+ "category":"integration",
13
+ "author":"AI Fabrix Team",
14
+ "createdAt":"2024-01-01T00:00:00Z",
15
+ "updatedAt":"2024-01-01T00:00:00Z",
16
+ "compatibility":{
17
+ "minVersion":"1.0.0",
18
+ "maxVersion":"2.0.0",
19
+ "deprecated":false
20
+ },
21
+ "tags":[
22
+ "schema",
23
+ "external-datasource",
24
+ "dataplane",
25
+ "integration",
26
+ "validation"
27
+ ],
28
+ "dependencies":[
29
+ "external-system.schema.json"
30
+ ],
31
+ "changelog":[
32
+ {
33
+ "version":"1.0.0",
34
+ "date":"2024-01-01T00:00:00Z",
35
+ "changes":[
36
+ "Initial schema for External Data Sources",
37
+ "Added fieldMappings DSL with transformation expressions",
38
+ "Added metadataSchema validation",
39
+ "Added exposed fields configuration for MCP/OpenAPI",
40
+ "Added ABAC accessFields validation",
41
+ "Added OpenAPI and MCP operation configurations",
42
+ "Added sync configuration and validation rules"
43
+ ],
44
+ "breaking":false
45
+ }
46
+ ]
47
+ },
6
48
  "type":"object",
7
49
  "required":[
8
50
  "key",
@@ -38,6 +80,12 @@
38
80
  "type":"string",
39
81
  "pattern":"^[a-z0-9-]+$"
40
82
  },
83
+ "resourceType":{
84
+ "type":"string",
85
+ "enum":["customer","contact","person","document","deal"],
86
+ "default":"document",
87
+ "description":"Resource type for the datasource. Maps to database ResourceType enum."
88
+ },
41
89
  "version":{
42
90
  "type":"string",
43
91
  "pattern":"^[0-9]+\\.[0-9]+\\.[0-9]+$",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
- "$id": "https://aifabrix.ai/schemas/external-system.schema.json",
3
+ "$id": "https://raw.githubusercontent.com/esystemsdev/aifabrix-builder/refs/heads/main/lib/schema/external-system.schema.json",
4
4
  "title": "AI Fabrix External System Configuration Schema",
5
5
  "description": "Schema for configuring an external system connected to the AI Fabrix Dataplane. This defines authentication, OpenAPI/MCP bindings, field mappings defaults, metadata handling and portal inputs.",
6
6
 
@@ -101,9 +101,9 @@
101
101
  "authentication": {
102
102
  "type": "object",
103
103
  "description": "Authentication configuration for the external system.",
104
- "required": ["mode"],
104
+ "required": ["type"],
105
105
  "properties": {
106
- "mode": {
106
+ "type": {
107
107
  "type": "string",
108
108
  "enum": ["oauth2", "apikey", "basic", "aad", "none"],
109
109
  "description": "Authentication method used for API access."
@@ -111,7 +111,7 @@
111
111
 
112
112
  "oauth2": {
113
113
  "type": "object",
114
- "description": "OAuth2 configuration used when mode == 'oauth2'. All secrets are stored in Key Vault.",
114
+ "description": "OAuth2 configuration used when type == 'oauth2'. All secrets are stored in Key Vault.",
115
115
  "properties": {
116
116
  "tokenUrl": {
117
117
  "type": "string",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
- "$id": "https://docs.aifabrix.ai/schemas/Configuration-Schema-Infra.json",
3
+ "$id": "https://raw.githubusercontent.com/esystemsdev/aifabrix-builder/refs/heads/main/lib/schema/infrastructure-schema.json",
4
4
  "title": "AI Fabrix Infrastructure Configuration Schema",
5
5
  "description": "Infrastructure-level configuration schema for AI Fabrix deployment",
6
6
  "metadata": {
package/lib/templates.js CHANGED
@@ -16,6 +16,37 @@ const yaml = require('js-yaml');
16
16
  */
17
17
  function generateVariablesYaml(appName, config) {
18
18
  const displayName = appName.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
19
+ const appType = config.type || 'webapp';
20
+
21
+ // For external type, create minimal variables.yaml
22
+ if (appType === 'external') {
23
+ const variables = {
24
+ app: {
25
+ key: appName,
26
+ displayName: displayName,
27
+ description: `${appName.replace(/-/g, ' ')} external system`,
28
+ type: 'external'
29
+ },
30
+ deployment: {
31
+ controllerUrl: '',
32
+ environment: 'dev'
33
+ },
34
+ externalIntegration: {
35
+ schemaBasePath: './schemas',
36
+ systems: [],
37
+ dataSources: [],
38
+ autopublish: true,
39
+ version: '1.0.0'
40
+ }
41
+ };
42
+
43
+ return yaml.dump(variables, {
44
+ indent: 2,
45
+ lineWidth: 120,
46
+ noRefs: true,
47
+ sortKeys: false
48
+ });
49
+ }
19
50
 
20
51
  // Parse image name to separate name and tag
21
52
  let imageName = appName;
@@ -32,7 +63,7 @@ function generateVariablesYaml(appName, config) {
32
63
  key: appName,
33
64
  displayName: displayName,
34
65
  description: `${appName.replace(/-/g, ' ')} application`,
35
- type: 'webapp'
66
+ type: appType
36
67
  },
37
68
  image: {
38
69
  name: imageName,
@@ -61,20 +61,28 @@ function parseDeviceCodeResponse(response) {
61
61
  * @function initiateDeviceCodeFlow
62
62
  * @param {string} controllerUrl - Base URL of the controller
63
63
  * @param {string} environment - Environment key (e.g., 'miso', 'dev', 'tst', 'pro')
64
+ * @param {string} [scope] - OAuth2 scope string (default: 'openid profile email')
64
65
  * @returns {Promise<Object>} Device code response with device_code, user_code, verification_uri, expires_in, interval
65
66
  * @throws {Error} If initiation fails
66
67
  */
67
- async function initiateDeviceCodeFlow(controllerUrl, environment) {
68
+ async function initiateDeviceCodeFlow(controllerUrl, environment, scope) {
68
69
  if (!environment || typeof environment !== 'string') {
69
70
  throw new Error('Environment key is required');
70
71
  }
71
72
 
73
+ // Default scope for backward compatibility
74
+ const defaultScope = 'openid profile email';
75
+ const requestScope = scope || defaultScope;
76
+
72
77
  const url = `${controllerUrl}/api/v1/auth/login?environment=${encodeURIComponent(environment)}`;
73
78
  const response = await getMakeApiCall()(url, {
74
79
  method: 'POST',
75
80
  headers: {
76
81
  'Content-Type': 'application/json'
77
- }
82
+ },
83
+ body: JSON.stringify({
84
+ scope: requestScope
85
+ })
78
86
  });
79
87
 
80
88
  if (!response.success) {
@@ -0,0 +1,68 @@
1
+ /**
2
+ * AI Fabrix Builder Token Encryption Utilities
3
+ *
4
+ * This module provides encryption and decryption functions for authentication tokens
5
+ * using AES-256-GCM algorithm for ISO 27001 compliance.
6
+ * Reuses the same encryption infrastructure as secrets encryption.
7
+ *
8
+ * @fileoverview Token encryption utilities for AI Fabrix Builder
9
+ * @author AI Fabrix Team
10
+ * @version 2.0.0
11
+ */
12
+
13
+ const { encryptSecret, decryptSecret, isEncrypted } = require('./secrets-encryption');
14
+
15
+ /**
16
+ * Encrypts a token value using AES-256-GCM
17
+ * Returns encrypted value in format: secure://<iv>:<ciphertext>:<authTag>
18
+ * All components are base64 encoded
19
+ *
20
+ * @function encryptToken
21
+ * @param {string} value - Plaintext token value to encrypt
22
+ * @param {string} key - Encryption key (hex or base64, 32 bytes)
23
+ * @returns {string} Encrypted value with secure:// prefix
24
+ * @throws {Error} If encryption fails or key is invalid
25
+ *
26
+ * @example
27
+ * const encrypted = encryptToken('my-token', 'a1b2c3...');
28
+ * // Returns: 'secure://<iv>:<ciphertext>:<authTag>'
29
+ */
30
+ function encryptToken(value, key) {
31
+ return encryptSecret(value, key);
32
+ }
33
+
34
+ /**
35
+ * Decrypts an encrypted token value
36
+ * Handles secure:// prefixed values and extracts IV, ciphertext, and auth tag
37
+ *
38
+ * @function decryptToken
39
+ * @param {string} encryptedValue - Encrypted value with secure:// prefix
40
+ * @param {string} key - Encryption key (hex or base64, 32 bytes)
41
+ * @returns {string} Decrypted plaintext value
42
+ * @throws {Error} If decryption fails, key is invalid, or format is incorrect
43
+ *
44
+ * @example
45
+ * const decrypted = decryptToken('secure://<iv>:<ciphertext>:<authTag>', 'a1b2c3...');
46
+ * // Returns: 'my-token'
47
+ */
48
+ function decryptToken(encryptedValue, key) {
49
+ return decryptSecret(encryptedValue, key);
50
+ }
51
+
52
+ /**
53
+ * Checks if a token value is encrypted (starts with secure://)
54
+ *
55
+ * @function isTokenEncrypted
56
+ * @param {string} value - Value to check
57
+ * @returns {boolean} True if value is encrypted
58
+ */
59
+ function isTokenEncrypted(value) {
60
+ return isEncrypted(value);
61
+ }
62
+
63
+ module.exports = {
64
+ encryptToken,
65
+ decryptToken,
66
+ isTokenEncrypted
67
+ };
68
+
package/lib/validator.js CHANGED
@@ -14,6 +14,8 @@ const path = require('path');
14
14
  const yaml = require('js-yaml');
15
15
  const Ajv = require('ajv');
16
16
  const applicationSchema = require('./schema/application-schema.json');
17
+ const externalSystemSchema = require('./schema/external-system.schema.json');
18
+ const externalDataSourceSchema = require('./schema/external-datasource.schema.json');
17
19
  const { transformVariablesForValidation } = require('./utils/variable-transformer');
18
20
  const { checkEnvironment } = require('./utils/environment-checker');
19
21
  const { formatValidationErrors } = require('./utils/error-formatter');
@@ -56,13 +58,45 @@ async function validateVariables(appName) {
56
58
  const transformed = transformVariablesForValidation(variables, appName);
57
59
 
58
60
  const ajv = new Ajv({ allErrors: true, strict: false });
61
+ // Register external schemas with their $id (GitHub raw URLs)
62
+ // Create copies to avoid modifying the original schemas
63
+ const externalSystemSchemaCopy = { ...externalSystemSchema };
64
+ const externalDataSourceSchemaCopy = { ...externalDataSourceSchema };
65
+ // Remove $schema for draft-2020-12 to avoid AJV issues
66
+ if (externalDataSourceSchemaCopy.$schema && externalDataSourceSchemaCopy.$schema.includes('2020-12')) {
67
+ delete externalDataSourceSchemaCopy.$schema;
68
+ }
69
+ ajv.addSchema(externalSystemSchemaCopy, externalSystemSchema.$id);
70
+ ajv.addSchema(externalDataSourceSchemaCopy, externalDataSourceSchema.$id);
59
71
  const validate = ajv.compile(applicationSchema);
60
72
  const valid = validate(transformed);
61
73
 
74
+ // Additional explicit validation for external type
75
+ const errors = valid ? [] : formatValidationErrors(validate.errors);
76
+ const warnings = [];
77
+
78
+ // If type is external, perform additional checks
79
+ if (variables.app && variables.app.type === 'external') {
80
+ // Check for externalIntegration block
81
+ if (!variables.externalIntegration) {
82
+ errors.push('externalIntegration block is required when app.type is "external"');
83
+ } else {
84
+ // Validate externalIntegration structure
85
+ if (!variables.externalIntegration.schemaBasePath) {
86
+ errors.push('externalIntegration.schemaBasePath is required');
87
+ }
88
+ if (!variables.externalIntegration.systems || !Array.isArray(variables.externalIntegration.systems) || variables.externalIntegration.systems.length === 0) {
89
+ errors.push('externalIntegration.systems must be a non-empty array');
90
+ }
91
+ // Note: dataSources can be empty, so we don't validate that here
92
+ // File existence is validated during build/deploy, not during schema validation
93
+ }
94
+ }
95
+
62
96
  return {
63
- valid,
64
- errors: valid ? [] : formatValidationErrors(validate.errors),
65
- warnings: []
97
+ valid: valid && errors.length === 0,
98
+ errors,
99
+ warnings
66
100
  };
67
101
  }
68
102
 
@@ -239,6 +273,16 @@ function validateDeploymentJson(deployment) {
239
273
  }
240
274
 
241
275
  const ajv = new Ajv({ allErrors: true, strict: false });
276
+ // Register external schemas with their $id (GitHub raw URLs)
277
+ // Create copies to avoid modifying the original schemas
278
+ const externalSystemSchemaCopy = { ...externalSystemSchema };
279
+ const externalDataSourceSchemaCopy = { ...externalDataSourceSchema };
280
+ // Remove $schema for draft-2020-12 to avoid AJV issues
281
+ if (externalDataSourceSchemaCopy.$schema && externalDataSourceSchemaCopy.$schema.includes('2020-12')) {
282
+ delete externalDataSourceSchemaCopy.$schema;
283
+ }
284
+ ajv.addSchema(externalSystemSchemaCopy, externalSystemSchema.$id);
285
+ ajv.addSchema(externalDataSourceSchemaCopy, externalDataSourceSchema.$id);
242
286
  const validate = ajv.compile(applicationSchema);
243
287
  const valid = validate(deployment);
244
288
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aifabrix/builder",
3
- "version": "2.7.0",
3
+ "version": "2.8.0",
4
4
  "description": "AI Fabrix Local Fabric & Deployment SDK",
5
5
  "main": "lib/index.js",
6
6
  "bin": {
package/tatus ADDED
@@ -0,0 +1,181 @@
1
+
2
+ SSUUMMMMAARRYY OOFF LLEESSSS CCOOMMMMAANNDDSS
3
+
4
+ Commands marked with * may be preceded by a number, _N.
5
+ Notes in parentheses indicate the behavior if _N is given.
6
+ A key preceded by a caret indicates the Ctrl key; thus ^K is ctrl-K.
7
+
8
+ h H Display this help.
9
+ q :q Q :Q ZZ Exit.
10
+ ---------------------------------------------------------------------------
11
+
12
+ MMOOVVIINNGG
13
+
14
+ e ^E j ^N CR * Forward one line (or _N lines).
15
+ y ^Y k ^K ^P * Backward one line (or _N lines).
16
+ f ^F ^V SPACE * Forward one window (or _N lines).
17
+ b ^B ESC-v * Backward one window (or _N lines).
18
+ z * Forward one window (and set window to _N).
19
+ w * Backward one window (and set window to _N).
20
+ ESC-SPACE * Forward one window, but don't stop at end-of-file.
21
+ d ^D * Forward one half-window (and set half-window to _N).
22
+ u ^U * Backward one half-window (and set half-window to _N).
23
+ ESC-) RightArrow * Right one half screen width (or _N positions).
24
+ ESC-( LeftArrow * Left one half screen width (or _N positions).
25
+ ESC-} ^RightArrow Right to last column displayed.
26
+ ESC-{ ^LeftArrow Left to first column.
27
+ F Forward forever; like "tail -f".
28
+ ESC-F Like F but stop when search pattern is found.
29
+ r ^R ^L Repaint screen.
30
+ R Repaint screen, discarding buffered input.
31
+ ---------------------------------------------------
32
+ Default "window" is the screen height.
33
+ Default "half-window" is half of the screen height.
34
+ ---------------------------------------------------------------------------
35
+
36
+ SSEEAARRCCHHIINNGG
37
+
38
+ /_p_a_t_t_e_r_n * Search forward for (_N-th) matching line.
39
+ ?_p_a_t_t_e_r_n * Search backward for (_N-th) matching line.
40
+ n * Repeat previous search (for _N-th occurrence).
41
+ N * Repeat previous search in reverse direction.
42
+ ESC-n * Repeat previous search, spanning files.
43
+ ESC-N * Repeat previous search, reverse dir. & spanning files.
44
+ ^O^N ^On * Search forward for (_N-th) OSC8 hyperlink.
45
+ ^O^P ^Op * Search backward for (_N-th) OSC8 hyperlink.
46
+ ^O^L ^Ol Jump to the currently selected OSC8 hyperlink.
47
+ ESC-u Undo (toggle) search highlighting.
48
+ ESC-U Clear search highlighting.
49
+ &_p_a_t_t_e_r_n * Display only matching lines.
50
+ ---------------------------------------------------
51
+ A search pattern may begin with one or more of:
52
+ ^N or ! Search for NON-matching lines.
53
+ ^E or * Search multiple files (pass thru END OF FILE).
54
+ ^F or @ Start search at FIRST file (for /) or last file (for ?).
55
+ ^K Highlight matches, but don't move (KEEP position).
56
+ ^R Don't use REGULAR EXPRESSIONS.
57
+ ^S _n Search for match in _n-th parenthesized subpattern.
58
+ ^W WRAP search if no match found.
59
+ ^L Enter next character literally into pattern.
60
+ ---------------------------------------------------------------------------
61
+
62
+ JJUUMMPPIINNGG
63
+
64
+ g < ESC-< * Go to first line in file (or line _N).
65
+ G > ESC-> * Go to last line in file (or line _N).
66
+ p % * Go to beginning of file (or _N percent into file).
67
+ t * Go to the (_N-th) next tag.
68
+ T * Go to the (_N-th) previous tag.
69
+ { ( [ * Find close bracket } ) ].
70
+ } ) ] * Find open bracket { ( [.
71
+ ESC-^F _<_c_1_> _<_c_2_> * Find close bracket _<_c_2_>.
72
+ ESC-^B _<_c_1_> _<_c_2_> * Find open bracket _<_c_1_>.
73
+ ---------------------------------------------------
74
+ Each "find close bracket" command goes forward to the close bracket
75
+ matching the (_N-th) open bracket in the top line.
76
+ Each "find open bracket" command goes backward to the open bracket
77
+ matching the (_N-th) close bracket in the bottom line.
78
+
79
+ m_<_l_e_t_t_e_r_> Mark the current top line with <letter>.
80
+ M_<_l_e_t_t_e_r_> Mark the current bottom line with <letter>.
81
+ '_<_l_e_t_t_e_r_> Go to a previously marked position.
82
+ '' Go to the previous position.
83
+ ^X^X Same as '.
84
+ ESC-m_<_l_e_t_t_e_r_> Clear a mark.
85
+ ---------------------------------------------------
86
+ A mark is any upper-case or lower-case letter.
87
+ Certain marks are predefined:
88
+ ^ means beginning of the file
89
+ $ means end of the file
90
+ ---------------------------------------------------------------------------
91
+
92
+ CCHHAANNGGIINNGG FFIILLEESS
93
+
94
+ :e [_f_i_l_e] Examine a new file.
95
+ ^X^V Same as :e.
96
+ :n * Examine the (_N-th) next file from the command line.
97
+ :p * Examine the (_N-th) previous file from the command line.
98
+ :x * Examine the first (or _N-th) file from the command line.
99
+ ^O^O Open the currently selected OSC8 hyperlink.
100
+ :d Delete the current file from the command line list.
101
+ = ^G :f Print current file name.
102
+ ---------------------------------------------------------------------------
103
+
104
+ MMIISSCCEELLLLAANNEEOOUUSS CCOOMMMMAANNDDSS
105
+
106
+ -_<_f_l_a_g_> Toggle a command line option [see OPTIONS below].
107
+ --_<_n_a_m_e_> Toggle a command line option, by name.
108
+ __<_f_l_a_g_> Display the setting of a command line option.
109
+ ___<_n_a_m_e_> Display the setting of an option, by name.
110
+ +_c_m_d Execute the less cmd each time a new file is examined.
111
+
112
+ !_c_o_m_m_a_n_d Execute the shell command with $SHELL.
113
+ #_c_o_m_m_a_n_d Execute the shell command, expanded like a prompt.
114
+ |XX_c_o_m_m_a_n_d Pipe file between current pos & mark XX to shell command.
115
+ s _f_i_l_e Save input to a file.
116
+ v Edit the current file with $VISUAL or $EDITOR.
117
+ V Print version number of "less".
118
+ ---------------------------------------------------------------------------
119
+
120
+ OOPPTTIIOONNSS
121
+
122
+ Most options may be changed either on the command line,
123
+ or from within less by using the - or -- command.
124
+ Options may be given in one of two forms: either a single
125
+ character preceded by a -, or a name preceded by --.
126
+
127
+ -? ........ --help
128
+ Display help (from command line).
129
+ -a ........ --search-skip-screen
130
+ Search skips current screen.
131
+ -A ........ --SEARCH-SKIP-SCREEN
132
+ Search starts just after target line.
133
+ -b [_N] .... --buffers=[_N]
134
+ Number of buffers.
135
+ -B ........ --auto-buffers
136
+ Don't automatically allocate buffers for pipes.
137
+ -c ........ --clear-screen
138
+ Repaint by clearing rather than scrolling.
139
+ -d ........ --dumb
140
+ Dumb terminal.
141
+ -D xx_c_o_l_o_r . --color=xx_c_o_l_o_r
142
+ Set screen colors.
143
+ -e -E .... --quit-at-eof --QUIT-AT-EOF
144
+ Quit at end of file.
145
+ -f ........ --force
146
+ Force open non-regular files.
147
+ -F ........ --quit-if-one-screen
148
+ Quit if entire file fits on first screen.
149
+ -g ........ --hilite-search
150
+ Highlight only last match for searches.
151
+ -G ........ --HILITE-SEARCH
152
+ Don't highlight any matches for searches.
153
+ -h [_N] .... --max-back-scroll=[_N]
154
+ Backward scroll limit.
155
+ -i ........ --ignore-case
156
+ Ignore case in searches that do not contain uppercase.
157
+ -I ........ --IGNORE-CASE
158
+ Ignore case in all searches.
159
+ -j [_N] .... --jump-target=[_N]
160
+ Screen position of target lines.
161
+ -J ........ --status-column
162
+ Display a status column at left edge of screen.
163
+ -k _f_i_l_e ... --lesskey-file=_f_i_l_e
164
+ Use a compiled lesskey file.
165
+ -K ........ --quit-on-intr
166
+ Exit less in response to ctrl-C.
167
+ -L ........ --no-lessopen
168
+ Ignore the LESSOPEN environment variable.
169
+ -m -M .... --long-prompt --LONG-PROMPT
170
+ Set prompt style.
171
+ -n ......... --line-numbers
172
+ Suppress line numbers in prompts and messages.
173
+ -N ......... --LINE-NUMBERS
174
+ Display line number at start of each line.
175
+ -o [_f_i_l_e] .. --log-file=[_f_i_l_e]
176
+ Copy to log file (standard input only).
177
+ -O [_f_i_l_e] .. --LOG-FILE=[_f_i_l_e]
178
+ Copy to log file (unconditionally overwrite).
179
+ -p _p_a_t_t_e_r_n . --pattern=[_p_a_t_t_e_r_n]
180
+ Start at pattern (from command line).
181
+ -P [_p_r_o_m_p_t] --prompt=[_p_r_o_m_p_t]
@@ -0,0 +1,55 @@
1
+ {
2
+ "key": "{{datasourceKey}}",
3
+ "displayName": "{{datasourceDisplayName}}",
4
+ "description": "{{datasourceDescription}}",
5
+ "systemKey": "{{systemKey}}",
6
+ "entityKey": "{{entityKey}}",
7
+ "resourceType": "{{resourceType}}",
8
+ "enabled": true,
9
+ "version": "1.0.0",
10
+ "metadataSchema": {
11
+ "type": "object",
12
+ "properties": {}
13
+ },
14
+ "fieldMappings": {
15
+ "accessFields": ["id", "name"],
16
+ "fields": {
17
+ "id": {
18
+ "expression": "{{raw.id}}",
19
+ "type": "string",
20
+ "description": "Unique identifier",
21
+ "required": true
22
+ },
23
+ "name": {
24
+ "expression": "{{raw.name}}",
25
+ "type": "string",
26
+ "description": "Display name",
27
+ "required": true
28
+ }
29
+ }
30
+ },
31
+ "exposed": {
32
+ "fields": ["id", "name"],
33
+ "description": "Exposed fields for {{datasourceDisplayName}}"
34
+ }{{#if (eq systemType "openapi")}},
35
+ "openapi": {
36
+ "enabled": true,
37
+ "documentKey": "{{systemKey}}-api",
38
+ "baseUrl": "https://api.example.com",
39
+ "resourcePath": "/{{entityKey}}",
40
+ "operations": {
41
+ "list": {
42
+ "operationId": "list{{entityKey}}",
43
+ "method": "GET",
44
+ "path": "/{{entityKey}}"
45
+ },
46
+ "get": {
47
+ "operationId": "get{{entityKey}}",
48
+ "method": "GET",
49
+ "path": "/{{entityKey}}/{id}"
50
+ }
51
+ },
52
+ "autoRbac": true
53
+ }{{/if}}
54
+ }
55
+
@@ -0,0 +1,37 @@
1
+ {
2
+ "key": "{{systemKey}}",
3
+ "displayName": "{{systemDisplayName}}",
4
+ "description": "{{systemDescription}}",
5
+ "type": "{{systemType}}",
6
+ "enabled": true,
7
+ "environment": {
8
+ "baseUrl": "https://api.example.com"
9
+ },
10
+ "authentication": {
11
+ "mode": "{{authType}}"{{#if (eq authType "oauth2")}},
12
+ "oauth2": {
13
+ "tokenUrl": "https://api.example.com/oauth/token",
14
+ "clientId": "kv://{{systemKey}}-oauth2-client-id",
15
+ "clientSecret": "kv://{{systemKey}}-oauth2-client-secret",
16
+ "scopes": []
17
+ }{{/if}}{{#if (eq authType "apikey")}},
18
+ "apikey": {
19
+ "headerName": "X-API-Key",
20
+ "key": "kv://{{systemKey}}-api-key"
21
+ }{{/if}}{{#if (eq authType "basic")}},
22
+ "basic": {
23
+ "username": "kv://{{systemKey}}-username",
24
+ "password": "kv://{{systemKey}}-password"
25
+ }{{/if}}
26
+ }{{#if (eq systemType "openapi")}},
27
+ "openapi": {
28
+ "documentKey": "{{systemKey}}-api",
29
+ "autoDiscoverEntities": false
30
+ }{{/if}}{{#if (eq systemType "mcp")}},
31
+ "mcp": {
32
+ "serverUrl": "https://mcp.example.com",
33
+ "toolPrefix": "{{systemKey}}"
34
+ }{{/if}},
35
+ "tags": []
36
+ }
37
+