@sap-ux/axios-extension 1.6.0 → 1.7.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.
@@ -82,9 +82,10 @@ export declare class AbapServiceProvider extends ServiceProvider {
82
82
  /**
83
83
  * Create or get an existing instance of design time adaptation service.
84
84
  *
85
+ * @param alias - optional alias path on which the LREP service is exposed
85
86
  * @returns an instance of the design time adaptation service.
86
87
  */
87
- getLayeredRepository(): LayeredRepositoryService;
88
+ getLayeredRepository(alias?: string): LayeredRepositoryService;
88
89
  /**
89
90
  * Retrieve singleton instance of AdtService subclass to serve the specific ADT request query.
90
91
  *
@@ -174,13 +174,15 @@ class AbapServiceProvider extends service_provider_1.ServiceProvider {
174
174
  /**
175
175
  * Create or get an existing instance of design time adaptation service.
176
176
  *
177
+ * @param alias - optional alias path on which the LREP service is exposed
177
178
  * @returns an instance of the design time adaptation service.
178
179
  */
179
- getLayeredRepository() {
180
- if (!this.services[lrep_service_1.LayeredRepositoryService.PATH]) {
181
- this.services[lrep_service_1.LayeredRepositoryService.PATH] = this.createService(lrep_service_1.LayeredRepositoryService.PATH, lrep_service_1.LayeredRepositoryService);
180
+ getLayeredRepository(alias) {
181
+ const path = alias !== null && alias !== void 0 ? alias : lrep_service_1.LayeredRepositoryService.PATH;
182
+ if (!this.services[path]) {
183
+ this.services[path] = this.createService(path, lrep_service_1.LayeredRepositoryService);
182
184
  }
183
- return this.services[lrep_service_1.LayeredRepositoryService.PATH];
185
+ return this.services[path];
184
186
  }
185
187
  /**
186
188
  * Retrieve singleton instance of AdtService subclass to serve the specific ADT request query.
@@ -4,6 +4,7 @@ import type { AxiosResponse } from 'axios';
4
4
  import { Axios } from 'axios';
5
5
  import type { Logger } from '@sap-ux/logger';
6
6
  import type { ManifestNamespace } from '@sap-ux/project-access';
7
+ import type { TransportConfig } from './ui5-abap-repository-service';
7
8
  export type Manifest = ManifestNamespace.SAPJSONSchemaForWebApplicationManifestFile & {
8
9
  [key: string]: unknown;
9
10
  };
@@ -27,19 +28,11 @@ export type Namespace = NamespaceObject | string;
27
28
  /**
28
29
  * Required configuration to deploy an adaptation project.
29
30
  */
30
- export interface AdaptationConfig {
31
+ export interface AdaptationConfig extends TransportConfig {
31
32
  /**
32
33
  * Namespace either as string or object
33
34
  */
34
35
  namespace: Namespace;
35
- /**
36
- * Optional ABAP package name
37
- */
38
- package?: string;
39
- /**
40
- * Optional transport request
41
- */
42
- transport?: string;
43
36
  /**
44
37
  * Optional layer (default: CUSTOMER_BASE)
45
38
  */
@@ -83,6 +76,12 @@ type Layer = 'VENDOR' | 'CUSTOMER_BASE';
83
76
  export declare class LayeredRepositoryService extends Axios implements Service {
84
77
  static readonly PATH = "/sap/bc/lrep";
85
78
  log: Logger;
79
+ /**
80
+ * Simple request to fetch a CSRF token required for all writing operations.
81
+ *
82
+ * @returns the response
83
+ */
84
+ getCsrfToken(): Promise<AxiosResponse<any, any>>;
86
85
  /**
87
86
  * Merge a given app descriptor variant with the stord app descriptor.
88
87
  *
@@ -103,16 +102,16 @@ export declare class LayeredRepositoryService extends Axios implements Service {
103
102
  /**
104
103
  * Deploy the given archive either by creating a new folder in the layered repository or updating an existing one.
105
104
  *
106
- * @param archivePath path to a zip archive containing the adaptation project
105
+ * @param archive path to a zip archive or archive as buffer containing the adaptation project
107
106
  * @param config adataption project deployment configuration
108
107
  * @returns the Axios response object for futher processing
109
108
  */
110
- deploy(archivePath: string, config: AdaptationConfig): Promise<AxiosResponse>;
109
+ deploy(archive: Buffer | string, config: AdaptationConfig): Promise<AxiosResponse>;
111
110
  /**
112
111
  * Undeploy the archive identified by the configuration.
113
112
  *
114
- * @param config adataption project deployment configuration
115
- * @returns the Axios response object for futher processing
113
+ * @param config adaptation project deployment configuration
114
+ * @returns the Axios response object for further processing
116
115
  */
117
116
  undeploy(config: AdaptationConfig): Promise<AxiosResponse>;
118
117
  /**
@@ -23,6 +23,15 @@ const odata_request_error_1 = require("../base/odata-request-error");
23
23
  function getNamespaceAsString(namespace) {
24
24
  return typeof namespace !== 'string' ? `apps/${namespace['reference']}/appVariants/${namespace['id']}/` : namespace;
25
25
  }
26
+ /**
27
+ * Check if a variable is a buffer.
28
+ *
29
+ * @param input variable to be checked
30
+ * @returns true if the input is a buffer
31
+ */
32
+ function isBuffer(input) {
33
+ return input.BYTES_PER_ELEMENT !== undefined;
34
+ }
26
35
  /**
27
36
  * Path suffix for all DTA actions.
28
37
  */
@@ -31,6 +40,24 @@ const DTA_PATH_SUFFIX = '/dta_folder/';
31
40
  * A class representing the design time adaptation service allowing to deploy adaptation projects to an ABAP system.
32
41
  */
33
42
  class LayeredRepositoryService extends axios_1.Axios {
43
+ /**
44
+ * Simple request to fetch a CSRF token required for all writing operations.
45
+ *
46
+ * @returns the response
47
+ */
48
+ getCsrfToken() {
49
+ return __awaiter(this, void 0, void 0, function* () {
50
+ try {
51
+ return yield this.get('/actions/getcsrftoken/');
52
+ }
53
+ catch (error) {
54
+ if ((0, odata_request_error_1.isAxiosError)(error)) {
55
+ this.tryLogResponse(error.response);
56
+ }
57
+ throw error;
58
+ }
59
+ });
60
+ }
34
61
  /**
35
62
  * Merge a given app descriptor variant with the stord app descriptor.
36
63
  *
@@ -90,14 +117,14 @@ class LayeredRepositoryService extends axios_1.Axios {
90
117
  /**
91
118
  * Deploy the given archive either by creating a new folder in the layered repository or updating an existing one.
92
119
  *
93
- * @param archivePath path to a zip archive containing the adaptation project
120
+ * @param archive path to a zip archive or archive as buffer containing the adaptation project
94
121
  * @param config adataption project deployment configuration
95
122
  * @returns the Axios response object for futher processing
96
123
  */
97
- deploy(archivePath, config) {
124
+ deploy(archive, config) {
98
125
  var _a, _b;
99
126
  return __awaiter(this, void 0, void 0, function* () {
100
- const archive = (0, fs_1.readFileSync)(archivePath);
127
+ const data = isBuffer(archive) ? archive : (0, fs_1.readFileSync)(archive);
101
128
  const checkResponse = yield this.isExistingVariant(config.namespace);
102
129
  const params = {
103
130
  name: getNamespaceAsString(config.namespace),
@@ -110,7 +137,7 @@ class LayeredRepositoryService extends axios_1.Axios {
110
137
  const response = yield this.request({
111
138
  method: checkResponse.status === 200 ? 'PUT' : 'POST',
112
139
  url: DTA_PATH_SUFFIX,
113
- data: archive,
140
+ data,
114
141
  params,
115
142
  headers: {
116
143
  'Content-Type': 'application/octet-stream'
@@ -123,11 +150,11 @@ class LayeredRepositoryService extends axios_1.Axios {
123
150
  /**
124
151
  * Undeploy the archive identified by the configuration.
125
152
  *
126
- * @param config adataption project deployment configuration
127
- * @returns the Axios response object for futher processing
153
+ * @param config adaptation project deployment configuration
154
+ * @returns the Axios response object for further processing
128
155
  */
129
156
  undeploy(config) {
130
- var _a;
157
+ var _a, _b;
131
158
  return __awaiter(this, void 0, void 0, function* () {
132
159
  const checkResponse = yield this.isExistingVariant(config.namespace);
133
160
  if (checkResponse.status !== 200) {
@@ -140,9 +167,19 @@ class LayeredRepositoryService extends axios_1.Axios {
140
167
  if (config.transport) {
141
168
  params['changelist'] = config.transport;
142
169
  }
143
- const response = yield this.delete(DTA_PATH_SUFFIX, { params });
144
- this.tryLogResponse(response, 'Undeployment successful.');
145
- return response;
170
+ try {
171
+ const response = yield this.delete(DTA_PATH_SUFFIX, { params });
172
+ this.tryLogResponse(response, 'Undeployment successful.');
173
+ return response;
174
+ }
175
+ catch (error) {
176
+ this.log.error('Undeployment failed');
177
+ this.log.debug(error);
178
+ if ((0, odata_request_error_1.isAxiosError)(error) && ((_b = error.response) === null || _b === void 0 ? void 0 : _b.status) === 405) {
179
+ this.log.error('Newer version of SAP_UI required, please check https://help.sap.com/docs/bas/developing-sap-fiori-app-in-sap-business-application-studio/delete-adaptation-project');
180
+ }
181
+ throw error;
182
+ }
146
183
  });
147
184
  }
148
185
  /**
@@ -57,12 +57,14 @@ export declare function prettyPrintMessage({ msg, log, host, isDest }: {
57
57
  * @param options.error error message returned from gateway
58
58
  * @param options.log logger to be used
59
59
  * @param options.host optional host name to pretty print links
60
+ * @param options.isDest optional value if additional info should be printed
60
61
  * @param showAllMessages optional, show all errors but restrict for certain flows i.e. test mode
61
62
  */
62
- export declare function prettyPrintError({ error, log, host }: {
63
+ export declare function prettyPrintError({ error, log, host, isDest }: {
63
64
  error: ErrorMessage;
64
65
  log: Logger;
65
66
  host?: string;
67
+ isDest?: boolean;
66
68
  }, showAllMessages?: boolean): void;
67
69
  /**
68
70
  * Print a user friendly time string.
@@ -79,9 +79,10 @@ function logFullURL({ host, path, log, isDest = false }) {
79
79
  * @param options.error error message returned from gateway
80
80
  * @param options.log logger to be used
81
81
  * @param options.host optional host name to pretty print links
82
+ * @param options.isDest optional value if additional info should be printed
82
83
  * @param showAllMessages optional, show all errors but restrict for certain flows i.e. test mode
83
84
  */
84
- function prettyPrintError({ error, log, host }, showAllMessages = true) {
85
+ function prettyPrintError({ error, log, host, isDest }, showAllMessages = true) {
85
86
  var _a, _b, _c;
86
87
  if (error) {
87
88
  if (showAllMessages) {
@@ -91,7 +92,7 @@ function prettyPrintError({ error, log, host }, showAllMessages = true) {
91
92
  if (!entry.message.startsWith('<![CDATA')) {
92
93
  logLevel(entry.severity, entry.message, log, true);
93
94
  }
94
- logFullURL({ host, path: entry['longtext_url'], log });
95
+ logFullURL({ host, path: entry['longtext_url'], log, isDest });
95
96
  });
96
97
  if (showAllMessages && ((_c = error.innererror) === null || _c === void 0 ? void 0 : _c.Error_Resolution)) {
97
98
  for (const key in error.innererror.Error_Resolution) {
@@ -2,10 +2,23 @@
2
2
  import type { AxiosResponse, AxiosRequestConfig } from 'axios';
3
3
  import type { ErrorMessage } from './message';
4
4
  import { ODataService } from '../base/odata-service';
5
+ /**
6
+ * Required configuration a transportable object.
7
+ */
8
+ export interface TransportConfig {
9
+ /**
10
+ * Optional package for the ABAP development object
11
+ */
12
+ package?: string;
13
+ /**
14
+ * Optional transport request to record the changes
15
+ */
16
+ transport?: string;
17
+ }
5
18
  /**
6
19
  * Required configuration for the BSP hosting an app.
7
20
  */
8
- export interface BspConfig {
21
+ export interface BspConfig extends TransportConfig {
9
22
  /**
10
23
  * Name of the BSP, additionally, the last part of the exposed service path
11
24
  */
@@ -14,14 +27,6 @@ export interface BspConfig {
14
27
  * Optional description of the ABAP development object representing the BSP
15
28
  */
16
29
  description?: string;
17
- /**
18
- * Optional package for the ABAP development object
19
- */
20
- package?: string;
21
- /**
22
- * Optional transport request to record the changes
23
- */
24
- transport?: string;
25
30
  }
26
31
  /**
27
32
  * Configuration required for deploying an app.
@@ -83,6 +88,13 @@ export declare class Ui5AbapRepositoryService extends ODataService {
83
88
  * @returns application information or undefined
84
89
  */
85
90
  getInfo(app: string): Promise<AppInfo>;
91
+ /**
92
+ * Get the application files as zip archive. This will only work on ABAP systems 2308 or newer.
93
+ *
94
+ * @param app application id (BSP application name)
95
+ * @returns undefined if no app is found or downloading files is not supported, otherwise return the application files as a buffer.
96
+ */
97
+ downloadFiles(app: string): Promise<Buffer>;
86
98
  /**
87
99
  * Deploy the given archive either by creating a new BSP or updating an existing one.
88
100
  *
@@ -154,10 +166,12 @@ export declare class Ui5AbapRepositoryService extends ODataService {
154
166
  * @param e error thrown by Axios after sending a request
155
167
  * @param e.error error from Axios
156
168
  * @param e.host hostname
169
+ * @param e.isDest
157
170
  */
158
- protected logError({ error, host }: {
171
+ protected logError({ error, host, isDest }: {
159
172
  error: Error;
160
173
  host?: string;
174
+ isDest?: boolean;
161
175
  }): void;
162
176
  /**
163
177
  * Get ErrorMessage object from response contain an error as a string.
@@ -75,6 +75,34 @@ class Ui5AbapRepositoryService extends odata_service_1.ODataService {
75
75
  }
76
76
  });
77
77
  }
78
+ /**
79
+ * Get the application files as zip archive. This will only work on ABAP systems 2308 or newer.
80
+ *
81
+ * @param app application id (BSP application name)
82
+ * @returns undefined if no app is found or downloading files is not supported, otherwise return the application files as a buffer.
83
+ */
84
+ downloadFiles(app) {
85
+ var _a;
86
+ return __awaiter(this, void 0, void 0, function* () {
87
+ try {
88
+ const response = yield this.get(`/Repositories('${encodeURIComponent(app)}')`, {
89
+ params: {
90
+ CodePage: 'UTF8',
91
+ DownloadFiles: 'RUNTIME'
92
+ }
93
+ });
94
+ const data = response.odata();
95
+ return data.ZipArchive ? Buffer.from(data.ZipArchive) : undefined;
96
+ }
97
+ catch (error) {
98
+ this.log.debug(`Retrieving application ${app}, ${error}`);
99
+ if ((0, odata_request_error_1.isAxiosError)(error) && ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 404) {
100
+ return undefined;
101
+ }
102
+ throw error;
103
+ }
104
+ });
105
+ }
78
106
  /**
79
107
  * Deploy the given archive either by creating a new BSP or updating an existing one.
80
108
  *
@@ -93,6 +121,7 @@ class Ui5AbapRepositoryService extends odata_service_1.ODataService {
93
121
  this.log.debug(`Payload:\n${payload}`);
94
122
  const config = this.createConfig(bsp.transport, testMode, safeMode);
95
123
  const frontendUrl = this.getAbapFrontendUrl();
124
+ const isDest = /\.dest\//.test(config.baseURL);
96
125
  try {
97
126
  const response = yield this.updateRepoRequest(!!info, bsp.name, payload, config);
98
127
  // An app can be successfully deployed after a timeout exception, no value in showing exception headers
@@ -101,7 +130,7 @@ class Ui5AbapRepositoryService extends odata_service_1.ODataService {
101
130
  msg: response.headers['sap-message'],
102
131
  log: this.log,
103
132
  host: frontendUrl,
104
- isDest: /\.dest\//.test(config.baseURL)
133
+ isDest
105
134
  });
106
135
  }
107
136
  if (!testMode) {
@@ -117,13 +146,14 @@ class Ui5AbapRepositoryService extends odata_service_1.ODataService {
117
146
  (0, message_1.prettyPrintError)({
118
147
  error: this.getErrorMessageFromString(response === null || response === void 0 ? void 0 : response.data),
119
148
  log: this.log,
120
- host: frontendUrl
149
+ host: frontendUrl,
150
+ isDest
121
151
  }, false);
122
152
  }
123
153
  return response;
124
154
  }
125
155
  catch (error) {
126
- this.logError({ error, host: frontendUrl });
156
+ this.logError({ error, host: frontendUrl, isDest });
127
157
  throw error;
128
158
  }
129
159
  });
@@ -142,11 +172,17 @@ class Ui5AbapRepositoryService extends odata_service_1.ODataService {
142
172
  const config = this.createConfig(bsp.transport, testMode);
143
173
  const host = this.getAbapFrontendUrl();
144
174
  const info = yield this.getInfo(bsp.name);
175
+ const isDest = /\.dest\//.test(config.baseURL);
145
176
  try {
146
177
  if (info) {
147
178
  const response = yield this.deleteRepoRequest(bsp.name, config);
148
179
  if ((_a = response === null || response === void 0 ? void 0 : response.headers) === null || _a === void 0 ? void 0 : _a['sap-message']) {
149
- (0, message_1.prettyPrintMessage)({ msg: response.headers['sap-message'], log: this.log, host });
180
+ (0, message_1.prettyPrintMessage)({
181
+ msg: response.headers['sap-message'],
182
+ log: this.log,
183
+ host,
184
+ isDest
185
+ });
150
186
  }
151
187
  return response;
152
188
  }
@@ -156,7 +192,7 @@ class Ui5AbapRepositoryService extends odata_service_1.ODataService {
156
192
  }
157
193
  }
158
194
  catch (error) {
159
- this.logError({ error, host });
195
+ this.logError({ error, host, isDest });
160
196
  throw error;
161
197
  }
162
198
  });
@@ -330,14 +366,15 @@ class Ui5AbapRepositoryService extends odata_service_1.ODataService {
330
366
  * @param e error thrown by Axios after sending a request
331
367
  * @param e.error error from Axios
332
368
  * @param e.host hostname
369
+ * @param e.isDest
333
370
  */
334
- logError({ error, host }) {
371
+ logError({ error, host, isDest }) {
335
372
  var _a, _b;
336
373
  this.log.error(error.message);
337
374
  if ((0, odata_request_error_1.isAxiosError)(error) && ((_a = error.response) === null || _a === void 0 ? void 0 : _a.data)) {
338
375
  const errorMessage = this.getErrorMessageFromString((_b = error.response) === null || _b === void 0 ? void 0 : _b.data);
339
376
  if (errorMessage) {
340
- (0, message_1.prettyPrintError)({ error: errorMessage, host, log: this.log });
377
+ (0, message_1.prettyPrintError)({ error: errorMessage, host, log: this.log, isDest });
341
378
  }
342
379
  else {
343
380
  this.log.error(error.response.data.toString());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap-ux/axios-extension",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "Extension of the Axios module adding convenience methods to interact with SAP systems especially with OData services.",
5
5
  "repository": {
6
6
  "type": "git",