@trayio/cdk-cli 5.11.0 → 5.13.0-unstable

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/README.md CHANGED
@@ -19,7 +19,7 @@ $ npm install -g @trayio/cdk-cli
19
19
  $ tray-cdk COMMAND
20
20
  running command...
21
21
  $ tray-cdk (--version|-v)
22
- @trayio/cdk-cli/5.11.0 linux-x64 node-v18.20.8
22
+ @trayio/cdk-cli/5.13.0-unstable linux-x64 node-v18.20.8
23
23
  $ tray-cdk --help [COMMAND]
24
24
  USAGE
25
25
  $ tray-cdk COMMAND
@@ -32,6 +32,7 @@ USAGE
32
32
  <!-- commands -->
33
33
  * [`tray-cdk .`](#tray-cdk-)
34
34
  * [`tray-cdk autocomplete [SHELL]`](#tray-cdk-autocomplete-shell)
35
+ * [`tray-cdk connector add-dynamic-output-schema OPERATIONNAME`](#tray-cdk-connector-add-dynamic-output-schema-operationname)
35
36
  * [`tray-cdk connector add-operation [OPERATIONNAME] [OPERATIONTYPE]`](#tray-cdk-connector-add-operation-operationname-operationtype)
36
37
  * [`tray-cdk connector build`](#tray-cdk-connector-build)
37
38
  * [`tray-cdk connector import [OPENAPISPEC] [CONNECTORNAME]`](#tray-cdk-connector-import-openapispec-connectorname)
@@ -96,6 +97,26 @@ EXAMPLES
96
97
 
97
98
  _See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v3.0.5/src/commands/autocomplete/index.ts)_
98
99
 
100
+ ## `tray-cdk connector add-dynamic-output-schema OPERATIONNAME`
101
+
102
+ Add a dynamic output schema operation for an existing operation
103
+
104
+ ```
105
+ USAGE
106
+ $ tray-cdk connector add-dynamic-output-schema OPERATIONNAME
107
+
108
+ ARGUMENTS
109
+ OPERATIONNAME Name of the parent operation to add dynamic output schema for
110
+
111
+ DESCRIPTION
112
+ Add a dynamic output schema operation for an existing operation
113
+
114
+ EXAMPLES
115
+ $ tray-cdk connector add-dynamic-output-schema get_posts
116
+
117
+ $ tray-cdk connector add-dynamic-output-schema fetch_user_data
118
+ ```
119
+
99
120
  ## `tray-cdk connector add-operation [OPERATIONNAME] [OPERATIONTYPE]`
100
121
 
101
122
  Add an operation to connector project
@@ -0,0 +1,11 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class AddDynamicOutputSchema extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ operationName: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ run(): Promise<void>;
9
+ private findSrcDirectory;
10
+ }
11
+ //# sourceMappingURL=add-dynamic-output-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-dynamic-output-schema.d.ts","sourceRoot":"","sources":["../../../src/commands/connector/add-dynamic-output-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAQ,MAAM,aAAa,CAAC;AAS5C,MAAM,CAAC,OAAO,OAAO,sBAAuB,SAAQ,OAAO;IAC1D,MAAM,CAAC,WAAW,SACiD;IAEnE,MAAM,CAAC,QAAQ,WAGb;IAEF,MAAM,CAAC,IAAI;;MAOT;IAEI,GAAG;IA+PT,OAAO,CAAC,gBAAgB;CAOxB"}
@@ -0,0 +1,243 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ const core_1 = require("@oclif/core");
27
+ const fse = __importStar(require("fs-extra"));
28
+ const path = __importStar(require("path"));
29
+ const StringExtensions_1 = require("@trayio/commons/string/StringExtensions");
30
+ const colorizeString_1 = require("@trayio/cdk-cli-commons/utils/colorizeString");
31
+ class AddDynamicOutputSchema extends core_1.Command {
32
+ static description = 'Add a dynamic output schema operation for an existing operation';
33
+ static examples = [
34
+ '<%= config.bin %> <%= command.id %> get_posts',
35
+ '<%= config.bin %> <%= command.id %> fetch_user_data',
36
+ ];
37
+ static args = {
38
+ operationName: core_1.Args.string({
39
+ name: 'operationName',
40
+ required: true,
41
+ description: 'Name of the parent operation to add dynamic output schema for',
42
+ }),
43
+ };
44
+ async run() {
45
+ const { args } = await this.parse(AddDynamicOutputSchema);
46
+ const { operationName } = args;
47
+ const currentDirectory = process.cwd();
48
+ const srcDir = this.findSrcDirectory(currentDirectory);
49
+ // Validate parent operation exists
50
+ const parentOperationPath = path.join(srcDir, operationName);
51
+ if (!fse.existsSync(parentOperationPath)) {
52
+ this.error((0, colorizeString_1.error)(`Operation '${operationName}' not found in src/ directory.\nMake sure you're in the connector root or src/ directory.`));
53
+ }
54
+ const parentOperationJsonPath = path.join(parentOperationPath, 'operation.json');
55
+ if (!fse.existsSync(parentOperationJsonPath)) {
56
+ this.error((0, colorizeString_1.error)(`Operation '${operationName}' exists but missing operation.json file.`));
57
+ }
58
+ this.log(`Checking for operation '${operationName}'... ✓`);
59
+ // Check if dynamic output schema operation already exists
60
+ const outputSchemaOpName = `${operationName}_output_schema`;
61
+ const outputSchemaOpPath = path.join(srcDir, outputSchemaOpName);
62
+ if (fse.existsSync(outputSchemaOpPath)) {
63
+ this.error((0, colorizeString_1.error)(`Dynamic output schema operation '${outputSchemaOpName}' already exists!`));
64
+ }
65
+ // Read parent operation.json
66
+ const parentOperationJson = await fse.readJson(parentOperationJsonPath);
67
+ // Get connector name to construct auth file name (matches add-operation pattern)
68
+ const connectorJsonPath = path.join(path.dirname(srcDir), 'connector.json');
69
+ let connectorNamePascalCase = 'MyConnector';
70
+ let authFileName = 'Authentication';
71
+ let authType = 'NoAuth';
72
+ try {
73
+ const connectorJson = await fse.readJson(connectorJsonPath);
74
+ connectorNamePascalCase = StringExtensions_1.StringExtensions.pascalCase(connectorJson.name);
75
+ // Check for {ConnectorName}Auth.ts pattern (standard pattern)
76
+ const standardAuthFile = `${connectorNamePascalCase}Auth.ts`;
77
+ const standardAuthPath = path.join(srcDir, standardAuthFile);
78
+ if (fse.existsSync(standardAuthPath)) {
79
+ authFileName = standardAuthFile.replace('.ts', '');
80
+ authType = `${connectorNamePascalCase}Auth`;
81
+ }
82
+ else {
83
+ // Fall back to other common patterns
84
+ const authFiles = ['Authentication.ts', 'Auth.ts'];
85
+ const foundAuthFile = authFiles.find((file) => {
86
+ const authPath = path.join(srcDir, file);
87
+ return fse.existsSync(authPath);
88
+ });
89
+ if (foundAuthFile) {
90
+ authFileName = foundAuthFile.replace('.ts', '');
91
+ // Try to read and extract auth type name
92
+ const authContent = await fse.readFile(path.join(srcDir, foundAuthFile), 'utf-8');
93
+ const typeMatch = authContent.match(/export\s+type\s+(\w+)/);
94
+ if (typeMatch) {
95
+ [, authType] = typeMatch;
96
+ }
97
+ }
98
+ }
99
+ }
100
+ catch (e) {
101
+ // If we can't read connector.json, use defaults
102
+ this.warn('Could not read connector.json, using default auth type. Auth import may need manual adjustment.');
103
+ }
104
+ this.log(`Creating dynamic output schema operation '${outputSchemaOpName}'...`);
105
+ // Create operation folder
106
+ await fse.ensureDir(outputSchemaOpPath);
107
+ this.log(' ✓ Created operation folder');
108
+ // Generate names
109
+ const parentOpNamePascalCase = StringExtensions_1.StringExtensions.pascalCase(operationName);
110
+ const outputSchemaOpNamePascalCase = StringExtensions_1.StringExtensions.pascalCase(outputSchemaOpName);
111
+ const parentOpNameCamelCase = operationName
112
+ .split('_')
113
+ .map((word, i) => i === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1))
114
+ .join('');
115
+ const outputSchemaOpNameCamelCase = outputSchemaOpName
116
+ .split('_')
117
+ .map((word, i) => i === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1))
118
+ .join('');
119
+ // 1. Generate operation.json
120
+ const operationJson = {
121
+ name: outputSchemaOpName,
122
+ title: `${StringExtensions_1.StringExtensions.titleCase(operationName)} Output Schema`,
123
+ description: `Dynamic output schema generator for ${operationName} (private operation)`,
124
+ isPrivate: true,
125
+ };
126
+ await fse.writeJson(path.join(outputSchemaOpPath, 'operation.json'), operationJson, { spaces: 2 });
127
+ this.log(' ✓ Generated operation.json');
128
+ // 2. Generate input.ts (re-export from parent)
129
+ const inputTsContent = `export type { ${parentOpNamePascalCase}Input as ${outputSchemaOpNamePascalCase}Input } from '../${operationName}/input';
130
+ `;
131
+ await fse.writeFile(path.join(outputSchemaOpPath, 'input.ts'), inputTsContent);
132
+ this.log(' ✓ Generated input.ts');
133
+ // 3. Generate output.ts
134
+ const outputTsContent = `import { DynamicOutput } from '@trayio/cdk-dsl/connector/operation/OperationHandler';
135
+
136
+ export type ${outputSchemaOpNamePascalCase}Output = DynamicOutput;
137
+ `;
138
+ await fse.writeFile(path.join(outputSchemaOpPath, 'output.ts'), outputTsContent);
139
+ this.log(' ✓ Generated output.ts');
140
+ // 4. Generate handler.ts from template
141
+ const handlerTsContent = `import { OperationHandlerSetup } from '@trayio/cdk-dsl/connector/operation/OperationHandlerSetup';
142
+ import {
143
+ OperationHandlerResult,
144
+ DynamicOutput,
145
+ } from '@trayio/cdk-dsl/connector/operation/OperationHandler';
146
+ import { JsonSchemaIntrospector } from '@trayio/commons/schema/JsonSchemaIntrospector';
147
+ import { ${parentOpNamePascalCase}Input } from '../${operationName}/input';
148
+ import { ${authType} } from '../${authFileName}';
149
+ import { ${parentOpNameCamelCase}Handler } from '../${operationName}/handler';
150
+
151
+ /**
152
+ * Dynamic output schema handler for ${operationName}
153
+ *
154
+ * This handler generates a JSON Schema by introspecting actual API responses.
155
+ * Customize the data-fetching logic below for your specific use case.
156
+ */
157
+ export const ${outputSchemaOpNameCamelCase}Handler =
158
+ OperationHandlerSetup.configureDynamicOutputHandler<
159
+ ${authType},
160
+ ${parentOpNamePascalCase}Input
161
+ >((handler) =>
162
+ handler.usingComposite(async (ctx, input, invoke) => {
163
+ try {
164
+ // TODO: Customize this logic for your use case
165
+
166
+ // Option 1: Invoke the main operation (ONLY for read-only GET operations!)
167
+ const result = await invoke(${parentOpNameCamelCase}Handler)(input);
168
+
169
+ // Option 2: Call a metadata/schema endpoint instead
170
+ // const result = await invoke(getSchemaMetadataHandler)(input);
171
+
172
+ // Option 3: Compute schema without API calls
173
+ // const schema = computeSchemaBasedOnInput(input);
174
+ // return OperationHandlerResult.success<DynamicOutput>({ output_schema: schema });
175
+
176
+ if (result.isFailure) {
177
+ // Return generic fallback schema on error
178
+ return OperationHandlerResult.success<DynamicOutput>({
179
+ output_schema: {
180
+ type: 'object',
181
+ additionalProperties: true,
182
+ description: 'Generic schema - operation failed',
183
+ },
184
+ });
185
+ }
186
+
187
+ // Use the standard JsonSchemaIntrospector utility to convert response to JSON Schema
188
+ const schema = JsonSchemaIntrospector.introspectToJsonSchema(
189
+ result.value,
190
+ {
191
+ maxDepth: 10,
192
+ includeExamples: false,
193
+ strictRequired: true,
194
+ }
195
+ );
196
+
197
+ return OperationHandlerResult.success<DynamicOutput>({
198
+ output_schema: schema,
199
+ });
200
+ } catch (error) {
201
+ // Fallback on any error
202
+ return OperationHandlerResult.success<DynamicOutput>({
203
+ output_schema: {
204
+ type: 'object',
205
+ additionalProperties: true,
206
+ description: 'Fallback schema due to error',
207
+ },
208
+ });
209
+ }
210
+ })
211
+ );
212
+ `;
213
+ await fse.writeFile(path.join(outputSchemaOpPath, 'handler.ts'), handlerTsContent);
214
+ this.log(' ✓ Generated handler.ts (with JsonSchemaIntrospector template)');
215
+ // 5. Update parent operation.json with isDynamicOutput: true
216
+ const updatedParentJson = {
217
+ ...parentOperationJson,
218
+ isDynamicOutput: true,
219
+ };
220
+ await fse.writeJson(parentOperationJsonPath, updatedParentJson, {
221
+ spaces: 2,
222
+ });
223
+ this.log(` ✓ Updated parent operation.json with isDynamicOutput: true`);
224
+ // Success message with next steps
225
+ this.log('');
226
+ this.log((0, colorizeString_1.success)(`Success! Created dynamic output schema operation: ${outputSchemaOpName}`));
227
+ this.log('');
228
+ this.log('Next steps:');
229
+ this.log(` 1. Edit src/${outputSchemaOpName}/handler.ts`);
230
+ this.log(' 2. Customize the data fetching logic for your use case');
231
+ this.log(' 3. Run "tray-cdk connector build" to build the connector');
232
+ this.log('');
233
+ this.log('Note: Dynamic output is only safe for read-only GET operations!');
234
+ }
235
+ findSrcDirectory(currentDirectory) {
236
+ const { base } = path.parse(currentDirectory);
237
+ if (base === 'src') {
238
+ return currentDirectory;
239
+ }
240
+ return path.join(currentDirectory, 'src');
241
+ }
242
+ }
243
+ exports.default = AddDynamicOutputSchema;
@@ -17,6 +17,37 @@
17
17
  "index.js"
18
18
  ]
19
19
  },
20
+ "connector:add-dynamic-output-schema": {
21
+ "aliases": [],
22
+ "args": {
23
+ "operationName": {
24
+ "description": "Name of the parent operation to add dynamic output schema for",
25
+ "name": "operationName",
26
+ "required": true
27
+ }
28
+ },
29
+ "description": "Add a dynamic output schema operation for an existing operation",
30
+ "examples": [
31
+ "<%= config.bin %> <%= command.id %> get_posts",
32
+ "<%= config.bin %> <%= command.id %> fetch_user_data"
33
+ ],
34
+ "flags": {},
35
+ "hasDynamicHelp": false,
36
+ "hiddenAliases": [],
37
+ "id": "connector:add-dynamic-output-schema",
38
+ "pluginAlias": "@trayio/cdk-cli",
39
+ "pluginName": "@trayio/cdk-cli",
40
+ "pluginType": "core",
41
+ "strict": true,
42
+ "enableJsonFlag": false,
43
+ "isESM": false,
44
+ "relativePath": [
45
+ "dist",
46
+ "commands",
47
+ "connector",
48
+ "add-dynamic-output-schema.js"
49
+ ]
50
+ },
20
51
  "connector:add-operation": {
21
52
  "aliases": [],
22
53
  "args": {
@@ -684,5 +715,5 @@
684
715
  ]
685
716
  }
686
717
  },
687
- "version": "5.11.0"
718
+ "version": "5.13.0-unstable"
688
719
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trayio/cdk-cli",
3
- "version": "5.11.0",
3
+ "version": "5.13.0-unstable",
4
4
  "description": "A CLI for connector development",
5
5
  "exports": {
6
6
  "./*": "./dist/*.js"
@@ -22,13 +22,13 @@
22
22
  "@oclif/plugin-version": "2.0.11",
23
23
  "@oclif/plugin-warn-if-update-available": "^3.1.4",
24
24
  "@oclif/test": "3.1.12",
25
- "@trayio/axios": "5.11.0",
26
- "@trayio/cdk-build": "5.11.0",
27
- "@trayio/cdk-cli-commons": "5.11.0",
28
- "@trayio/commons": "5.11.0",
29
- "@trayio/generator": "5.11.0",
30
- "@trayio/tray-client": "5.11.0",
31
- "@trayio/tray-openapi": "5.11.0",
25
+ "@trayio/axios": "5.13.0-unstable",
26
+ "@trayio/cdk-build": "5.13.0-unstable",
27
+ "@trayio/cdk-cli-commons": "5.13.0-unstable",
28
+ "@trayio/commons": "5.13.0-unstable",
29
+ "@trayio/generator": "5.13.0-unstable",
30
+ "@trayio/tray-client": "5.13.0-unstable",
31
+ "@trayio/tray-openapi": "5.13.0-unstable",
32
32
  "chalk": "4.1.2",
33
33
  "dotenv": "^16.0.0",
34
34
  "inquirer": "8.2.6"
@@ -92,5 +92,6 @@
92
92
  "devDependencies": {
93
93
  "@types/inquirer": "8.2.6",
94
94
  "oclif": "*"
95
- }
95
+ },
96
+ "stableVersion": "0.0.0"
96
97
  }