@sap-ux/axios-extension 1.6.1 → 1.7.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.
@@ -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
  /**
@@ -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.
@@ -68,6 +73,7 @@ export declare const abapUrlReplaceMap: Map<RegExp, string>;
68
73
  export declare class Ui5AbapRepositoryService extends ODataService {
69
74
  static readonly PATH = "/sap/opu/odata/UI5/ABAP_REPOSITORY_SRV";
70
75
  private readonly publicUrl;
76
+ private readonly isDest;
71
77
  /**
72
78
  * Extension of the base constructor to set preferred response format if not provided by caller.
73
79
  *
@@ -83,6 +89,13 @@ export declare class Ui5AbapRepositoryService extends ODataService {
83
89
  * @returns application information or undefined
84
90
  */
85
91
  getInfo(app: string): Promise<AppInfo>;
92
+ /**
93
+ * Get the application files as zip archive. This will only work on ABAP systems 2308 or newer.
94
+ *
95
+ * @param app application id (BSP application name)
96
+ * @returns undefined if no app is found or downloading files is not supported, otherwise return the application files as a buffer.
97
+ */
98
+ downloadFiles(app: string): Promise<Buffer>;
86
99
  /**
87
100
  * Deploy the given archive either by creating a new BSP or updating an existing one.
88
101
  *
@@ -154,12 +167,10 @@ export declare class Ui5AbapRepositoryService extends ODataService {
154
167
  * @param e error thrown by Axios after sending a request
155
168
  * @param e.error error from Axios
156
169
  * @param e.host hostname
157
- * @param e.isDest
158
170
  */
159
- protected logError({ error, host, isDest }: {
171
+ protected logError({ error, host }: {
160
172
  error: Error;
161
173
  host?: string;
162
- isDest?: boolean;
163
174
  }): void;
164
175
  /**
165
176
  * Get ErrorMessage object from response contain an error as a string.
@@ -52,6 +52,7 @@ class Ui5AbapRepositoryService extends odata_service_1.ODataService {
52
52
  config.headers['Accept'] = (_b = config.headers['Accept']) !== null && _b !== void 0 ? _b : 'application/json,application/xml,text/plain,*/*';
53
53
  super(config);
54
54
  this.publicUrl = config.publicUrl || this.defaults.baseURL;
55
+ this.isDest = /\.dest\//.test(this.defaults.baseURL);
55
56
  }
56
57
  /**
57
58
  * Get information about a deployed application. Returns undefined if the application cannot be found.
@@ -75,6 +76,34 @@ class Ui5AbapRepositoryService extends odata_service_1.ODataService {
75
76
  }
76
77
  });
77
78
  }
79
+ /**
80
+ * Get the application files as zip archive. This will only work on ABAP systems 2308 or newer.
81
+ *
82
+ * @param app application id (BSP application name)
83
+ * @returns undefined if no app is found or downloading files is not supported, otherwise return the application files as a buffer.
84
+ */
85
+ downloadFiles(app) {
86
+ var _a;
87
+ return __awaiter(this, void 0, void 0, function* () {
88
+ try {
89
+ const response = yield this.get(`/Repositories('${encodeURIComponent(app)}')`, {
90
+ params: {
91
+ CodePage: 'UTF8',
92
+ DownloadFiles: 'RUNTIME'
93
+ }
94
+ });
95
+ const data = response.odata();
96
+ return data.ZipArchive ? Buffer.from(data.ZipArchive) : undefined;
97
+ }
98
+ catch (error) {
99
+ this.log.debug(`Retrieving application ${app}, ${error}`);
100
+ if ((0, odata_request_error_1.isAxiosError)(error) && ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 404) {
101
+ return undefined;
102
+ }
103
+ throw error;
104
+ }
105
+ });
106
+ }
78
107
  /**
79
108
  * Deploy the given archive either by creating a new BSP or updating an existing one.
80
109
  *
@@ -93,7 +122,6 @@ class Ui5AbapRepositoryService extends odata_service_1.ODataService {
93
122
  this.log.debug(`Payload:\n${payload}`);
94
123
  const config = this.createConfig(bsp.transport, testMode, safeMode);
95
124
  const frontendUrl = this.getAbapFrontendUrl();
96
- const isDest = /\.dest\//.test(config.baseURL);
97
125
  try {
98
126
  const response = yield this.updateRepoRequest(!!info, bsp.name, payload, config);
99
127
  // An app can be successfully deployed after a timeout exception, no value in showing exception headers
@@ -102,7 +130,7 @@ class Ui5AbapRepositoryService extends odata_service_1.ODataService {
102
130
  msg: response.headers['sap-message'],
103
131
  log: this.log,
104
132
  host: frontendUrl,
105
- isDest
133
+ isDest: this.isDest
106
134
  });
107
135
  }
108
136
  if (!testMode) {
@@ -119,13 +147,13 @@ class Ui5AbapRepositoryService extends odata_service_1.ODataService {
119
147
  error: this.getErrorMessageFromString(response === null || response === void 0 ? void 0 : response.data),
120
148
  log: this.log,
121
149
  host: frontendUrl,
122
- isDest
150
+ isDest: this.isDest
123
151
  }, false);
124
152
  }
125
153
  return response;
126
154
  }
127
155
  catch (error) {
128
- this.logError({ error, host: frontendUrl, isDest });
156
+ this.logError({ error, host: frontendUrl });
129
157
  throw error;
130
158
  }
131
159
  });
@@ -144,7 +172,6 @@ class Ui5AbapRepositoryService extends odata_service_1.ODataService {
144
172
  const config = this.createConfig(bsp.transport, testMode);
145
173
  const host = this.getAbapFrontendUrl();
146
174
  const info = yield this.getInfo(bsp.name);
147
- const isDest = /\.dest\//.test(config.baseURL);
148
175
  try {
149
176
  if (info) {
150
177
  const response = yield this.deleteRepoRequest(bsp.name, config);
@@ -153,7 +180,7 @@ class Ui5AbapRepositoryService extends odata_service_1.ODataService {
153
180
  msg: response.headers['sap-message'],
154
181
  log: this.log,
155
182
  host,
156
- isDest
183
+ isDest: this.isDest
157
184
  });
158
185
  }
159
186
  return response;
@@ -164,7 +191,7 @@ class Ui5AbapRepositoryService extends odata_service_1.ODataService {
164
191
  }
165
192
  }
166
193
  catch (error) {
167
- this.logError({ error, host, isDest });
194
+ this.logError({ error, host });
168
195
  throw error;
169
196
  }
170
197
  });
@@ -338,15 +365,14 @@ class Ui5AbapRepositoryService extends odata_service_1.ODataService {
338
365
  * @param e error thrown by Axios after sending a request
339
366
  * @param e.error error from Axios
340
367
  * @param e.host hostname
341
- * @param e.isDest
342
368
  */
343
- logError({ error, host, isDest }) {
369
+ logError({ error, host }) {
344
370
  var _a, _b;
345
371
  this.log.error(error.message);
346
372
  if ((0, odata_request_error_1.isAxiosError)(error) && ((_a = error.response) === null || _a === void 0 ? void 0 : _a.data)) {
347
373
  const errorMessage = this.getErrorMessageFromString((_b = error.response) === null || _b === void 0 ? void 0 : _b.data);
348
374
  if (errorMessage) {
349
- (0, message_1.prettyPrintError)({ error: errorMessage, host, log: this.log, isDest });
375
+ (0, message_1.prettyPrintError)({ error: errorMessage, host, log: this.log, isDest: this.isDest });
350
376
  }
351
377
  else {
352
378
  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.1",
3
+ "version": "1.7.1",
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",