@emilgroup/action-sdk-node 1.0.1-beta.20

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.
@@ -0,0 +1,16 @@
1
+ .gitignore
2
+ .npmignore
3
+ .openapi-generator-ignore
4
+ README.md
5
+ api.ts
6
+ api/default-api.ts
7
+ base.ts
8
+ common.ts
9
+ configuration.ts
10
+ git_push.sh
11
+ index.ts
12
+ models/index.ts
13
+ models/inline-response200.ts
14
+ models/inline-response503.ts
15
+ package.json
16
+ tsconfig.json
@@ -0,0 +1 @@
1
+ 5.4.0
@@ -0,0 +1,23 @@
1
+ # OpenAPI Generator Ignore
2
+ # Generated by openapi-generator https://github.com/openapitools/openapi-generator
3
+
4
+ # Use this file to prevent files from being overwritten by the generator.
5
+ # The patterns follow closely to .gitignore or .dockerignore.
6
+
7
+ # As an example, the C# client generator defines ApiClient.cs.
8
+ # You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
9
+ #ApiClient.cs
10
+
11
+ # You can match any string of characters against a directory, file or extension with a single asterisk (*):
12
+ #foo/*/qux
13
+ # The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
14
+
15
+ # You can recursively match patterns against a directory, file or extension with a double asterisk (**):
16
+ #foo/**/qux
17
+ # This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
18
+
19
+ # You can also negate patterns with an exclamation (!).
20
+ # For example, you can ignore all files in a docs folder with the file extension .md:
21
+ #docs/*.md
22
+ # Then explicitly reverse the ignore rule for a single file:
23
+ #!docs/README.md
package/README.md ADDED
@@ -0,0 +1,84 @@
1
+ # Emil Action SDK for Nodejs
2
+
3
+ This TypeScript/JavaScript client utilizes [axios](https://github.com/axios/axios). The generated Node module can be used with Nodejs based applications.
4
+
5
+ Language level
6
+ * ES5 - you must have a Promises/A+ library installed
7
+ * ES6
8
+
9
+ Module system
10
+ * CommonJS
11
+ * ES6 module system
12
+
13
+ Although this package can be used in both TypeScript and JavaScript, it is intended to be used with TypeScript. The definition should be automatically resolved via `package.json`. ([Reference](http://www.typescriptlang.org/docs/handbook/typings-for-npm-packages.html)). For more information, you can go to [Emil Api documentation](https://emil.stoplight.io/docs/emil-api/).
14
+
15
+ ## Consuming
16
+
17
+ Navigate to the folder of your consuming project and run one of the following commands:
18
+
19
+ ```
20
+ npm install @emilgroup/action-sdk-node@1.0.1-beta.20 --save
21
+ ```
22
+ or
23
+ ```
24
+ yarn add @emilgroup/action-sdk-node@1.0.1-beta.20
25
+ ```
26
+
27
+ And then you can import `ActionsApi`.
28
+
29
+ ```ts
30
+ import { ActionsApi } from '@emilgroup/action-sdk-node'
31
+
32
+ const actionsApi = new ActionsApi();
33
+ ```
34
+ ## Credentials
35
+
36
+ To use authentication protected endpoints, you have to first authorize. To do so, the easiest way is to provide a configuration file under `~/.emil/credentials` with the following content:
37
+
38
+ ```shell
39
+ emil_username=XXXXX@XXXX.XXX
40
+ emil_password=XXXXXXXXXXXXXX
41
+ ```
42
+
43
+ It is also possible to provide environment variables instead:
44
+
45
+ ```shell
46
+ export EMIL_USERNAME=XXXXX@XXXX.XXX
47
+ export EMIL_PASSWORD=XXXXXXXXXXXXXX
48
+ ```
49
+
50
+ ## Base path
51
+
52
+ To select the basic path for using the API, we can use two approaches. The first is to use one of the predefined environments, and the second is to specify the domain as a string.
53
+
54
+ ```ts
55
+ import { ActionsApi, Environment } from '@emilgroup/action-sdk-node'
56
+
57
+ const actionsApi = new ActionsApi();
58
+
59
+ // Allows you to simply choose environment. It will usually be Environment.Production.
60
+ actionsApi.selectEnvironment(Environment.Production);
61
+
62
+ // For advanced users, use the custom baseUrl of the website you need to connect to.
63
+ actionsApi.selectBasePath('https://my-custom-domain.com');
64
+ ```
65
+
66
+ ## Example
67
+
68
+ Here is a basic functionning example:
69
+
70
+ ```ts
71
+ async function listActions(): Promise<Void> {
72
+ try {
73
+ const actionsApi = new ActionsApi();
74
+
75
+ await actionsApi.initialize(); // should be called only once per Api.
76
+
77
+ const { data: { items } } = await actionsApi.listActions();
78
+
79
+ console.log(items);
80
+ } catch(error) {
81
+ // process error
82
+ }
83
+ }
84
+ ```
@@ -0,0 +1,128 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ /**
4
+ * EMIL ActionService
5
+ * The EMIL ActionService API description
6
+ *
7
+ * The version of the OpenAPI document: 1.0
8
+ * Contact: kontakt@emil.de
9
+ *
10
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
11
+ * https://openapi-generator.tech
12
+ * Do not edit the class manually.
13
+ */
14
+
15
+
16
+ import globalAxios, { AxiosPromise, AxiosInstance, AxiosRequestConfig } from 'axios';
17
+ import { Configuration } from '../configuration';
18
+ // Some imports not used depending on template conditions
19
+ // @ts-ignore
20
+ import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from '../common';
21
+ // @ts-ignore
22
+ import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError } from '../base';
23
+ // @ts-ignore
24
+ import { InlineResponse200 } from '../models';
25
+ // @ts-ignore
26
+ import { InlineResponse503 } from '../models';
27
+ // URLSearchParams not necessarily used
28
+ // @ts-ignore
29
+ import { URL, URLSearchParams } from 'url';
30
+ const FormData = require('form-data');
31
+ /**
32
+ * DefaultApi - axios parameter creator
33
+ * @export
34
+ */
35
+ export const DefaultApiAxiosParamCreator = function (configuration?: Configuration) {
36
+ return {
37
+ /**
38
+ * Returns the health status of the ActionService service. This endpoint is used to monitor the operational status of the ActionService service. It typically returns a simple status indicator, such as \'UP\' or \'OK\', confirming that the service is operational and available.
39
+ * @summary Health Check
40
+ * @param {*} [options] Override http request option.
41
+ * @throws {RequiredError}
42
+ */
43
+ check: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
44
+ const localVarPath = `/actionservice/health`;
45
+ // use dummy base URL string because the URL constructor only accepts absolute URLs.
46
+ const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
47
+ let baseOptions;
48
+ let baseAccessToken;
49
+ if (configuration) {
50
+ baseOptions = configuration.baseOptions;
51
+ baseAccessToken = configuration.accessToken;
52
+ }
53
+
54
+ const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
55
+ const localVarHeaderParameter = {} as any;
56
+ const localVarQueryParameter = {} as any;
57
+
58
+
59
+
60
+ setSearchParams(localVarUrlObj, localVarQueryParameter);
61
+ let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
62
+ localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
63
+
64
+ return {
65
+ url: toPathString(localVarUrlObj),
66
+ options: localVarRequestOptions,
67
+ };
68
+ },
69
+ }
70
+ };
71
+
72
+ /**
73
+ * DefaultApi - functional programming interface
74
+ * @export
75
+ */
76
+ export const DefaultApiFp = function(configuration?: Configuration) {
77
+ const localVarAxiosParamCreator = DefaultApiAxiosParamCreator(configuration)
78
+ return {
79
+ /**
80
+ * Returns the health status of the ActionService service. This endpoint is used to monitor the operational status of the ActionService service. It typically returns a simple status indicator, such as \'UP\' or \'OK\', confirming that the service is operational and available.
81
+ * @summary Health Check
82
+ * @param {*} [options] Override http request option.
83
+ * @throws {RequiredError}
84
+ */
85
+ async check(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse200>> {
86
+ const localVarAxiosArgs = await localVarAxiosParamCreator.check(options);
87
+ return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
88
+ },
89
+ }
90
+ };
91
+
92
+ /**
93
+ * DefaultApi - factory interface
94
+ * @export
95
+ */
96
+ export const DefaultApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
97
+ const localVarFp = DefaultApiFp(configuration)
98
+ return {
99
+ /**
100
+ * Returns the health status of the ActionService service. This endpoint is used to monitor the operational status of the ActionService service. It typically returns a simple status indicator, such as \'UP\' or \'OK\', confirming that the service is operational and available.
101
+ * @summary Health Check
102
+ * @param {*} [options] Override http request option.
103
+ * @throws {RequiredError}
104
+ */
105
+ check(options?: any): AxiosPromise<InlineResponse200> {
106
+ return localVarFp.check(options).then((request) => request(axios, basePath));
107
+ },
108
+ };
109
+ };
110
+
111
+ /**
112
+ * DefaultApi - object-oriented interface
113
+ * @export
114
+ * @class DefaultApi
115
+ * @extends {BaseAPI}
116
+ */
117
+ export class DefaultApi extends BaseAPI {
118
+ /**
119
+ * Returns the health status of the ActionService service. This endpoint is used to monitor the operational status of the ActionService service. It typically returns a simple status indicator, such as \'UP\' or \'OK\', confirming that the service is operational and available.
120
+ * @summary Health Check
121
+ * @param {*} [options] Override http request option.
122
+ * @throws {RequiredError}
123
+ * @memberof DefaultApi
124
+ */
125
+ public check(options?: AxiosRequestConfig) {
126
+ return DefaultApiFp(this.configuration).check(options).then((request) => request(this.axios, this.basePath));
127
+ }
128
+ }
package/api.ts ADDED
@@ -0,0 +1,31 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ /**
4
+ * EMIL ActionService
5
+ * The EMIL ActionService API description
6
+ *
7
+ * The version of the OpenAPI document: 1.0
8
+ * Contact: kontakt@emil.de
9
+ *
10
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
11
+ * https://openapi-generator.tech
12
+ * Do not edit the class manually.
13
+ */
14
+
15
+
16
+ import { Configuration } from './configuration';
17
+ import globalAxios, { AxiosPromise, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
18
+ // URLSearchParams not necessarily used
19
+ // @ts-ignore
20
+ import { URL, URLSearchParams } from 'url';
21
+ import FormData from 'form-data'
22
+ // Some imports not used depending on template conditions
23
+ // @ts-ignore
24
+ import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from './common';
25
+ // @ts-ignore
26
+ import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError } from './base';
27
+ import { DefaultApi } from './api';
28
+
29
+
30
+ export * from './api/default-api';
31
+
package/base.ts ADDED
@@ -0,0 +1,327 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ /**
4
+ * EMIL ActionService
5
+ * The EMIL ActionService API description
6
+ *
7
+ * The version of the OpenAPI document: 1.0
8
+ * Contact: kontakt@emil.de
9
+ *
10
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
11
+ * https://openapi-generator.tech
12
+ * Do not edit the class manually.
13
+ */
14
+
15
+
16
+ import { Configuration } from "./configuration";
17
+ // Some imports not used depending on template conditions
18
+ // @ts-ignore
19
+ import globalAxios, { AxiosPromise, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
20
+ import * as fs from 'fs';
21
+ import * as path from 'path';
22
+ import * as os from 'os';
23
+
24
+ export const BASE_PATH = "https://apiv2.emil.de".replace(/\/+$/, "");
25
+ const CONFIG_DIRECTORY = '.emil';
26
+ const CONFIG_FILENAME = 'credentials';
27
+ const KEY_USERNAME = 'emil_username';
28
+ const KEY_PASSWORD = 'emil_password';
29
+
30
+ const filePath = os.homedir() + path.sep + CONFIG_DIRECTORY + path.sep + CONFIG_FILENAME;
31
+ /**
32
+ *
33
+ * @export
34
+ */
35
+ export const COLLECTION_FORMATS = {
36
+ csv: ",",
37
+ ssv: " ",
38
+ tsv: "\t",
39
+ pipes: "|",
40
+ };
41
+
42
+ export interface LoginClass {
43
+ accessToken: string;
44
+ permissions: string;
45
+ }
46
+
47
+ export interface SwitchWorkspaceRequest {
48
+ username: string;
49
+ targetWorkspace: string;
50
+ }
51
+
52
+ export interface SwitchWorkspaceResponseClass {
53
+ accessToken: string;
54
+ permissions: string;
55
+ }
56
+
57
+ export enum Environment {
58
+ Production = 'https://apiv2.emil.de',
59
+ Test = 'https://apiv2-test.emil.de',
60
+ Staging = 'https://apiv2-staging.emil.de',
61
+ Development = 'https://apiv2-dev.emil.de',
62
+ ProductionZurich = 'https://eu-central-2.apiv2.emil.de',
63
+ }
64
+
65
+ let _retry_count = 0
66
+ let _retry = null
67
+
68
+ export function resetRetry() {
69
+ _retry_count = 0
70
+ }
71
+
72
+ /**
73
+ *
74
+ * @export
75
+ * @interface RequestArgs
76
+ */
77
+ export interface RequestArgs {
78
+ url: string;
79
+ options: AxiosRequestConfig;
80
+ }
81
+
82
+ const NETWORK_ERROR_MESSAGE = "Network Error";
83
+
84
+ /**
85
+ *
86
+ * @export
87
+ * @class BaseAPI
88
+ */
89
+ export class BaseAPI {
90
+ protected configuration: Configuration;
91
+ private username?: string;
92
+ private password?: string;
93
+
94
+ constructor(configuration?: Configuration, protected basePath: string = BASE_PATH, protected axios: AxiosInstance = globalAxios) {
95
+ if (configuration) {
96
+ this.configuration = configuration;
97
+ this.basePath = configuration.basePath || this.basePath;
98
+ } else {
99
+ this.configuration = new Configuration({
100
+ basePath: this.basePath,
101
+ });
102
+ }
103
+
104
+ this.attachInterceptor(axios);
105
+ }
106
+
107
+ async initialize(env: Environment = Environment.Production, targetWorkspace?: string) {
108
+ this.configuration.basePath = env;
109
+
110
+ await this.loadCredentials();
111
+
112
+ if (this.username) {
113
+ await this.authorize(this.username, this.password, targetWorkspace);
114
+ this.password = null; // to avoid keeping password loaded in memory.
115
+ }
116
+ }
117
+
118
+ private async loadCredentials() {
119
+ try {
120
+ await this.readConfigFile();
121
+ } catch (error) {
122
+ console.warn(`No credentials file found. Check that ${filePath} exists.`);
123
+ }
124
+
125
+ this.readEnvVariables();
126
+
127
+ if (!this.username) {
128
+ console.info(`No credentials found in credentials file or environment variables. Either provide some or use
129
+ authorize() function.`);
130
+ }
131
+ }
132
+
133
+ private async readConfigFile() {
134
+ const file = await fs.promises.readFile(filePath, 'utf-8');
135
+
136
+ const lines = file.split(os.EOL)
137
+ .filter(Boolean);
138
+
139
+ lines.forEach((line: string) => {
140
+ if (line.startsWith(KEY_USERNAME)) {
141
+ this.username = line.length > KEY_USERNAME.length + 1 ? line.substring(KEY_USERNAME.length + 1) : '';
142
+ } else if (line.startsWith(KEY_PASSWORD)) {
143
+ this.password = line.length > KEY_PASSWORD.length + 1 ? line.substring(KEY_PASSWORD.length + 1) : '';
144
+ }
145
+ });
146
+ }
147
+
148
+ private readEnvVariables(): boolean {
149
+ if (process.env.EMIL_USERNAME) {
150
+ this.username = process.env.EMIL_USERNAME;
151
+ this.password = process.env.EMIL_PASSWORD || '';
152
+
153
+ return true;
154
+ }
155
+
156
+ return false;
157
+ }
158
+
159
+ selectEnvironment(env: Environment) {
160
+ this.configuration.basePath = env;
161
+ }
162
+
163
+ async authorize(username: string, password: string, targetWorkspace?: string): Promise<void> {
164
+ const options: AxiosRequestConfig = {
165
+ method: 'POST',
166
+ url: `${this.configuration.basePath}/authservice/v1/login`,
167
+ headers: { 'Content-Type': 'application/json' },
168
+ data: {
169
+ username,
170
+ password,
171
+ },
172
+ withCredentials: true,
173
+ };
174
+
175
+ const response = await globalAxios.request<LoginClass>(options);
176
+
177
+ const { data: { accessToken } } = response;
178
+ this.configuration.username = username;
179
+ this.configuration.accessToken = `Bearer ${accessToken}`;
180
+
181
+ const refreshToken = this.extractRefreshToken(response)
182
+ this.configuration.refreshToken = refreshToken;
183
+
184
+ // Switch workspace if provided
185
+ if (targetWorkspace) {
186
+ await this.switchWorkspace(targetWorkspace);
187
+ }
188
+ }
189
+ async switchWorkspace(targetWorkspace: string): Promise<void> {
190
+ const options: AxiosRequestConfig = {
191
+ method: 'POST',
192
+ url: `${this.configuration.basePath}/authservice/v1/workspaces/switch`,
193
+ headers: {
194
+ 'Content-Type': 'application/json',
195
+ 'Authorization': `Bearer ${this.configuration.accessToken}`,
196
+ 'Cookie': this.configuration.refreshToken,
197
+ },
198
+ data: {
199
+ username: this.configuration.username,
200
+ targetWorkspace,
201
+ } as SwitchWorkspaceRequest,
202
+ withCredentials: true,
203
+ };
204
+
205
+ const response = await globalAxios.request<SwitchWorkspaceResponseClass>(options);
206
+
207
+ const { data: { accessToken } } = response;
208
+ this.configuration.accessToken = `Bearer ${accessToken}`;
209
+
210
+ const refreshToken = this.extractRefreshToken(response);
211
+ if (refreshToken) {
212
+ this.configuration.refreshToken = refreshToken;
213
+ }
214
+ }
215
+
216
+ async refreshTokenInternal(): Promise<string> {
217
+ const { username, refreshToken } = this.configuration;
218
+
219
+
220
+ if (!username || !refreshToken) {
221
+ return '';
222
+ }
223
+
224
+ const options: AxiosRequestConfig = {
225
+ method: 'POST',
226
+ url: `${this.configuration.basePath}/authservice/v1/refresh-token`,
227
+ headers: {
228
+ 'Content-Type': 'application/json',
229
+ Cookie: refreshToken,
230
+ },
231
+ data: { username: username },
232
+ withCredentials: true,
233
+ };
234
+
235
+ const { data: { accessToken } } = await globalAxios.request<LoginClass>(options);
236
+
237
+ return accessToken;
238
+ }
239
+
240
+ private extractRefreshToken(response: AxiosResponse): string {
241
+ if (response.headers && response.headers['set-cookie']
242
+ && response.headers['set-cookie'].length > 0) {
243
+
244
+ return `${response.headers['set-cookie'][0].split(';')[0]};`;
245
+ }
246
+
247
+ return '';
248
+ }
249
+
250
+ getConfiguration(): Configuration {
251
+ return this.configuration;
252
+ }
253
+
254
+ private attachInterceptor(axios: AxiosInstance) {
255
+ axios.interceptors.response.use(
256
+ (res) => {
257
+ return res;
258
+ },
259
+ async (err) => {
260
+ let originalConfig = err.config;
261
+ if (err.response) {
262
+ // Access Token was expired
263
+ if (err.response.status === 401 && !originalConfig._retry) {
264
+ originalConfig._retry = true;
265
+ try {
266
+ const tokenString = await this.refreshTokenInternal();
267
+ const accessToken = `Bearer ${tokenString}`;
268
+
269
+ originalConfig.headers['Authorization'] = accessToken;
270
+
271
+ this.configuration.accessToken = accessToken;
272
+
273
+ return axios.request(originalConfig);
274
+ } catch (_error) {
275
+ if (_error.response && _error.response.data) {
276
+ return Promise.reject(_error.response.data);
277
+ }
278
+ return Promise.reject(_error);
279
+ }
280
+ }
281
+ if (err.response.status === 403 && err.response.data) {
282
+ return Promise.reject(err.response.data);
283
+ }
284
+ } else if(err.message === NETWORK_ERROR_MESSAGE
285
+ && err.isAxiosError
286
+ && originalConfig.headers.hasOwnProperty('Authorization')
287
+ && _retry_count < 4
288
+ ){
289
+ _retry_count++;
290
+ try {
291
+ const tokenString = await this.refreshTokenInternal();
292
+ const accessToken = `Bearer ${tokenString}`;
293
+
294
+ _retry = true;
295
+ originalConfig.headers['Authorization'] = accessToken;
296
+
297
+ this.configuration.accessToken = accessToken;
298
+
299
+ return axios.request({
300
+ ...originalConfig,
301
+ });
302
+ } catch (_error) {
303
+ if (_error.response && _error.response.data) {
304
+ return Promise.reject(_error.response.data);
305
+ }
306
+ return Promise.reject(_error);
307
+ }
308
+ }
309
+ return Promise.reject(err);
310
+ }
311
+ );
312
+ }
313
+ };
314
+
315
+ /**
316
+ *
317
+ * @export
318
+ * @class RequiredError
319
+ * @extends {Error}
320
+ */
321
+ export class RequiredError extends Error {
322
+ override name: "RequiredError" = "RequiredError";
323
+ constructor(public field: string, msg?: string) {
324
+ super(msg);
325
+ }
326
+ }
327
+