@trayio/cdk-cli 5.13.0 → 5.15.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.
Files changed (28) hide show
  1. package/README.md +46 -19
  2. package/dist/commands/connector/add-dynamic-output-schema.d.ts +16 -0
  3. package/dist/commands/connector/add-dynamic-output-schema.d.ts.map +1 -0
  4. package/dist/commands/connector/add-dynamic-output-schema.js +163 -0
  5. package/dist/commands/connector/add-dynamic-output-schema.unit.test.d.ts +2 -0
  6. package/dist/commands/connector/add-dynamic-output-schema.unit.test.d.ts.map +1 -0
  7. package/dist/commands/connector/add-dynamic-output-schema.unit.test.js +335 -0
  8. package/dist/commands/deployment/create.d.ts +1 -0
  9. package/dist/commands/deployment/create.d.ts.map +1 -1
  10. package/dist/commands/deployment/get.d.ts +1 -0
  11. package/dist/commands/deployment/get.d.ts.map +1 -1
  12. package/dist/commands/namespace/create.d.ts +1 -0
  13. package/dist/commands/namespace/create.d.ts.map +1 -1
  14. package/dist/commands/namespace/get.d.ts +1 -0
  15. package/dist/commands/namespace/get.d.ts.map +1 -1
  16. package/dist/commands/permissions/add.d.ts +1 -0
  17. package/dist/commands/permissions/add.d.ts.map +1 -1
  18. package/dist/commands/permissions/list.d.ts +1 -0
  19. package/dist/commands/permissions/list.d.ts.map +1 -1
  20. package/dist/lib/dynamic-output/auth-detector.d.ts +21 -0
  21. package/dist/lib/dynamic-output/auth-detector.d.ts.map +1 -0
  22. package/dist/lib/dynamic-output/auth-detector.js +85 -0
  23. package/dist/lib/dynamic-output/index.d.ts +2 -0
  24. package/dist/lib/dynamic-output/index.d.ts.map +1 -0
  25. package/dist/lib/dynamic-output/index.js +5 -0
  26. package/dist/templates/dynamic-output-schema-template.zip +0 -0
  27. package/oclif.manifest.json +68 -1
  28. package/package.json +8 -8
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.13.0 linux-x64 node-v18.20.8
22
+ @trayio/cdk-cli/5.15.0 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
@@ -222,12 +243,13 @@ Creates a new deployment for a connector project
222
243
 
223
244
  ```
224
245
  USAGE
225
- $ tray-cdk deployment create [--us] [--eu] [--ap]
246
+ $ tray-cdk deployment create [--us] [--eu] [--ap] [--ap2]
226
247
 
227
248
  FLAGS
228
- --ap Use the Tray APAC region
229
- --eu Use the Tray EU region
230
- --us Use the Tray US region
249
+ --ap Use the Tray APAC region
250
+ --ap2 Use the Tray APAC 2 region
251
+ --eu Use the Tray EU region
252
+ --us Use the Tray US region
231
253
 
232
254
  DESCRIPTION
233
255
  Creates a new deployment for a connector project
@@ -239,7 +261,7 @@ Retrieves the status of a connector deployment
239
261
 
240
262
  ```
241
263
  USAGE
242
- $ tray-cdk deployment get [CONNECTORNAME] [CONNECTORVERSION] [UUID] [-t] [--us] [--eu] [--ap]
264
+ $ tray-cdk deployment get [CONNECTORNAME] [CONNECTORVERSION] [UUID] [-t] [--us] [--eu] [--ap] [--ap2]
243
265
 
244
266
  ARGUMENTS
245
267
  CONNECTORNAME The name of the connector
@@ -249,6 +271,7 @@ ARGUMENTS
249
271
  FLAGS
250
272
  -t, --tail Enables the command to run until the deployment is complete with either a success or failure.
251
273
  --ap Use the Tray APAC region
274
+ --ap2 Use the Tray APAC 2 region
252
275
  --eu Use the Tray EU region
253
276
  --us Use the Tray US region
254
277
 
@@ -301,16 +324,17 @@ Creates a new connector namespace for your organization
301
324
 
302
325
  ```
303
326
  USAGE
304
- $ tray-cdk namespace create ORGID NAMESPACE [--us] [--eu] [--ap]
327
+ $ tray-cdk namespace create ORGID NAMESPACE [--us] [--eu] [--ap] [--ap2]
305
328
 
306
329
  ARGUMENTS
307
330
  ORGID The ID of the organization for which to create the namespace
308
331
  NAMESPACE The name of the namespace to create
309
332
 
310
333
  FLAGS
311
- --ap Use the Tray APAC region
312
- --eu Use the Tray EU region
313
- --us Use the Tray US region
334
+ --ap Use the Tray APAC region
335
+ --ap2 Use the Tray APAC 2 region
336
+ --eu Use the Tray EU region
337
+ --us Use the Tray US region
314
338
 
315
339
  DESCRIPTION
316
340
  Creates a new connector namespace for your organization
@@ -327,15 +351,16 @@ Retrieves the connector namespace for your organization, if one exists
327
351
 
328
352
  ```
329
353
  USAGE
330
- $ tray-cdk namespace get ORGID [--us] [--eu] [--ap]
354
+ $ tray-cdk namespace get ORGID [--us] [--eu] [--ap] [--ap2]
331
355
 
332
356
  ARGUMENTS
333
357
  ORGID The ID of the organization you want to retrieve the namespace for
334
358
 
335
359
  FLAGS
336
- --ap Use the Tray APAC region
337
- --eu Use the Tray EU region
338
- --us Use the Tray US region
360
+ --ap Use the Tray APAC region
361
+ --ap2 Use the Tray APAC 2 region
362
+ --eu Use the Tray EU region
363
+ --us Use the Tray US region
339
364
 
340
365
  DESCRIPTION
341
366
  Retrieves the connector namespace for your organization, if one exists
@@ -352,7 +377,7 @@ Share your connector version with other users in your organization
352
377
 
353
378
  ```
354
379
  USAGE
355
- $ tray-cdk permissions add [CONNECTORNAME] [CONNECTORVERSION] [-e <value>] [--us] [--eu] [--ap]
380
+ $ tray-cdk permissions add [CONNECTORNAME] [CONNECTORVERSION] [-e <value>] [--us] [--eu] [--ap] [--ap2]
356
381
 
357
382
  ARGUMENTS
358
383
  CONNECTORNAME The name of the connector
@@ -361,6 +386,7 @@ ARGUMENTS
361
386
  FLAGS
362
387
  -e, --email=<value> Share with users by providing a list of emails
363
388
  --ap Use the Tray APAC region
389
+ --ap2 Use the Tray APAC 2 region
364
390
  --eu Use the Tray EU region
365
391
  --us Use the Tray US region
366
392
 
@@ -385,16 +411,17 @@ Retrieves a list of emails that have access to a connector
385
411
 
386
412
  ```
387
413
  USAGE
388
- $ tray-cdk permissions list [CONNECTORNAME] [CONNECTORVERSION] [--us] [--eu] [--ap]
414
+ $ tray-cdk permissions list [CONNECTORNAME] [CONNECTORVERSION] [--us] [--eu] [--ap] [--ap2]
389
415
 
390
416
  ARGUMENTS
391
417
  CONNECTORNAME The name of the connector
392
418
  CONNECTORVERSION The version of the connector
393
419
 
394
420
  FLAGS
395
- --ap Use the Tray APAC region
396
- --eu Use the Tray EU region
397
- --us Use the Tray US region
421
+ --ap Use the Tray APAC region
422
+ --ap2 Use the Tray APAC 2 region
423
+ --eu Use the Tray EU region
424
+ --us Use the Tray US region
398
425
 
399
426
  DESCRIPTION
400
427
  Retrieves a list of emails that have access to a connector
@@ -0,0 +1,16 @@
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
+ private generator;
9
+ run(): Promise<void>;
10
+ private validateParentOperation;
11
+ private detectAuthConfig;
12
+ private copyInputFromParent;
13
+ private updateParentOperationJson;
14
+ private findSrcDirectory;
15
+ }
16
+ //# 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;AAW5C,MAAM,CAAC,OAAO,OAAO,sBAAuB,SAAQ,OAAO;IAC1D,MAAM,CAAC,WAAW,SACiD;IAEnE,MAAM,CAAC,QAAQ,WAGb;IAEF,MAAM,CAAC,IAAI;;MAOT;IAEF,OAAO,CAAC,SAAS,CAAyB;IAEpC,GAAG;IAsGT,OAAO,CAAC,uBAAuB;YAuBjB,gBAAgB;YAehB,mBAAmB;YA8BnB,yBAAyB;IAcvC,OAAO,CAAC,gBAAgB;CAOxB"}
@@ -0,0 +1,163 @@
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
+ const NodeFsGenerator_1 = require("@trayio/generator/generator/NodeFsGenerator");
32
+ const auth_detector_1 = require("../../lib/dynamic-output/auth-detector");
33
+ class AddDynamicOutputSchema extends core_1.Command {
34
+ static description = 'Add a dynamic output schema operation for an existing operation';
35
+ static examples = [
36
+ '<%= config.bin %> <%= command.id %> get_posts',
37
+ '<%= config.bin %> <%= command.id %> fetch_user_data',
38
+ ];
39
+ static args = {
40
+ operationName: core_1.Args.string({
41
+ name: 'operationName',
42
+ required: true,
43
+ description: 'Name of the parent operation to add dynamic output schema for',
44
+ }),
45
+ };
46
+ generator = new NodeFsGenerator_1.NodeFsGenerator();
47
+ async run() {
48
+ const { args } = await this.parse(AddDynamicOutputSchema);
49
+ const { operationName } = args;
50
+ const currentDirectory = process.cwd();
51
+ const srcDir = this.findSrcDirectory(currentDirectory);
52
+ // Validate parent operation exists
53
+ this.validateParentOperation(srcDir, operationName);
54
+ const parentOperationPath = path.join(srcDir, operationName);
55
+ const parentOperationJsonPath = path.join(parentOperationPath, 'operation.json');
56
+ this.log(`Checking for operation '${operationName}'... ✓`);
57
+ // Check if dynamic output schema operation already exists
58
+ const outputSchemaOpName = `${operationName}_output_schema`;
59
+ const outputSchemaOpPath = path.join(srcDir, outputSchemaOpName);
60
+ if (fse.existsSync(outputSchemaOpPath)) {
61
+ this.error((0, colorizeString_1.error)(`Dynamic output schema operation '${outputSchemaOpName}' already exists!`));
62
+ }
63
+ // Read parent operation.json
64
+ const parentOperationJson = await fse.readJson(parentOperationJsonPath);
65
+ // Detect auth configuration
66
+ const authInfo = await this.detectAuthConfig(srcDir);
67
+ this.log(`Creating dynamic output schema operation '${outputSchemaOpName}'...`);
68
+ // Build template values for generator
69
+ const templateValues = {
70
+ operationNameSnakeCase: operationName,
71
+ operationNameTitleCase: StringExtensions_1.StringExtensions.titleCase(operationName),
72
+ operationNamePascalCase: StringExtensions_1.StringExtensions.pascalCase(operationName),
73
+ operationNameCamelCase: StringExtensions_1.StringExtensions.camelCase(operationName),
74
+ outputSchemaOpNameSnakeCase: outputSchemaOpName,
75
+ outputSchemaOpNamePascalCase: StringExtensions_1.StringExtensions.pascalCase(outputSchemaOpName),
76
+ outputSchemaOpNameCamelCase: StringExtensions_1.StringExtensions.camelCase(outputSchemaOpName),
77
+ parentOpNameSnakeCase: operationName,
78
+ parentOpNamePascalCase: StringExtensions_1.StringExtensions.pascalCase(operationName),
79
+ parentOpNameCamelCase: StringExtensions_1.StringExtensions.camelCase(operationName),
80
+ authType: authInfo.authType,
81
+ authFileName: authInfo.authFileName,
82
+ };
83
+ // Generate files from template
84
+ const rootDir = __dirname;
85
+ const templateDir = path.join(rootDir, '..', '..', 'templates');
86
+ const templatePath = path.join(templateDir, 'dynamic-output-schema-template.zip');
87
+ await this.generator.generate(templatePath, srcDir, templateValues)();
88
+ this.log(' ✓ Generated operation files from template');
89
+ // Ensure the output schema operation directory exists
90
+ await fse.ensureDir(outputSchemaOpPath);
91
+ // Manually copy input.ts from parent operation (can't be templated)
92
+ await this.copyInputFromParent(parentOperationPath, outputSchemaOpPath, StringExtensions_1.StringExtensions.pascalCase(operationName), StringExtensions_1.StringExtensions.pascalCase(outputSchemaOpName));
93
+ // Update parent operation.json with dynamic_output: true
94
+ await this.updateParentOperationJson(parentOperationJsonPath, parentOperationJson);
95
+ // Success message with next steps
96
+ this.log('');
97
+ this.log((0, colorizeString_1.success)(`Success! Created dynamic output schema operation: ${outputSchemaOpName}`));
98
+ this.log('');
99
+ this.log('Next steps:');
100
+ this.log(` 1. Edit src/${outputSchemaOpName}/handler.ts`);
101
+ this.log(' 2. Customize the data fetching logic for your use case');
102
+ this.log(' 3. Run "tray-cdk connector build" to build the connector');
103
+ this.log('');
104
+ this.log('Note: Dynamic output is only safe for read-only GET operations!');
105
+ }
106
+ validateParentOperation(srcDir, operationName) {
107
+ const parentOperationPath = path.join(srcDir, operationName);
108
+ if (!fse.existsSync(parentOperationPath)) {
109
+ this.error((0, colorizeString_1.error)(`Operation '${operationName}' not found in src/ directory.\nMake sure you're in the connector root or src/ directory.`));
110
+ }
111
+ const parentOperationJsonPath = path.join(parentOperationPath, 'operation.json');
112
+ if (!fse.existsSync(parentOperationJsonPath)) {
113
+ this.error((0, colorizeString_1.error)(`Operation '${operationName}' exists but missing operation.json file.`));
114
+ }
115
+ }
116
+ async detectAuthConfig(srcDir) {
117
+ const connectorJsonPath = path.join(path.dirname(srcDir), 'connector.json');
118
+ try {
119
+ const connectorJson = await fse.readJson(connectorJsonPath);
120
+ return await auth_detector_1.AuthDetector.detectAuthInfo(srcDir, connectorJson.name);
121
+ }
122
+ catch (e) {
123
+ // If we can't read connector.json, use defaults
124
+ this.warn('Could not read connector.json, using default auth type. Auth import may need manual adjustment.');
125
+ return await auth_detector_1.AuthDetector.detectAuthInfo(srcDir);
126
+ }
127
+ }
128
+ async copyInputFromParent(parentOperationPath, outputSchemaOpPath, parentOpNamePascalCase, outputSchemaOpNamePascalCase) {
129
+ const parentInputPath = path.join(parentOperationPath, 'input.ts');
130
+ let inputTsContent;
131
+ if (fse.existsSync(parentInputPath)) {
132
+ // Read parent input.ts and copy it with renamed types
133
+ const parentInputContent = await fse.readFile(parentInputPath, 'utf-8');
134
+ // Replace the parent type name with the new type name
135
+ inputTsContent = parentInputContent.replace(new RegExp(`\\b${parentOpNamePascalCase}Input\\b`, 'g'), `${outputSchemaOpNamePascalCase}Input`);
136
+ }
137
+ else {
138
+ // Fallback: create a simple input type
139
+ inputTsContent = `export type ${outputSchemaOpNamePascalCase}Input = Record<string, any>;
140
+ `;
141
+ }
142
+ await fse.writeFile(path.join(outputSchemaOpPath, 'input.ts'), inputTsContent);
143
+ this.log(' ✓ Generated input.ts from parent operation');
144
+ }
145
+ async updateParentOperationJson(parentOperationJsonPath, parentOperationJson) {
146
+ const updatedParentJson = {
147
+ ...parentOperationJson,
148
+ dynamic_output: true,
149
+ };
150
+ await fse.writeJson(parentOperationJsonPath, updatedParentJson, {
151
+ spaces: 2,
152
+ });
153
+ this.log(' ✓ Updated parent operation.json with dynamic_output: true');
154
+ }
155
+ findSrcDirectory(currentDirectory) {
156
+ const { base } = path.parse(currentDirectory);
157
+ if (base === 'src') {
158
+ return currentDirectory;
159
+ }
160
+ return path.join(currentDirectory, 'src');
161
+ }
162
+ }
163
+ exports.default = AddDynamicOutputSchema;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=add-dynamic-output-schema.unit.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-dynamic-output-schema.unit.test.d.ts","sourceRoot":"","sources":["../../../src/commands/connector/add-dynamic-output-schema.unit.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,335 @@
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ const stdout_stderr_1 = require("stdout-stderr");
30
+ const fse = __importStar(require("fs-extra"));
31
+ const path = __importStar(require("path"));
32
+ const add_dynamic_output_schema_1 = __importDefault(require("./add-dynamic-output-schema"));
33
+ jest.mock('fs-extra');
34
+ describe('AddDynamicOutputSchema', () => {
35
+ const mockFse = fse;
36
+ const operationName = 'get_posts';
37
+ const outputSchemaOpName = 'get_posts_output_schema';
38
+ const srcDir = path.join(process.cwd(), 'src');
39
+ const parentOperationPath = path.join(srcDir, operationName);
40
+ const outputSchemaOpPath = path.join(srcDir, outputSchemaOpName);
41
+ beforeEach(() => {
42
+ jest.clearAllMocks();
43
+ // Default mocks for successful case
44
+ mockFse.existsSync.mockImplementation((filePath) => {
45
+ const pathStr = filePath.toString();
46
+ if (pathStr.includes(operationName) &&
47
+ pathStr.includes('operation.json')) {
48
+ return true; // Parent operation.json exists
49
+ }
50
+ if (pathStr.includes(operationName) &&
51
+ !pathStr.includes('output_schema')) {
52
+ return true; // Parent operation exists
53
+ }
54
+ if (pathStr.includes('output_schema')) {
55
+ return false; // Output schema operation doesn't exist yet
56
+ }
57
+ if (pathStr.includes('connector.json')) {
58
+ return true;
59
+ }
60
+ if (pathStr.includes('MyConnectorAuth.ts')) {
61
+ return true;
62
+ }
63
+ return false;
64
+ });
65
+ mockFse.readJson.mockImplementation(async (filePath) => {
66
+ const pathStr = filePath.toString();
67
+ if (pathStr.includes('connector.json')) {
68
+ return { name: 'my_connector' };
69
+ }
70
+ if (pathStr.includes('operation.json')) {
71
+ return {
72
+ name: operationName,
73
+ title: 'Get Posts',
74
+ description: 'Get all posts',
75
+ };
76
+ }
77
+ return {};
78
+ });
79
+ mockFse.readFile.mockImplementation(async (filePath) => {
80
+ const pathStr = filePath.toString();
81
+ if (pathStr.includes('input.ts')) {
82
+ return `export type GetPostsInput = {
83
+ limit?: number;
84
+ offset?: number;
85
+ };
86
+ `;
87
+ }
88
+ if (pathStr.includes('Auth.ts')) {
89
+ return 'export type MyConnectorAuth = { apiKey: string };';
90
+ }
91
+ return '';
92
+ });
93
+ mockFse.readdir.mockImplementation(async (dirPath) => {
94
+ const pathStr = dirPath.toString();
95
+ if (pathStr.includes('src')) {
96
+ // Mock src directory contents with auth file
97
+ return [
98
+ operationName,
99
+ 'MyConnectorAuth.ts',
100
+ 'connector.ts',
101
+ 'index.ts',
102
+ ];
103
+ }
104
+ return [];
105
+ });
106
+ mockFse.ensureDir.mockResolvedValue(undefined);
107
+ mockFse.writeJson.mockResolvedValue(undefined);
108
+ mockFse.writeFile.mockResolvedValue(undefined);
109
+ });
110
+ afterAll(() => {
111
+ jest.restoreAllMocks();
112
+ });
113
+ describe('successful operation creation', () => {
114
+ it('should create dynamic output schema operation for existing operation', async () => {
115
+ const command = new add_dynamic_output_schema_1.default([operationName], {});
116
+ const mockGenerate = jest
117
+ .fn()
118
+ .mockImplementation(() => jest.fn().mockResolvedValue(true));
119
+ command['generator'] = {
120
+ generate: mockGenerate,
121
+ };
122
+ stdout_stderr_1.stdout.start();
123
+ await command.run();
124
+ stdout_stderr_1.stdout.stop();
125
+ // Verify success message
126
+ expect(stdout_stderr_1.stdout.output).toContain(`Success! Created dynamic output schema operation: ${outputSchemaOpName}`);
127
+ // Verify generator was called with correct template and values
128
+ expect(mockGenerate).toHaveBeenCalledWith(expect.stringContaining('dynamic-output-schema-template.zip'), expect.stringContaining('/src'), expect.objectContaining({
129
+ operationNameSnakeCase: operationName,
130
+ outputSchemaOpNameSnakeCase: outputSchemaOpName,
131
+ parentOpNameSnakeCase: operationName,
132
+ authType: 'MyConnectorAuth',
133
+ authFileName: 'MyConnectorAuth',
134
+ }));
135
+ // Verify parent operation.json was updated with dynamic_output: true
136
+ expect(mockFse.writeJson).toHaveBeenCalledWith(path.join(parentOperationPath, 'operation.json'), expect.objectContaining({
137
+ dynamic_output: true,
138
+ }), { spaces: 2 });
139
+ });
140
+ it('should generate correct input.ts by copying and renaming from parent', async () => {
141
+ const command = new add_dynamic_output_schema_1.default([operationName], {});
142
+ const mockGenerate = jest
143
+ .fn()
144
+ .mockImplementation(() => jest.fn().mockResolvedValue(true));
145
+ command['generator'] = {
146
+ generate: mockGenerate,
147
+ };
148
+ stdout_stderr_1.stdout.start();
149
+ await command.run();
150
+ stdout_stderr_1.stdout.stop();
151
+ // Verify input.ts was written with renamed types
152
+ expect(mockFse.writeFile).toHaveBeenCalledWith(path.join(outputSchemaOpPath, 'input.ts'), expect.stringContaining('GetPostsOutputSchemaInput'));
153
+ // Verify it doesn't import from parent operation
154
+ const inputCall = mockFse.writeFile.mock.calls.find((call) => call[0].toString().includes('input.ts'));
155
+ expect(inputCall?.[1]).not.toContain(`from '../${operationName}/input'`);
156
+ expect(inputCall?.[1]).toContain('GetPostsOutputSchemaInput');
157
+ });
158
+ it('should handle input.ts fallback when parent input.ts does not exist', async () => {
159
+ mockFse.existsSync.mockImplementation((filePath) => {
160
+ const pathStr = filePath.toString();
161
+ if (pathStr.includes('input.ts')) {
162
+ return false; // Parent input.ts doesn't exist
163
+ }
164
+ if (pathStr.includes(operationName) &&
165
+ pathStr.includes('operation.json')) {
166
+ return true;
167
+ }
168
+ if (pathStr.includes(operationName) &&
169
+ !pathStr.includes('output_schema')) {
170
+ return true;
171
+ }
172
+ if (pathStr.includes('connector.json')) {
173
+ return true;
174
+ }
175
+ return false;
176
+ });
177
+ mockFse.readdir.mockResolvedValue([
178
+ operationName,
179
+ 'MyConnectorAuth.ts',
180
+ 'connector.ts',
181
+ ]);
182
+ const command = new add_dynamic_output_schema_1.default([operationName], {});
183
+ const mockGenerate = jest
184
+ .fn()
185
+ .mockImplementation(() => jest.fn().mockResolvedValue(true));
186
+ command['generator'] = {
187
+ generate: mockGenerate,
188
+ };
189
+ stdout_stderr_1.stdout.start();
190
+ await command.run();
191
+ stdout_stderr_1.stdout.stop();
192
+ // Verify fallback input.ts was created
193
+ const inputCall = mockFse.writeFile.mock.calls.find((call) => call[0].toString().includes('input.ts'));
194
+ expect(inputCall?.[1]).toContain('Record<string, any>');
195
+ });
196
+ });
197
+ describe('error handling', () => {
198
+ it('should error when parent operation does not exist', async () => {
199
+ mockFse.existsSync.mockReturnValue(false);
200
+ mockFse.readdir.mockResolvedValue([]);
201
+ const command = new add_dynamic_output_schema_1.default([operationName], {});
202
+ let errorThrown = false;
203
+ try {
204
+ await command.run();
205
+ }
206
+ catch (error) {
207
+ errorThrown = true;
208
+ expect(error.message).toContain(`Operation '${operationName}' not found`);
209
+ }
210
+ expect(errorThrown).toBe(true);
211
+ });
212
+ it('should error when parent operation.json is missing', async () => {
213
+ mockFse.existsSync.mockImplementation((filePath) => {
214
+ const pathStr = filePath.toString();
215
+ if (pathStr.includes('operation.json')) {
216
+ return false; // operation.json doesn't exist
217
+ }
218
+ if (pathStr.includes(operationName)) {
219
+ return true; // but operation folder exists
220
+ }
221
+ return false;
222
+ });
223
+ mockFse.readdir.mockResolvedValue([]);
224
+ const command = new add_dynamic_output_schema_1.default([operationName], {});
225
+ let errorThrown = false;
226
+ try {
227
+ await command.run();
228
+ }
229
+ catch (error) {
230
+ errorThrown = true;
231
+ expect(error.message).toContain('missing operation.json');
232
+ }
233
+ expect(errorThrown).toBe(true);
234
+ });
235
+ it('should error when dynamic output schema operation already exists', async () => {
236
+ mockFse.existsSync.mockImplementation((filePath) =>
237
+ // Everything exists including the output schema operation
238
+ true);
239
+ mockFse.readdir.mockResolvedValue([]);
240
+ const command = new add_dynamic_output_schema_1.default([operationName], {});
241
+ let errorThrown = false;
242
+ try {
243
+ await command.run();
244
+ }
245
+ catch (error) {
246
+ errorThrown = true;
247
+ expect(error.message).toContain('already exists');
248
+ }
249
+ expect(errorThrown).toBe(true);
250
+ });
251
+ it('should warn when connector.json cannot be read', async () => {
252
+ mockFse.readJson.mockImplementation(async (filePath) => {
253
+ const pathStr = filePath.toString();
254
+ if (pathStr.includes('connector.json')) {
255
+ throw new Error('Cannot read connector.json');
256
+ }
257
+ if (pathStr.includes('operation.json')) {
258
+ return {
259
+ name: operationName,
260
+ title: 'Get Posts',
261
+ };
262
+ }
263
+ return {};
264
+ });
265
+ const command = new add_dynamic_output_schema_1.default([operationName], {});
266
+ stdout_stderr_1.stdout.start();
267
+ stdout_stderr_1.stderr.start();
268
+ await command.run();
269
+ stdout_stderr_1.stderr.stop();
270
+ stdout_stderr_1.stdout.stop();
271
+ // Should warn but still succeed
272
+ expect(stdout_stderr_1.stderr.output).toContain('Could not read connector.json');
273
+ expect(stdout_stderr_1.stdout.output).toContain('Success!');
274
+ });
275
+ });
276
+ describe('file detection', () => {
277
+ it('should detect standard {ConnectorName}Auth.ts pattern', async () => {
278
+ const command = new add_dynamic_output_schema_1.default([operationName], {});
279
+ const mockGenerate = jest
280
+ .fn()
281
+ .mockImplementation(() => jest.fn().mockResolvedValue(true));
282
+ command['generator'] = {
283
+ generate: mockGenerate,
284
+ };
285
+ stdout_stderr_1.stdout.start();
286
+ await command.run();
287
+ stdout_stderr_1.stdout.stop();
288
+ // Verify auth type was detected and passed to generator
289
+ expect(mockGenerate).toHaveBeenCalledWith(expect.anything(), expect.anything(), expect.objectContaining({
290
+ authType: 'MyConnectorAuth',
291
+ authFileName: 'MyConnectorAuth',
292
+ }));
293
+ });
294
+ it('should handle when in src/ directory', async () => {
295
+ // Mock process.cwd to return src directory
296
+ const originalCwd = process.cwd;
297
+ process.cwd = jest.fn().mockReturnValue(srcDir);
298
+ const command = new add_dynamic_output_schema_1.default([operationName], {});
299
+ const mockGenerate = jest
300
+ .fn()
301
+ .mockImplementation(() => jest.fn().mockResolvedValue(true));
302
+ command['generator'] = {
303
+ generate: mockGenerate,
304
+ };
305
+ stdout_stderr_1.stdout.start();
306
+ await command.run();
307
+ stdout_stderr_1.stdout.stop();
308
+ // Verify generator was called with src directory
309
+ expect(mockGenerate).toHaveBeenCalledWith(expect.anything(), srcDir, expect.anything());
310
+ // Restore
311
+ process.cwd = originalCwd;
312
+ });
313
+ });
314
+ describe('output messages', () => {
315
+ it('should display correct success message and next steps', async () => {
316
+ const command = new add_dynamic_output_schema_1.default([operationName], {});
317
+ const mockGenerate = jest
318
+ .fn()
319
+ .mockImplementation(() => jest.fn().mockResolvedValue(true));
320
+ command['generator'] = {
321
+ generate: mockGenerate,
322
+ };
323
+ stdout_stderr_1.stdout.start();
324
+ await command.run();
325
+ stdout_stderr_1.stdout.stop();
326
+ expect(stdout_stderr_1.stdout.output).toContain('Checking for operation');
327
+ expect(stdout_stderr_1.stdout.output).toContain('Creating dynamic output schema operation');
328
+ expect(stdout_stderr_1.stdout.output).toContain('✓ Generated operation files from template');
329
+ expect(stdout_stderr_1.stdout.output).toContain('✓ Generated input.ts from parent operation');
330
+ expect(stdout_stderr_1.stdout.output).toContain('✓ Updated parent operation.json');
331
+ expect(stdout_stderr_1.stdout.output).toContain('Next steps:');
332
+ expect(stdout_stderr_1.stdout.output).toContain(`Edit src/${outputSchemaOpName}/handler.ts`);
333
+ });
334
+ });
335
+ });
@@ -6,6 +6,7 @@ export default class Create extends Command {
6
6
  us: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
7
7
  eu: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
8
8
  ap: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
9
+ ap2: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
9
10
  };
10
11
  private regionHandler;
11
12
  run(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/deployment/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAM,MAAM,aAAa,CAAC;AAoB1C,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,OAAO;IAC1C,MAAM,CAAC,WAAW,SAAsD;IAExE,MAAM,CAAC,IAAI,KAAM;IAEjB,MAAM,CAAC,KAAK;;;;MAEV;IAEF,OAAO,CAAC,aAAa,CAGnB;IAEI,GAAG;CAiET"}
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/deployment/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAM,MAAM,aAAa,CAAC;AAoB1C,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,OAAO;IAC1C,MAAM,CAAC,WAAW,SAAsD;IAExE,MAAM,CAAC,IAAI,KAAM;IAEjB,MAAM,CAAC,KAAK;;;;;MAEV;IAEF,OAAO,CAAC,aAAa,CAGnB;IAEI,GAAG;CAiET"}
@@ -10,6 +10,7 @@ export default class Get extends Command {
10
10
  us: import("@oclif/core/lib/interfaces/parser").BooleanFlag<boolean>;
11
11
  eu: import("@oclif/core/lib/interfaces/parser").BooleanFlag<boolean>;
12
12
  ap: import("@oclif/core/lib/interfaces/parser").BooleanFlag<boolean>;
13
+ ap2: import("@oclif/core/lib/interfaces/parser").BooleanFlag<boolean>;
13
14
  tail: import("@oclif/core/lib/interfaces/parser").BooleanFlag<boolean>;
14
15
  };
15
16
  static examples: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"get.d.ts","sourceRoot":"","sources":["../../../src/commands/deployment/get.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAmB,MAAM,aAAa,CAAC;AAwBvD,MAAM,CAAC,OAAO,OAAO,GAAI,SAAQ,OAAO;IACvC,MAAM,CAAC,WAAW,SAAoD;IAEtE,MAAM,CAAC,IAAI;;;;MAiBT;IAEF,MAAM,CAAC,KAAK;;;;;MAOV;IAEF,MAAM,CAAC,QAAQ,WAUb;IAEF,OAAO,CAAC,aAAa,CAGnB;IAEF,OAAO,CAAC,6BAA6B,CAkCnC;IAEF,OAAO,CAAC,qBAAqB,CAe3B;IAEI,GAAG;CAsGT"}
1
+ {"version":3,"file":"get.d.ts","sourceRoot":"","sources":["../../../src/commands/deployment/get.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAmB,MAAM,aAAa,CAAC;AAwBvD,MAAM,CAAC,OAAO,OAAO,GAAI,SAAQ,OAAO;IACvC,MAAM,CAAC,WAAW,SAAoD;IAEtE,MAAM,CAAC,IAAI;;;;MAiBT;IAEF,MAAM,CAAC,KAAK;;;;;;MAOV;IAEF,MAAM,CAAC,QAAQ,WAUb;IAEF,OAAO,CAAC,aAAa,CAGnB;IAEF,OAAO,CAAC,6BAA6B,CAkCnC;IAEF,OAAO,CAAC,qBAAqB,CAe3B;IAEI,GAAG;CAsGT"}
@@ -9,6 +9,7 @@ export default class Create extends Command {
9
9
  us: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
10
  eu: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
11
11
  ap: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
12
+ ap2: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
12
13
  };
13
14
  static examples: string[];
14
15
  private regionHandler;
@@ -1 +1 @@
1
- {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/namespace/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAmB,MAAM,aAAa,CAAC;AAevD,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,OAAO;IAC1C,MAAM,CAAC,WAAW,SACyC;IAE3D,MAAM,CAAC,IAAI;;;MAYT;IAEF,MAAM,CAAC,KAAK;;;;MAEV;IAEF,MAAM,CAAC,QAAQ,WAGb;IAEF,OAAO,CAAC,aAAa,CAGnB;IAEI,GAAG;CAgDT"}
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/namespace/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAmB,MAAM,aAAa,CAAC;AAevD,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,OAAO;IAC1C,MAAM,CAAC,WAAW,SACyC;IAE3D,MAAM,CAAC,IAAI;;;MAYT;IAEF,MAAM,CAAC,KAAK;;;;;MAEV;IAEF,MAAM,CAAC,QAAQ,WAGb;IAEF,OAAO,CAAC,aAAa,CAGnB;IAEI,GAAG;CAgDT"}
@@ -8,6 +8,7 @@ export default class Get extends Command {
8
8
  us: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
9
9
  eu: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
10
  ap: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
11
+ ap2: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
11
12
  };
12
13
  static examples: string[];
13
14
  private regionHandler;
@@ -1 +1 @@
1
- {"version":3,"file":"get.d.ts","sourceRoot":"","sources":["../../../src/commands/namespace/get.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAmB,MAAM,aAAa,CAAC;AAgBvD,MAAM,CAAC,OAAO,OAAO,GAAI,SAAQ,OAAO;IACvC,MAAM,CAAC,WAAW,SACwD;IAE1E,MAAM,CAAC,IAAI;;MAOT;IAEF,MAAM,CAAC,KAAK;;;;MAEV;IAEF,MAAM,CAAC,QAAQ,WAGb;IAEF,OAAO,CAAC,aAAa,CAGnB;IAEI,GAAG;CA6CT"}
1
+ {"version":3,"file":"get.d.ts","sourceRoot":"","sources":["../../../src/commands/namespace/get.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAmB,MAAM,aAAa,CAAC;AAgBvD,MAAM,CAAC,OAAO,OAAO,GAAI,SAAQ,OAAO;IACvC,MAAM,CAAC,WAAW,SACwD;IAE1E,MAAM,CAAC,IAAI;;MAOT;IAEF,MAAM,CAAC,KAAK;;;;;MAEV;IAEF,MAAM,CAAC,QAAQ,WAGb;IAEF,OAAO,CAAC,aAAa,CAGnB;IAEI,GAAG;CA6CT"}
@@ -10,6 +10,7 @@ export default class Add extends Command {
10
10
  us: import("@oclif/core/lib/interfaces/parser").BooleanFlag<boolean>;
11
11
  eu: import("@oclif/core/lib/interfaces/parser").BooleanFlag<boolean>;
12
12
  ap: import("@oclif/core/lib/interfaces/parser").BooleanFlag<boolean>;
13
+ ap2: import("@oclif/core/lib/interfaces/parser").BooleanFlag<boolean>;
13
14
  email: import("@oclif/core/lib/interfaces/parser").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
14
15
  };
15
16
  private regionHandler;
@@ -1 +1 @@
1
- {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../src/commands/permissions/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,OAAO,EAAa,MAAM,aAAa,CAAC;AAkBvD,MAAM,CAAC,OAAO,OAAO,GAAI,SAAQ,OAAO;IACvC,MAAM,CAAC,WAAW,SACoD;IAEtE,MAAM,CAAC,QAAQ,WAQb;IAEF,MAAM,CAAC,IAAI;;;MAWT;IAEF,MAAM,CAAC,KAAK;;;;;MAaV;IAEF,OAAO,CAAC,aAAa,CAGnB;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;YAgFnB,kBAAkB;YAkClB,sBAAsB;IAuCpC,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,eAAe;CAGvB"}
1
+ {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../src/commands/permissions/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,OAAO,EAAa,MAAM,aAAa,CAAC;AAkBvD,MAAM,CAAC,OAAO,OAAO,GAAI,SAAQ,OAAO;IACvC,MAAM,CAAC,WAAW,SACoD;IAEtE,MAAM,CAAC,QAAQ,WAQb;IAEF,MAAM,CAAC,IAAI;;;MAWT;IAEF,MAAM,CAAC,KAAK;;;;;;MAaV;IAEF,OAAO,CAAC,aAAa,CAGnB;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;YAgFnB,kBAAkB;YAkClB,sBAAsB;IAuCpC,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,eAAe;CAGvB"}
@@ -10,6 +10,7 @@ export default class PermissionsList extends Command {
10
10
  us: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
11
11
  eu: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
12
12
  ap: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
13
+ ap2: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
13
14
  };
14
15
  private regionHandler;
15
16
  run(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/commands/permissions/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,OAAO,EAAa,MAAM,aAAa,CAAC;AAYvD,MAAM,CAAC,OAAO,OAAO,eAAgB,SAAQ,OAAO;IACnD,MAAM,CAAC,WAAW,SAC4C;IAG9D,MAAM,CAAC,QAAQ,WAIb;IAEF,MAAM,CAAC,IAAI;;;MAWT;IAEF,MAAM,CAAC,KAAK;;;;MAaV;IAEF,OAAO,CAAC,aAAa,CAGnB;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAsDjC"}
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/commands/permissions/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,OAAO,EAAa,MAAM,aAAa,CAAC;AAYvD,MAAM,CAAC,OAAO,OAAO,eAAgB,SAAQ,OAAO;IACnD,MAAM,CAAC,WAAW,SAC4C;IAG9D,MAAM,CAAC,QAAQ,WAIb;IAEF,MAAM,CAAC,IAAI;;;MAWT;IAEF,MAAM,CAAC,KAAK;;;;;MAaV;IAEF,OAAO,CAAC,aAAa,CAGnB;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAsDjC"}
@@ -0,0 +1,21 @@
1
+ export interface AuthInfo {
2
+ authFileName: string;
3
+ authType: string;
4
+ }
5
+ /**
6
+ * Detects the authentication file and type for a connector
7
+ */
8
+ export declare class AuthDetector {
9
+ /**
10
+ * Detects the auth file and extracts the auth type name
11
+ * @param srcDir - Path to the connector's src directory
12
+ * @param connectorName - Name of the connector from connector.json
13
+ * @returns AuthInfo with file name and type name
14
+ */
15
+ static detectAuthInfo(srcDir: string, connectorName?: string): Promise<AuthInfo>;
16
+ /**
17
+ * Find a file in a list using case-insensitive matching
18
+ */
19
+ private static findFileCaseInsensitive;
20
+ }
21
+ //# sourceMappingURL=auth-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-detector.d.ts","sourceRoot":"","sources":["../../../src/lib/dynamic-output/auth-detector.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,QAAQ;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,qBAAa,YAAY;IACxB;;;;;OAKG;WACU,cAAc,CAC1B,MAAM,EAAE,MAAM,EACd,aAAa,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,QAAQ,CAAC;IAkDpB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,uBAAuB;CAQtC"}
@@ -0,0 +1,85 @@
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
+ exports.AuthDetector = void 0;
27
+ const fse = __importStar(require("fs-extra"));
28
+ const path = __importStar(require("path"));
29
+ const StringExtensions_1 = require("@trayio/commons/string/StringExtensions");
30
+ /**
31
+ * Detects the authentication file and type for a connector
32
+ */
33
+ class AuthDetector {
34
+ /**
35
+ * Detects the auth file and extracts the auth type name
36
+ * @param srcDir - Path to the connector's src directory
37
+ * @param connectorName - Name of the connector from connector.json
38
+ * @returns AuthInfo with file name and type name
39
+ */
40
+ static async detectAuthInfo(srcDir, connectorName) {
41
+ let authFileName = 'Authentication';
42
+ let authType = 'NoAuth';
43
+ // Get all files in src directory for case-insensitive matching
44
+ const srcFiles = await fse.readdir(srcDir);
45
+ if (connectorName) {
46
+ const connectorNamePascalCase = StringExtensions_1.StringExtensions.pascalCase(connectorName);
47
+ // Check for {ConnectorName}Auth.ts pattern (standard pattern)
48
+ const standardAuthFile = `${connectorNamePascalCase}Auth.ts`;
49
+ const foundFile = this.findFileCaseInsensitive(srcFiles, standardAuthFile);
50
+ if (foundFile) {
51
+ authFileName = foundFile.replace('.ts', '');
52
+ authType = `${connectorNamePascalCase}Auth`;
53
+ return { authFileName, authType };
54
+ }
55
+ }
56
+ // Fall back to other common patterns
57
+ const authFiles = ['Authentication.ts', 'Auth.ts'];
58
+ const foundFile = authFiles
59
+ .map((pattern) => this.findFileCaseInsensitive(srcFiles, pattern))
60
+ .find((file) => file !== undefined);
61
+ if (foundFile) {
62
+ authFileName = foundFile.replace('.ts', '');
63
+ const authPath = path.join(srcDir, foundFile);
64
+ // Try to read and extract auth type name
65
+ try {
66
+ const authContent = await fse.readFile(authPath, 'utf-8');
67
+ const typeMatch = authContent.match(/export\s+type\s+(\w+)/);
68
+ if (typeMatch) {
69
+ [, authType] = typeMatch;
70
+ }
71
+ }
72
+ catch (e) {
73
+ // If we can't read the file, use the default
74
+ }
75
+ }
76
+ return { authFileName, authType };
77
+ }
78
+ /**
79
+ * Find a file in a list using case-insensitive matching
80
+ */
81
+ static findFileCaseInsensitive(files, targetFile) {
82
+ return files.find((file) => file.toLowerCase() === targetFile.toLowerCase());
83
+ }
84
+ }
85
+ exports.AuthDetector = AuthDetector;
@@ -0,0 +1,2 @@
1
+ export { AuthDetector, AuthInfo } from './auth-detector';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/dynamic-output/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AuthDetector = void 0;
4
+ var auth_detector_1 = require("./auth-detector");
5
+ Object.defineProperty(exports, "AuthDetector", { enumerable: true, get: function () { return auth_detector_1.AuthDetector; } });
@@ -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": {
@@ -360,6 +391,12 @@
360
391
  "name": "ap",
361
392
  "allowNo": false,
362
393
  "type": "boolean"
394
+ },
395
+ "ap2": {
396
+ "description": "Use the Tray APAC 2 region",
397
+ "name": "ap2",
398
+ "allowNo": false,
399
+ "type": "boolean"
363
400
  }
364
401
  },
365
402
  "hasDynamicHelp": false,
@@ -434,6 +471,12 @@
434
471
  "name": "ap",
435
472
  "allowNo": false,
436
473
  "type": "boolean"
474
+ },
475
+ "ap2": {
476
+ "description": "Use the Tray APAC 2 region",
477
+ "name": "ap2",
478
+ "allowNo": false,
479
+ "type": "boolean"
437
480
  }
438
481
  },
439
482
  "hasDynamicHelp": false,
@@ -489,6 +532,12 @@
489
532
  "name": "ap",
490
533
  "allowNo": false,
491
534
  "type": "boolean"
535
+ },
536
+ "ap2": {
537
+ "description": "Use the Tray APAC 2 region",
538
+ "name": "ap2",
539
+ "allowNo": false,
540
+ "type": "boolean"
492
541
  }
493
542
  },
494
543
  "hasDynamicHelp": false,
@@ -539,6 +588,12 @@
539
588
  "name": "ap",
540
589
  "allowNo": false,
541
590
  "type": "boolean"
591
+ },
592
+ "ap2": {
593
+ "description": "Use the Tray APAC 2 region",
594
+ "name": "ap2",
595
+ "allowNo": false,
596
+ "type": "boolean"
542
597
  }
543
598
  },
544
599
  "hasDynamicHelp": false,
@@ -609,6 +664,12 @@
609
664
  "name": "ap",
610
665
  "allowNo": false,
611
666
  "type": "boolean"
667
+ },
668
+ "ap2": {
669
+ "description": "Use the Tray APAC 2 region",
670
+ "name": "ap2",
671
+ "allowNo": false,
672
+ "type": "boolean"
612
673
  }
613
674
  },
614
675
  "hasDynamicHelp": false,
@@ -665,6 +726,12 @@
665
726
  "name": "ap",
666
727
  "allowNo": false,
667
728
  "type": "boolean"
729
+ },
730
+ "ap2": {
731
+ "description": "Use the Tray APAC 2 region",
732
+ "name": "ap2",
733
+ "allowNo": false,
734
+ "type": "boolean"
668
735
  }
669
736
  },
670
737
  "hasDynamicHelp": false,
@@ -684,5 +751,5 @@
684
751
  ]
685
752
  }
686
753
  },
687
- "version": "5.13.0"
754
+ "version": "5.15.0"
688
755
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trayio/cdk-cli",
3
- "version": "5.13.0",
3
+ "version": "5.15.0",
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.13.0",
26
- "@trayio/cdk-build": "5.13.0",
27
- "@trayio/cdk-cli-commons": "5.13.0",
28
- "@trayio/commons": "5.13.0",
29
- "@trayio/generator": "5.13.0",
30
- "@trayio/tray-client": "5.13.0",
31
- "@trayio/tray-openapi": "5.13.0",
25
+ "@trayio/axios": "5.15.0",
26
+ "@trayio/cdk-build": "5.15.0",
27
+ "@trayio/cdk-cli-commons": "5.15.0",
28
+ "@trayio/commons": "5.15.0",
29
+ "@trayio/generator": "5.15.0",
30
+ "@trayio/tray-client": "5.15.0",
31
+ "@trayio/tray-openapi": "5.15.0",
32
32
  "chalk": "4.1.2",
33
33
  "dotenv": "^16.0.0",
34
34
  "inquirer": "8.2.6"