@unito/integration-cli 0.57.2 → 0.58.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.
Files changed (96) hide show
  1. package/dist/.eslintrc.d.ts +6 -0
  2. package/dist/.eslintrc.js +17 -2
  3. package/dist/{integrationGenerator/integrationBoilerplate → boilerplate}/src/index.ts +1 -3
  4. package/dist/src/commands/dev.d.ts +4 -0
  5. package/dist/src/commands/dev.js +40 -4
  6. package/dist/src/commands/init.js +2 -2
  7. package/dist/src/commands/login.js +1 -1
  8. package/dist/src/commands/oauth2.js +27 -21
  9. package/dist/src/commands/test.js +28 -6
  10. package/dist/src/errors.d.ts +8 -0
  11. package/dist/src/errors.js +35 -18
  12. package/dist/src/resources/configuration.d.ts +1 -1
  13. package/dist/src/resources/configuration.js +4 -6
  14. package/dist/src/resources/credentials.d.ts +3 -0
  15. package/dist/src/resources/credentials.js +26 -0
  16. package/dist/src/resources/integrations.d.ts +1 -0
  17. package/dist/src/resources/integrations.js +37 -2
  18. package/dist/src/resources/oauth2.d.ts +4 -0
  19. package/dist/src/resources/oauth2.js +28 -0
  20. package/dist/src/resources/template.d.ts +3 -0
  21. package/dist/src/resources/template.js +40 -0
  22. package/dist/src/services/integrationsPlatform.d.ts +1 -0
  23. package/dist/src/services/integrationsPlatform.js +5 -1
  24. package/dist/src/{oauth2Helper/oauth2Helper.d.ts → services/oauth2.d.ts} +37 -23
  25. package/dist/src/{oauth2Helper/oauth2Helper.js → services/oauth2.js} +112 -113
  26. package/dist/test/commands/dev.test.js +21 -0
  27. package/dist/test/commands/init.test.js +4 -4
  28. package/dist/test/commands/login.test.js +1 -0
  29. package/dist/test/commands/oauth2.test.js +20 -2
  30. package/dist/test/commands/publish.test.js +1 -0
  31. package/dist/test/commands/test.test.js +22 -0
  32. package/dist/test/commands/upgrade.test.js +1 -0
  33. package/dist/test/resources/integrations.test.js +37 -0
  34. package/dist/test/resources/oauth2.test.js +55 -0
  35. package/dist/test/resources/template.test.js +40 -0
  36. package/dist/test/services/oauth2.test.d.ts +1 -0
  37. package/dist/test/services/oauth2.test.js +159 -0
  38. package/oclif.manifest.json +64 -9
  39. package/package.json +8 -8
  40. package/dist/integrationGenerator/errors.d.ts +0 -2
  41. package/dist/integrationGenerator/errors.js +0 -6
  42. package/dist/integrationGenerator/index.d.ts +0 -2
  43. package/dist/integrationGenerator/index.js +0 -5
  44. package/dist/integrationGenerator/integrationBoilerplate/integrationBoilerplate/.dockerignore +0 -3
  45. package/dist/integrationGenerator/integrationBoilerplate/integrationBoilerplate/.eslintrc.js +0 -74
  46. package/dist/integrationGenerator/integrationBoilerplate/integrationBoilerplate/.nvmrc +0 -1
  47. package/dist/integrationGenerator/integrationBoilerplate/integrationBoilerplate/.prettierignore +0 -1
  48. package/dist/integrationGenerator/integrationBoilerplate/integrationBoilerplate/.prettierrc +0 -7
  49. package/dist/integrationGenerator/integrationBoilerplate/integrationBoilerplate/.unito.json +0 -1
  50. package/dist/integrationGenerator/integrationBoilerplate/integrationBoilerplate/Dockerfile +0 -38
  51. package/dist/integrationGenerator/integrationBoilerplate/integrationBoilerplate/README.md +0 -21
  52. package/dist/integrationGenerator/integrationBoilerplate/integrationBoilerplate/src/index.ts +0 -94
  53. package/dist/integrationGenerator/integrationBoilerplate/package.json +0 -43
  54. package/dist/integrationGenerator/integrationBoilerplate/src/logger.ts +0 -55
  55. package/dist/integrationGenerator/integrationBoilerplate/src/middlewares/additionalLoggingContext.ts +0 -22
  56. package/dist/integrationGenerator/integrationBoilerplate/src/middlewares/correlationId.ts +0 -13
  57. package/dist/integrationGenerator/integrationBoilerplate/src/middlewares/credentials.ts +0 -38
  58. package/dist/integrationGenerator/integrationBoilerplate/src/request.ts +0 -59
  59. package/dist/integrationGenerator/integrationBoilerplate/src/routes/index.ts +0 -11
  60. package/dist/integrationGenerator/integrationBoilerplate/src/routes/me.ts +0 -15
  61. package/dist/integrationGenerator/integrationBoilerplate/src/routes/root.ts +0 -12
  62. package/dist/integrationGenerator/integrationBoilerplate/tsconfig.json +0 -37
  63. package/dist/integrationGenerator/src/index.d.ts +0 -1
  64. package/dist/integrationGenerator/src/index.js +0 -5
  65. package/dist/integrationGenerator/src/resources/index.d.ts +0 -1
  66. package/dist/integrationGenerator/src/resources/index.js +0 -5
  67. package/dist/integrationGenerator/src/resources/integration.d.ts +0 -9
  68. package/dist/integrationGenerator/src/resources/integration.js +0 -60
  69. package/dist/integrationGenerator/test/resources/integration.test.js +0 -50
  70. package/dist/src/oauth2Helper/types.d.ts +0 -22
  71. package/dist/src/oauth2Helper/types.js +0 -2
  72. package/dist/src/services/oauth2Helper.d.ts +0 -4
  73. package/dist/src/services/oauth2Helper.js +0 -35
  74. package/dist/test/oauth2Helper/oauth2Helper.test.js +0 -150
  75. package/dist/test/services/oauth2Helper.test.js +0 -85
  76. /package/dist/{integrationGenerator/integrationBoilerplate → boilerplate}/.dockerignore +0 -0
  77. /package/dist/{integrationGenerator/integrationBoilerplate → boilerplate}/.eslintrc.js +0 -0
  78. /package/dist/{integrationGenerator/integrationBoilerplate → boilerplate}/.nvmrc +0 -0
  79. /package/dist/{integrationGenerator/integrationBoilerplate → boilerplate}/.prettierignore +0 -0
  80. /package/dist/{integrationGenerator/integrationBoilerplate → boilerplate}/.prettierrc +0 -0
  81. /package/dist/{integrationGenerator/integrationBoilerplate → boilerplate}/.unito.json +0 -0
  82. /package/dist/{integrationGenerator/integrationBoilerplate → boilerplate}/Dockerfile +0 -0
  83. /package/dist/{integrationGenerator/integrationBoilerplate → boilerplate}/README.md +0 -0
  84. /package/dist/{integrationGenerator/integrationBoilerplate/integrationBoilerplate → boilerplate}/package.json +0 -0
  85. /package/dist/{integrationGenerator/integrationBoilerplate/integrationBoilerplate → boilerplate}/src/logger.ts +0 -0
  86. /package/dist/{integrationGenerator/integrationBoilerplate/integrationBoilerplate → boilerplate}/src/middlewares/additionalLoggingContext.ts +0 -0
  87. /package/dist/{integrationGenerator/integrationBoilerplate/integrationBoilerplate → boilerplate}/src/middlewares/correlationId.ts +0 -0
  88. /package/dist/{integrationGenerator/integrationBoilerplate/integrationBoilerplate → boilerplate}/src/middlewares/credentials.ts +0 -0
  89. /package/dist/{integrationGenerator/integrationBoilerplate/integrationBoilerplate → boilerplate}/src/request.ts +0 -0
  90. /package/dist/{integrationGenerator/integrationBoilerplate/integrationBoilerplate → boilerplate}/src/routes/index.ts +0 -0
  91. /package/dist/{integrationGenerator/integrationBoilerplate/integrationBoilerplate → boilerplate}/src/routes/me.ts +0 -0
  92. /package/dist/{integrationGenerator/integrationBoilerplate/integrationBoilerplate → boilerplate}/src/routes/root.ts +0 -0
  93. /package/dist/{integrationGenerator/integrationBoilerplate/integrationBoilerplate → boilerplate}/tsconfig.json +0 -0
  94. /package/dist/{integrationGenerator/test/resources/integration.test.d.ts → test/resources/integrations.test.d.ts} +0 -0
  95. /package/dist/test/{oauth2Helper/oauth2Helper.test.d.ts → resources/oauth2.test.d.ts} +0 -0
  96. /package/dist/test/{services/oauth2Helper.test.d.ts → resources/template.test.d.ts} +0 -0
@@ -6,7 +6,7 @@ const core_1 = require("@oclif/core");
6
6
  const sinon = tslib_1.__importStar(require("sinon"));
7
7
  const inquirer_1 = tslib_1.__importDefault(require("inquirer"));
8
8
  const Configuration = tslib_1.__importStar(require("../../src/resources/configuration"));
9
- const oauth2Service = tslib_1.__importStar(require("../../src/services/oauth2Helper"));
9
+ const oauth2Service = tslib_1.__importStar(require("../../src/resources/oauth2"));
10
10
  const IntegrationsPlatform = tslib_1.__importStar(require("../../src/services/integrationsPlatform"));
11
11
  const decryptionResource = tslib_1.__importStar(require("../../src/resources/decryption"));
12
12
  const configurationTypes_1 = require("../../src/configurationTypes");
@@ -59,6 +59,7 @@ describe('oauth2', () => {
59
59
  });
60
60
  test_1.test
61
61
  .stdout()
62
+ .stderr()
62
63
  .do(() => getConfigurationsStub.returns({
63
64
  ...baseConfiguration,
64
65
  authorizations: [],
@@ -86,6 +87,7 @@ describe('oauth2', () => {
86
87
  (0, test_1.expect)(performOAuth2FlowStub.getCall(0).args).to.deep.equal([
87
88
  { ...oauth2Information, clientId: 'devClientID' },
88
89
  'production',
90
+ undefined,
89
91
  ]);
90
92
  (0, test_1.expect)(updateTokenStub.getCalls().length).to.equal(0);
91
93
  (0, test_1.expect)(writeTestAccountStub.getCall(0).args).to.deep.equal([
@@ -101,6 +103,8 @@ describe('oauth2', () => {
101
103
  },
102
104
  ],
103
105
  },
106
+ 'production',
107
+ undefined,
104
108
  credentials,
105
109
  'development',
106
110
  ]);
@@ -111,7 +115,13 @@ describe('oauth2', () => {
111
115
  .it('performs the oauth flow when there is no test accounts and the auth information are setup', () => {
112
116
  (0, test_1.expect)(performOAuth2FlowStub.getCalls().length).to.equal(1);
113
117
  (0, test_1.expect)(updateTokenStub.getCalls().length).to.equal(0);
114
- (0, test_1.expect)(writeTestAccountStub.getCall(0).args).to.deep.equal([baseConfiguration, credentials, 'development']);
118
+ (0, test_1.expect)(writeTestAccountStub.getCall(0).args).to.deep.equal([
119
+ baseConfiguration,
120
+ 'production',
121
+ undefined,
122
+ credentials,
123
+ 'development',
124
+ ]);
115
125
  });
116
126
  test_1.test
117
127
  .stdout()
@@ -132,6 +142,8 @@ describe('oauth2', () => {
132
142
  development: credentials,
133
143
  },
134
144
  },
145
+ 'production',
146
+ undefined,
135
147
  credentials,
136
148
  'development',
137
149
  ]);
@@ -155,6 +167,8 @@ describe('oauth2', () => {
155
167
  development: { something: 'something' },
156
168
  },
157
169
  },
170
+ 'production',
171
+ undefined,
158
172
  credentials,
159
173
  'compliance',
160
174
  ]);
@@ -178,6 +192,8 @@ describe('oauth2', () => {
178
192
  development: credentials,
179
193
  },
180
194
  },
195
+ 'production',
196
+ undefined,
181
197
  credentials,
182
198
  'development',
183
199
  ]);
@@ -241,6 +257,8 @@ describe('oauth2', () => {
241
257
  },
242
258
  },
243
259
  },
260
+ 'production',
261
+ undefined,
244
262
  {
245
263
  accessToken: `${Configuration.ENCRYPTION_PREFIX}encryptedAccessToken`,
246
264
  refreshToken: `${Configuration.ENCRYPTION_PREFIX}encryptedRefreshToken`,
@@ -258,6 +258,7 @@ describe('Publish', () => {
258
258
  });
259
259
  test_1.test
260
260
  .stdout()
261
+ .stderr()
261
262
  .stub(GlobalConfiguration, 'read', stub => stub.throws(new errors_1.NoConfigurationFileError()))
262
263
  .stub(FileSystem, 'getFileBuffer', stub => stub.resolves(Buffer.from('')))
263
264
  .command(['publish'])
@@ -8,6 +8,7 @@ const IntegrationsPlatform = tslib_1.__importStar(require("../../src/services/in
8
8
  const IntegrationsPlatformResource = tslib_1.__importStar(require("../../src/resources/integrationsPlatform"));
9
9
  const ConfigurationResource = tslib_1.__importStar(require("../../src/resources/configuration"));
10
10
  const IntegrationResource = tslib_1.__importStar(require("../../src/resources/integrations"));
11
+ const CredentialResource = tslib_1.__importStar(require("../../src/resources/credentials"));
11
12
  const errors_1 = require("../../src/errors");
12
13
  describe('Test', () => {
13
14
  const cliConfiguration = {
@@ -50,6 +51,7 @@ describe('Test', () => {
50
51
  });
51
52
  test_1.test
52
53
  .stdout()
54
+ .stderr()
53
55
  .stub(ConfigurationResource, 'getConfiguration', stub => stub.resolves(cliConfiguration))
54
56
  .stub(IntegrationResource, 'validateIsIntegrationDirectory', stub => stub.throws(new Error('boom!')))
55
57
  .command(['test'])
@@ -187,4 +189,24 @@ describe('Test', () => {
187
189
  .it('overrides --webhook-acknowledge-relative-url', () => {
188
190
  (0, test_1.expect)(spawnStub.getCall(0).args.at(1)).to.include('--webhook-acknowledge-relative-url=bar');
189
191
  });
192
+ test_1.test
193
+ .stdout()
194
+ .stub(ConfigurationResource, 'getConfiguration', stub => stub.resolves(cliConfiguration))
195
+ .stub(IntegrationResource, 'validateIsIntegrationDirectory', stub => stub.returns(true))
196
+ .stub(CredentialResource, 'fetchCredential', stub => stub.resolves({ payload: { from: 'credential' } }))
197
+ .command(['test', '--credential-id=123'])
198
+ .it('credential-id', () => {
199
+ (0, test_1.expect)(spawnStub.getCall(0).args.at(1)).to.include('--credential-payload={"from":"credential"}');
200
+ (0, test_1.expect)(spawnStub.getCall(0).args.at(1)).to.include('--read-only');
201
+ });
202
+ test_1.test
203
+ .stdout()
204
+ .stub(ConfigurationResource, 'getConfiguration', stub => stub.resolves(cliConfiguration))
205
+ .stub(IntegrationResource, 'validateIsIntegrationDirectory', stub => stub.returns(true))
206
+ .stub(CredentialResource, 'fetchCredential', stub => stub.resolves({ payload: { from: 'credential' } }))
207
+ .command(['test', '--credential-id=123', '--no-read-only'])
208
+ .it('credential-id && read-only', () => {
209
+ (0, test_1.expect)(spawnStub.getCall(0).args.at(1)).to.include('--credential-payload={"from":"credential"}');
210
+ (0, test_1.expect)(spawnStub.getCall(0).args.at(1)).to.not.include('--read-only');
211
+ });
190
212
  });
@@ -37,6 +37,7 @@ describe('Upgrade', () => {
37
37
  });
38
38
  test_1.test
39
39
  .stdout()
40
+ .stderr()
40
41
  .stub(child_process_1.default, 'execSync', stub => stub.throws(new errors_1.ConfigurationMalformed()))
41
42
  .command(['upgrade'])
42
43
  .exit(-1)
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const strict_1 = tslib_1.__importDefault(require("node:assert/strict"));
5
+ const path = tslib_1.__importStar(require("path"));
6
+ const tmp_1 = tslib_1.__importDefault(require("tmp"));
7
+ const fs_1 = tslib_1.__importDefault(require("fs"));
8
+ const Integration = tslib_1.__importStar(require("../../src/resources/integrations"));
9
+ const errors_1 = require("../../src/errors");
10
+ describe('integrations', () => {
11
+ let tempDir;
12
+ const boilerplatePath = path.join(__dirname, '../../boilerplate');
13
+ describe('copyBoilerplate', () => {
14
+ beforeEach(() => {
15
+ tempDir = tmp_1.default.dirSync().name;
16
+ });
17
+ it('copy files', async () => {
18
+ const result = await Integration.copyBoilerplate('foo', tempDir);
19
+ strict_1.default.equal(result, path.join(tempDir, 'foo'));
20
+ (0, strict_1.default)(fs_1.default.existsSync(result));
21
+ const expectedFiles = await fs_1.default.promises.readdir(boilerplatePath);
22
+ expectedFiles.push('.npmrc');
23
+ const createdFiles = await fs_1.default.promises.readdir(result);
24
+ strict_1.default.deepEqual(createdFiles, expectedFiles.sort());
25
+ createdFiles.forEach(createdField => (0, strict_1.default)(expectedFiles.includes(createdField)));
26
+ });
27
+ it('already exists', async () => {
28
+ strict_1.default.doesNotThrow(async () => await Integration.copyBoilerplate('foo', tempDir));
29
+ strict_1.default.rejects(Integration.copyBoilerplate('foo', tempDir), errors_1.IntegrationAlreadyExistsError);
30
+ });
31
+ it('generates an .npmrc file', async () => {
32
+ const result = await Integration.copyBoilerplate('foo', tempDir);
33
+ const npmrc = await fs_1.default.promises.readFile(`${result}/.npmrc`, 'utf-8');
34
+ (0, strict_1.default)(npmrc.includes('engine-strict=true'));
35
+ });
36
+ });
37
+ });
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const strict_1 = tslib_1.__importDefault(require("node:assert/strict"));
5
+ const sinon_1 = tslib_1.__importDefault(require("sinon"));
6
+ const oauth2_1 = tslib_1.__importDefault(require("../../src/services/oauth2"));
7
+ const configurationTypes_1 = require("../../src/configurationTypes");
8
+ const oauth2HelperResource = tslib_1.__importStar(require("../../src/resources/oauth2"));
9
+ const errors_1 = require("../../src/errors");
10
+ const inquirer_1 = tslib_1.__importDefault(require("inquirer"));
11
+ describe('OAuth2Helper', () => {
12
+ let fetchStub;
13
+ const authorizationInfo = {
14
+ clientId: 'your-client-id',
15
+ clientSecret: 'your-client-secret',
16
+ authorizationUrl: 'https://provider.com/oauth/authorize',
17
+ scopes: [{ name: 'scope1' }, { name: 'scope2' }],
18
+ tokenUrl: 'https://provider.com/oauth/token',
19
+ grantType: configurationTypes_1.GrantType.AUTHORIZATION_CODE,
20
+ requestContentType: configurationTypes_1.RequestContentType.URL_ENCODED,
21
+ responseContentType: configurationTypes_1.RequestContentType.JSON,
22
+ };
23
+ beforeEach(() => {
24
+ sinon_1.default.stub(oauth2_1.default.prototype, 'startServer').resolves('http://localhost:5050');
25
+ sinon_1.default.stub(oauth2_1.default.prototype, 'stopServer');
26
+ sinon_1.default.stub(oauth2_1.default.prototype, 'authorize');
27
+ sinon_1.default.stub(inquirer_1.default, 'prompt');
28
+ });
29
+ afterEach(() => {
30
+ sinon_1.default.restore();
31
+ });
32
+ describe('performOAuth2Flow', () => {
33
+ it('should perform the oauth flow', async () => {
34
+ fetchStub = sinon_1.default.stub().onFirstCall().resolves({ status: 200 }).onSecondCall().resolves({ status: 200 });
35
+ sinon_1.default.replace(global, 'fetch', fetchStub);
36
+ sinon_1.default.stub(oauth2_1.default.prototype, 'callbackIsDone').resolves({ accessToken: 'token' });
37
+ await oauth2HelperResource.performOAuth2Flow(authorizationInfo);
38
+ strict_1.default.equal(fetchStub.getCall(0).args.at(0), 'http://localhost:5050/health');
39
+ });
40
+ it('raises a FailedToRetrieveAccessTokenError', async () => {
41
+ fetchStub = sinon_1.default.stub().onFirstCall().resolves({ status: 200 }).onSecondCall().resolves({ status: 200 });
42
+ sinon_1.default.replace(global, 'fetch', fetchStub);
43
+ sinon_1.default.stub(oauth2_1.default.prototype, 'callbackIsDone').resolves({});
44
+ const response = oauth2HelperResource.performOAuth2Flow(authorizationInfo);
45
+ await strict_1.default.rejects(response, errors_1.FailedToRetrieveAccessTokenError);
46
+ });
47
+ it('raises a FailedToRetrieveAccessTokenError when the accessToken is not returned', async () => {
48
+ fetchStub = sinon_1.default.stub().onFirstCall().resolves({ status: 200 }).onSecondCall().resolves({ status: 200 });
49
+ sinon_1.default.replace(global, 'fetch', fetchStub);
50
+ sinon_1.default.stub(oauth2_1.default.prototype, 'callbackIsDone').resolves({});
51
+ const response = oauth2HelperResource.performOAuth2Flow(authorizationInfo);
52
+ await strict_1.default.rejects(response, errors_1.FailedToRetrieveAccessTokenError);
53
+ });
54
+ });
55
+ });
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const strict_1 = tslib_1.__importDefault(require("node:assert/strict"));
5
+ const node_test_1 = require("node:test");
6
+ const template_1 = require("../../src/resources/template");
7
+ (0, node_test_1.describe)('template', function () {
8
+ const context = {
9
+ var: 'value',
10
+ 'some.value': 'some',
11
+ some_value: 'value',
12
+ 'Some%20Thing': 'Some%20Thing',
13
+ foo: 'bar',
14
+ hello: 'Hello World!',
15
+ bool: 'false',
16
+ toString: 'string',
17
+ chars: 'šö䟜ñꀣ¥‡ÑÒÓÔÕÖרÙÚàáâãäåæçÿü',
18
+ path: '/foo/bar',
19
+ surrogatepairs: '\uD834\uDF06',
20
+ };
21
+ (0, node_test_1.it)('empty string', function () {
22
+ strict_1.default.equal((0, template_1.parseTemplate)('').expand(context), '');
23
+ });
24
+ (0, node_test_1.it)('does not encode non expressions', function () {
25
+ strict_1.default.equal((0, template_1.parseTemplate)('hello/world').expand(context), 'hello/world');
26
+ strict_1.default.equal((0, template_1.parseTemplate)('Hello World!/{foo}').expand(context), 'Hello%20World!/{foo}');
27
+ });
28
+ (0, node_test_1.it)('expand non-ASCII strings', function () {
29
+ strict_1.default.equal((0, template_1.parseTemplate)('{+chars}').expand(context), '%C5%A1%C3%B6%C3%A4%C5%B8%C5%93%C3%B1%C3%AA%E2%82%AC%C2%A3%C2%A5%E2%80%A1%C3%91%C3%92%C3%93%C3%94%C3%95%C3%96%C3%97%C3%98%C3%99%C3%9A%C3%A0%C3%A1%C3%A2%C3%A3%C3%A4%C3%A5%C3%A6%C3%A7%C3%BF%C3%BC');
30
+ });
31
+ (0, node_test_1.it)('reserved expansion of basic strings', function () {
32
+ strict_1.default.equal((0, template_1.parseTemplate)('{+var}').expand(context), 'value');
33
+ strict_1.default.equal((0, template_1.parseTemplate)('{+hello}').expand(context), 'Hello%20World!');
34
+ strict_1.default.equal((0, template_1.parseTemplate)('{+Some%20Thing}').expand(context), 'Some%20Thing');
35
+ });
36
+ (0, node_test_1.it)('preserves paths', function () {
37
+ strict_1.default.equal((0, template_1.parseTemplate)('{+path}/here').expand(context), '/foo/bar/here');
38
+ strict_1.default.equal((0, template_1.parseTemplate)('here?ref={+path}').expand(context), 'here?ref=/foo/bar');
39
+ });
40
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ /* eslint-disable @typescript-eslint/no-explicit-any */
5
+ const strict_1 = tslib_1.__importDefault(require("node:assert/strict"));
6
+ const sinon_1 = tslib_1.__importDefault(require("sinon"));
7
+ const oauth2_1 = tslib_1.__importStar(require("../../src/services/oauth2")), oauth2Namespace = oauth2_1;
8
+ const configurationTypes_1 = require("../../src/configurationTypes");
9
+ const errors_1 = require("../../src/errors");
10
+ const globalConfiguration_1 = require("../../src/resources/globalConfiguration");
11
+ describe('OAuth2Helper', () => {
12
+ let oauth2Helper;
13
+ let openSpy;
14
+ let fetchStub;
15
+ describe('constructor', () => {
16
+ it('should throw an error if the request content type is not supported', async () => {
17
+ try {
18
+ new oauth2_1.default({ scopes: [], requestContentType: 'random' });
19
+ }
20
+ catch (err) {
21
+ (0, strict_1.default)(err instanceof errors_1.UnsupportedContentTypeError);
22
+ }
23
+ });
24
+ });
25
+ describe('method', () => {
26
+ beforeEach(() => {
27
+ const authorizationInfo = {
28
+ clientId: 'your-client-id',
29
+ clientSecret: 'your-client-secret',
30
+ authorizationUrl: 'https://provider.com/oauth/authorize',
31
+ scopes: [{ name: 'scope1' }, { name: 'scope2' }],
32
+ tokenUrl: 'https://provider.com/oauth/token',
33
+ grantType: configurationTypes_1.GrantType.AUTHORIZATION_CODE,
34
+ requestContentType: configurationTypes_1.RequestContentType.URL_ENCODED,
35
+ responseContentType: configurationTypes_1.RequestContentType.JSON,
36
+ tokenRequestParameters: {
37
+ header: {
38
+ Authorization: 'custom',
39
+ },
40
+ },
41
+ };
42
+ oauth2Helper = new oauth2_1.default(authorizationInfo, globalConfiguration_1.Environment.Production, { foo: 'fooValue', bar: 'barValue' });
43
+ fetchStub = sinon_1.default.stub().resolves({ json: sinon_1.default.stub().resolves({}), status: 200 });
44
+ sinon_1.default.stub(oauth2Helper, 'startServer').resolves('http://localhost:5050');
45
+ sinon_1.default.stub(oauth2Helper, 'stopServer');
46
+ sinon_1.default.replace(global, 'fetch', fetchStub);
47
+ sinon_1.default.replace(oauth2Namespace, 'open', { open: (_url) => undefined });
48
+ openSpy = sinon_1.default.stub(oauth2Namespace.open, 'open');
49
+ });
50
+ afterEach(() => {
51
+ sinon_1.default.restore();
52
+ });
53
+ describe('authorize', () => {
54
+ it('should open the authorization URL', async () => {
55
+ await oauth2Helper.authorize();
56
+ sinon_1.default.assert.calledOnce(openSpy);
57
+ sinon_1.default.assert.calledWith(openSpy, 'https://provider.com/oauth/authorize?client_id=your-client-id&scope=scope1+scope2&state=eyJjbGlDYWxsYmFja1VybCI6Ii9vYXV0aDIvY2FsbGJhY2sifQ%3D%3D&response_type=code&redirect_uri=https%3A%2F%2Fintegrations-platform.unito.io%2Fcredentials%2Fnew%2Foauth2%2Fcallback-cli');
58
+ });
59
+ it('should maintain the pre-existing query parameters in authorization URL', async () => {
60
+ oauth2Helper['providerAuthorizationUrl'] = 'https://provider.com/oauth/authorize?query1=value1&query2=value2';
61
+ await oauth2Helper.authorize();
62
+ sinon_1.default.assert.calledOnce(openSpy);
63
+ sinon_1.default.assert.calledWith(openSpy, 'https://provider.com/oauth/authorize?query1=value1&query2=value2&client_id=your-client-id&scope=scope1+scope2&state=eyJjbGlDYWxsYmFja1VybCI6Ii9vYXV0aDIvY2FsbGJhY2sifQ%3D%3D&response_type=code&redirect_uri=https%3A%2F%2Fintegrations-platform.unito.io%2Fcredentials%2Fnew%2Foauth2%2Fcallback-cli');
64
+ });
65
+ it('should support dynamic params', async () => {
66
+ oauth2Helper['providerAuthorizationUrl'] = 'https://pro-{+foo}-der.com/oauth/authorize?query1={+bar}';
67
+ await oauth2Helper.authorize();
68
+ sinon_1.default.assert.calledOnce(openSpy);
69
+ sinon_1.default.assert.calledWith(openSpy, 'https://pro-fooValue-der.com/oauth/authorize?query1=barValue&client_id=your-client-id&scope=scope1+scope2&state=eyJjbGlDYWxsYmFja1VybCI6Ii9vYXV0aDIvY2FsbGJhY2sifQ%3D%3D&response_type=code&redirect_uri=https%3A%2F%2Fintegrations-platform.unito.io%2Fcredentials%2Fnew%2Foauth2%2Fcallback-cli');
70
+ });
71
+ });
72
+ describe('handleCallback', () => {
73
+ it('should retrieve the access token and return it in the response', async () => {
74
+ const code = 'test-code';
75
+ const req = { query: { code } };
76
+ const res = { send: sinon_1.default.stub(), setHeader: sinon_1.default.stub() };
77
+ await oauth2Helper['handleCallback'](req, res);
78
+ sinon_1.default.assert.calledOnce(fetchStub);
79
+ sinon_1.default.assert.calledWith(fetchStub, 'https://provider.com/oauth/token', {
80
+ headers: {
81
+ 'Content-Type': 'application/x-www-form-urlencoded',
82
+ Authorization: 'custom',
83
+ },
84
+ body: sinon_1.default.match.string,
85
+ method: 'POST',
86
+ });
87
+ sinon_1.default.assert.calledOnce(res.send);
88
+ sinon_1.default.assert.calledWith(res.send, oauth2Namespace.HTML_SUCCESS_MSG);
89
+ });
90
+ it('should handle dynamic variables with values from provider response and credential payload', async () => {
91
+ oauth2Helper['tokenUrl'] = 'https://{+foo}.com/oauth/token?specialParam={+authorizationResponse.responseValue}';
92
+ const code = 'test-code';
93
+ const req = { query: { code, responseValue: 'DynamicValue' } };
94
+ const res = { send: sinon_1.default.stub(), setHeader: sinon_1.default.stub() };
95
+ await oauth2Helper['handleCallback'](req, res);
96
+ sinon_1.default.assert.calledOnce(fetchStub);
97
+ sinon_1.default.assert.calledWith(fetchStub, 'https://fooValue.com/oauth/token?specialParam=DynamicValue', {
98
+ headers: {
99
+ 'Content-Type': 'application/x-www-form-urlencoded',
100
+ Authorization: 'custom',
101
+ },
102
+ body: sinon_1.default.match.string,
103
+ method: 'POST',
104
+ });
105
+ sinon_1.default.assert.calledOnce(res.send);
106
+ sinon_1.default.assert.calledWith(res.send, oauth2Namespace.HTML_SUCCESS_MSG);
107
+ });
108
+ it('should handle errors and return 500 status', async () => {
109
+ const code = 'test-code';
110
+ const req = { query: { code } };
111
+ const res = { send: sinon_1.default.stub(), setHeader: sinon_1.default.stub() };
112
+ fetchStub.rejects(new Error('Failed to retrieve access token'));
113
+ await oauth2Helper['handleCallback'](req, res);
114
+ sinon_1.default.assert.calledOnce(res.send);
115
+ sinon_1.default.assert.calledWith(res.send, oauth2Namespace.HTML_ERROR_MSG);
116
+ });
117
+ });
118
+ describe('updateToken', () => {
119
+ it('should retrieve the access token when a refresh token is available', async () => {
120
+ const refreshToken = 'test-refresh-token';
121
+ const accessToken = 'test-access-token';
122
+ const fetchResponse = { access_token: accessToken, refresh_token: refreshToken };
123
+ fetchStub.resolves({ status: 200, json: sinon_1.default.stub().resolves(fetchResponse) });
124
+ const result = await oauth2Helper.updateToken(refreshToken);
125
+ strict_1.default.deepEqual(result, { accessToken, refreshToken });
126
+ sinon_1.default.assert.calledOnce(fetchStub);
127
+ });
128
+ it('should throw an error when failing to refresh the access token', async () => {
129
+ const refreshToken = 'test-refresh-token';
130
+ fetchStub.rejects(new Error('Failed to retrieve access token'));
131
+ const response = oauth2Helper.updateToken(refreshToken);
132
+ await strict_1.default.rejects(response, errors_1.FailedToRetrieveAccessTokenError);
133
+ sinon_1.default.assert.calledOnce(fetchStub);
134
+ });
135
+ it("should throw an error if we don't support the request content type", async () => {
136
+ const refreshToken = 'test-refresh-token';
137
+ oauth2Helper['requestContentType'] = 'random';
138
+ const response = oauth2Helper.updateToken(refreshToken);
139
+ await strict_1.default.rejects(response, errors_1.InvalidRequestContentTypeError);
140
+ });
141
+ });
142
+ describe('encodeBody', () => {
143
+ it('should encode body data as URL-encoded when content type is URL_ENCODED', () => {
144
+ const bodyData = { key1: 'value1', key2: 'value2' };
145
+ const contentType = configurationTypes_1.RequestContentType.URL_ENCODED;
146
+ const expectedEncodedBody = 'key1=value1&key2=value2';
147
+ const encodedBody = oauth2Helper['encodeBody'](bodyData, contentType);
148
+ strict_1.default.equal(encodedBody, expectedEncodedBody);
149
+ });
150
+ it('should encode body data as JSON when content type is JSON', () => {
151
+ const bodyData = { key1: 'value1', key2: 'value2' };
152
+ const contentType = configurationTypes_1.RequestContentType.JSON;
153
+ const expectedEncodedBody = JSON.stringify(bodyData);
154
+ const encodedBody = oauth2Helper['encodeBody'](bodyData, contentType);
155
+ strict_1.default.equal(encodedBody, expectedEncodedBody);
156
+ });
157
+ });
158
+ });
159
+ });
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.57.2",
2
+ "version": "0.58.1",
3
3
  "commands": {
4
4
  "activity": {
5
5
  "id": "activity",
@@ -74,6 +74,41 @@
74
74
  "description": "output more (debug) information",
75
75
  "allowNo": false
76
76
  },
77
+ "credential-payload": {
78
+ "name": "credential-payload",
79
+ "type": "option",
80
+ "description": "(advanced) credential payload to use.",
81
+ "multiple": false,
82
+ "exclusive": [
83
+ "credential-id"
84
+ ]
85
+ },
86
+ "credential-id": {
87
+ "name": "credential-id",
88
+ "type": "option",
89
+ "description": "(advanced) credential to use.",
90
+ "multiple": false,
91
+ "exclusive": [
92
+ "credential-payload"
93
+ ]
94
+ },
95
+ "test-account": {
96
+ "name": "test-account",
97
+ "type": "option",
98
+ "description": "test account to use.",
99
+ "multiple": false,
100
+ "options": [
101
+ "development",
102
+ "compliance"
103
+ ],
104
+ "default": "development"
105
+ },
106
+ "read-only": {
107
+ "name": "read-only",
108
+ "type": "boolean",
109
+ "description": "whether or not to only perform read operations",
110
+ "allowNo": true
111
+ },
77
112
  "crawlMode": {
78
113
  "name": "crawlMode",
79
114
  "type": "option",
@@ -209,15 +244,16 @@
209
244
  },
210
245
  "oauth2": {
211
246
  "id": "oauth2",
212
- "summary": "Perform an OAuth2 workflow locally",
213
- "description": "The Oauth2 command allows you to perform an OAuth2 workflow locally, either to create a new test account or to refresh an existing one.",
247
+ "summary": "Perform an OAuth2 workflow to either populate or refresh a test account's credentials.",
248
+ "description": "The Oauth2 command allows you to perform an OAuth2 workflow to populate the specified test account's accessToken and refreshToken to be used by the 'test' and 'dev' commands.\n\n If the test-account is already populated, the command will refresh the credentials if the refresh token is available.\n If you want to force a new OAuth2 flow to change the connected account or something else, use the --reauth flag.",
214
249
  "strict": true,
215
250
  "pluginName": "@unito/integration-cli",
216
251
  "pluginAlias": "@unito/integration-cli",
217
252
  "pluginType": "core",
218
253
  "aliases": [],
219
254
  "examples": [
220
- "<%= config.bin %> <%= command.id %>"
255
+ "<%= config.bin %> <%= command.id %>",
256
+ "<%= config.bin %> <%= command.id %> --reauth --test-account=compliance"
221
257
  ],
222
258
  "flags": {
223
259
  "test-account": {
@@ -235,6 +271,7 @@
235
271
  "name": "environment",
236
272
  "type": "option",
237
273
  "description": "the environment of the platform",
274
+ "hidden": true,
238
275
  "multiple": false,
239
276
  "options": [
240
277
  "local",
@@ -246,7 +283,7 @@
246
283
  "reauth": {
247
284
  "name": "reauth",
248
285
  "type": "boolean",
249
- "description": "triggers a new oauth2 flow to collect credentials and overwrite the current one",
286
+ "description": "triggers a new oauth2 flow to overwrite the test account's current credentials",
250
287
  "allowNo": false
251
288
  },
252
289
  "config-path": {
@@ -394,13 +431,25 @@
394
431
  "credential-payload": {
395
432
  "name": "credential-payload",
396
433
  "type": "option",
434
+ "description": "(advanced) credential payload to use.",
435
+ "multiple": false,
436
+ "exclusive": [
437
+ "credential-id"
438
+ ]
439
+ },
440
+ "credential-id": {
441
+ "name": "credential-id",
442
+ "type": "option",
397
443
  "description": "(advanced) credential to use.",
398
- "multiple": false
444
+ "multiple": false,
445
+ "exclusive": [
446
+ "credential-payload"
447
+ ]
399
448
  },
400
449
  "test-account": {
401
450
  "name": "test-account",
402
451
  "type": "option",
403
- "description": "Test account to use.",
452
+ "description": "test account to use.",
404
453
  "multiple": false,
405
454
  "options": [
406
455
  "development",
@@ -408,6 +457,12 @@
408
457
  ],
409
458
  "default": "development"
410
459
  },
460
+ "read-only": {
461
+ "name": "read-only",
462
+ "type": "boolean",
463
+ "description": "whether or not to only perform read operations",
464
+ "allowNo": true
465
+ },
411
466
  "crawlMode": {
412
467
  "name": "crawlMode",
413
468
  "type": "option",
@@ -430,7 +485,7 @@
430
485
  "debug": {
431
486
  "name": "debug",
432
487
  "type": "boolean",
433
- "description": "Log launch command to console before running it - including decrypted values - for debugging only",
488
+ "description": "log launch command to console before running it - including decrypted values - for debugging only",
434
489
  "hidden": true,
435
490
  "allowNo": false
436
491
  },
@@ -438,7 +493,7 @@
438
493
  "name": "config-path",
439
494
  "type": "option",
440
495
  "summary": "relative path to a custom \".unito.json\" file",
441
- "description": "Use a custom configuration file instead of the default '.unito.json' or other environment specific\n ones.\n\n If you want to force the CLI to use a specific configuration file, you can use this flag to specify the relative\n path from your integration's root folder (with a leading '/').\n\n Usage: <%= config.bin %> <%= command.id %> --config-path=/myCustomConfig.json",
496
+ "description": "use a custom configuration file instead of the default '.unito.json' or other environment specific\n ones.\n\n If you want to force the CLI to use a specific configuration file, you can use this flag to specify the relative\n path from your integration's root folder (with a leading '/').\n\n Usage: <%= config.bin %> <%= command.id %> --config-path=/myCustomConfig.json",
442
497
  "multiple": false
443
498
  }
444
499
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unito/integration-cli",
3
- "version": "0.57.2",
3
+ "version": "0.58.1",
4
4
  "description": "Integration CLI",
5
5
  "bin": {
6
6
  "integration-cli": "./bin/run"
@@ -13,18 +13,18 @@
13
13
  "email": "hello@unito.io"
14
14
  },
15
15
  "engines": {
16
- "node": ">=18.0.0"
16
+ "node": ">=20.0.0"
17
17
  },
18
18
  "scripts": {
19
19
  "prepublishOnly": "npm run lint && npm run test",
20
20
  "prepack": "oclif manifest",
21
21
  "postpack": "shx rm -f oclif.manifest.json",
22
22
  "prepare": "npm run compile",
23
- "lint": "eslint --fix src test scripts integrationGenerator/src integrationGenerator/test --ext .ts && prettier --write src test scripts integrationGenerator/src integrationGenerator/test",
24
- "compile": "ts-node scripts/generateTypes.ts > src/configurationTypes.ts && tsc -b && mkdir -p dist/schemas && cp schemas/*.json dist/schemas/ && cp -r integrationGenerator/integrationBoilerplate ./dist/integrationGenerator/integrationBoilerplate",
23
+ "lint": "eslint --fix src test scripts --ext .ts && prettier --write src test scripts",
24
+ "compile": "rm -rf dist && ts-node scripts/generateTypes.ts > src/configurationTypes.ts && tsc -b && mkdir -p dist/schemas && cp schemas/*.json dist/schemas/ && cp -r boilerplate ./dist/boilerplate",
25
25
  "compile:watch": "tsc --build -w",
26
- "test": "mocha $(find test -name '*.test.ts') $(find integrationGenerator/test -name '*.test.ts')",
27
- "test:debug": "mocha test/**/*.test.ts integrationGenerator/test/**/*.test.ts --inspect-brk",
26
+ "test": "mocha \"test/**/*.test.ts\"",
27
+ "test:debug": "mocha --inspect-brk \"test/**/*.test.ts\"",
28
28
  "ci:test": "c8 npm run test"
29
29
  },
30
30
  "files": [
@@ -38,7 +38,7 @@
38
38
  "@oclif/core": "3.x",
39
39
  "@typescript-eslint/eslint-plugin": "6.x",
40
40
  "@typescript-eslint/parser": "6.13.x",
41
- "@unito/integration-debugger": "0.23.0",
41
+ "@unito/integration-debugger": "0.24.0",
42
42
  "@unito/integrations-platform-client": "0.46.1",
43
43
  "ajv": "8.x",
44
44
  "ajv-formats": "2.x",
@@ -62,7 +62,7 @@
62
62
  "@types/gradient-string": "1.x",
63
63
  "@types/inquirer": "9.x",
64
64
  "@types/mocha": "10.x",
65
- "@types/node": "18.x",
65
+ "@types/node": "20.x",
66
66
  "@types/openurl": "1.x",
67
67
  "@types/tmp": "0.x",
68
68
  "c8": "9.x",
@@ -1,2 +0,0 @@
1
- export declare class AlreadyExistingIntegrationError extends Error {
2
- }
@@ -1,6 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AlreadyExistingIntegrationError = void 0;
4
- class AlreadyExistingIntegrationError extends Error {
5
- }
6
- exports.AlreadyExistingIntegrationError = AlreadyExistingIntegrationError;
@@ -1,2 +0,0 @@
1
- export * from './src';
2
- export * from './errors';