@mcp-abap-adt/connection 1.4.0 → 1.4.2
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.
|
@@ -33,6 +33,11 @@ export declare class RfcAbapConnection implements AbapConnection {
|
|
|
33
33
|
getSessionId(): string | null;
|
|
34
34
|
setSessionType(_type: 'stateful' | 'stateless'): void;
|
|
35
35
|
makeAdtRequest<T = any, D = any>(options: IAbapRequestOptions): Promise<IAdtResponse<T, D>>;
|
|
36
|
+
/**
|
|
37
|
+
* Reset the connection — for RFC this closes the session.
|
|
38
|
+
* Provides interface compatibility with HTTP connections.
|
|
39
|
+
*/
|
|
40
|
+
reset(): void;
|
|
36
41
|
/**
|
|
37
42
|
* Close the RFC connection and release the ABAP session.
|
|
38
43
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RfcAbapConnection.d.ts","sourceRoot":"","sources":["../../src/connection/RfcAbapConnection.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,mBAAmB,EACnB,YAAY,EACb,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"RfcAbapConnection.d.ts","sourceRoot":"","sources":["../../src/connection/RfcAbapConnection.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,mBAAmB,EACnB,YAAY,EACb,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AA0F1D;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,iBAAkB,YAAW,cAAc;IAOpD,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAPzB,OAAO,CAAC,SAAS,CAA2B;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsB;gBAG7B,MAAM,EAAE,SAAS,EACjB,MAAM,GAAE,OAAO,GAAG,IAAW;IAa1C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA8BxB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAInC,YAAY,IAAI,MAAM,GAAG,IAAI;IAI7B,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,GAAG,IAAI;IAI/C,cAAc,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,GAAG,EACnC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IA6I9B;;;OAGG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAc5B,OAAO,CAAC,MAAM,CAAC,cAAc;CAqB9B"}
|
|
@@ -25,6 +25,37 @@ function buildRfcParams(config) {
|
|
|
25
25
|
lang: 'EN',
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Map ADT exception type names to HTTP status codes.
|
|
30
|
+
* These are standard ADT exception types returned in `<exc:exception>` XML.
|
|
31
|
+
*/
|
|
32
|
+
const EXCEPTION_STATUS_MAP = {
|
|
33
|
+
ExceptionResourceNotFound: { code: 404, text: 'Not Found' },
|
|
34
|
+
ExceptionResourceNoAuthorization: { code: 403, text: 'Forbidden' },
|
|
35
|
+
ExceptionResourceAlreadyExists: { code: 409, text: 'Conflict' },
|
|
36
|
+
ExceptionResourceLocked: { code: 423, text: 'Locked' },
|
|
37
|
+
ExceptionBadRequest: { code: 400, text: 'Bad Request' },
|
|
38
|
+
ExceptionNotSupported: { code: 501, text: 'Not Implemented' },
|
|
39
|
+
ExceptionConflict: { code: 409, text: 'Conflict' },
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Detect HTTP status from ADT exception XML in response body.
|
|
43
|
+
* On some legacy systems, SADT_REST_RFC_ENDPOINT returns errors as XML
|
|
44
|
+
* exceptions without setting proper HTTP status codes in STATUS_LINE.
|
|
45
|
+
*/
|
|
46
|
+
function detectExceptionStatus(body) {
|
|
47
|
+
// Extract exception type: <exc:exception ... xmlns:exc="..."><exc:type>ExceptionName</exc:type>
|
|
48
|
+
const typeMatch = body.match(/<exc:type[^>]*>([^<]+)<\/exc:type>/);
|
|
49
|
+
if (typeMatch) {
|
|
50
|
+
const exType = typeMatch[1].trim();
|
|
51
|
+
const mapped = EXCEPTION_STATUS_MAP[exType];
|
|
52
|
+
if (mapped) {
|
|
53
|
+
return { statusCode: mapped.code, statusText: mapped.text };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Unknown exception type — return 500 as generic server error
|
|
57
|
+
return { statusCode: 500, statusText: 'Internal Server Error' };
|
|
58
|
+
}
|
|
28
59
|
/**
|
|
29
60
|
* RFC-based connection for on-premise SAP systems.
|
|
30
61
|
*
|
|
@@ -100,12 +131,11 @@ class RfcAbapConnection {
|
|
|
100
131
|
throw new Error('RFC connection is not open. Call connect() first.');
|
|
101
132
|
}
|
|
102
133
|
const method = options.method.toUpperCase();
|
|
103
|
-
|
|
104
|
-
//
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
134
|
+
const uri = options.url;
|
|
135
|
+
// Note: sap-client is NOT added to URI for RFC connections.
|
|
136
|
+
// The RFC session is already logged into the correct client
|
|
137
|
+
// (via the 'client' param in RFC connection). Adding sap-client
|
|
138
|
+
// to the URI can cause "object not found" on some systems.
|
|
109
139
|
// Build header fields
|
|
110
140
|
const headerFields = [];
|
|
111
141
|
if (options.headers) {
|
|
@@ -138,9 +168,16 @@ class RfcAbapConnection {
|
|
|
138
168
|
},
|
|
139
169
|
});
|
|
140
170
|
const resp = result.RESPONSE || result;
|
|
171
|
+
// Log raw RFC response structure for debugging
|
|
172
|
+
this.logger?.debug(`RFC raw response keys: ${Object.keys(resp).join(', ')}`);
|
|
173
|
+
if (resp.STATUS_LINE) {
|
|
174
|
+
this.logger?.debug(`RFC STATUS_LINE: ${JSON.stringify(resp.STATUS_LINE)}`);
|
|
175
|
+
}
|
|
141
176
|
// Parse status — RFC returns status in STATUS_LINE structure
|
|
142
|
-
|
|
143
|
-
const
|
|
177
|
+
// Field names: STATUS_CODE (not CODE), REASON_PHRASE (not REASON)
|
|
178
|
+
const rawCode = resp.STATUS_LINE?.STATUS_CODE || resp.STATUS_LINE?.CODE || 0;
|
|
179
|
+
let statusCode = typeof rawCode === 'string' ? Number.parseInt(rawCode, 10) : rawCode;
|
|
180
|
+
let statusText = resp.STATUS_LINE?.REASON_PHRASE || resp.STATUS_LINE?.REASON || '';
|
|
144
181
|
// Parse response body
|
|
145
182
|
const respBody = resp.MESSAGE_BODY
|
|
146
183
|
? Buffer.isBuffer(resp.MESSAGE_BODY)
|
|
@@ -155,6 +192,20 @@ class RfcAbapConnection {
|
|
|
155
192
|
respHeaders[field.NAME.toLowerCase()] = field.VALUE;
|
|
156
193
|
}
|
|
157
194
|
}
|
|
195
|
+
// On some systems (e.g. BASIS < 7.50), SADT_REST_RFC_ENDPOINT does not
|
|
196
|
+
// populate STATUS_LINE, returning status 0. Detect errors from the
|
|
197
|
+
// response body: ADT exception XML indicates a failed request.
|
|
198
|
+
if (!statusCode && respBody.includes('<exc:exception')) {
|
|
199
|
+
const detected = detectExceptionStatus(respBody);
|
|
200
|
+
statusCode = detected.statusCode;
|
|
201
|
+
statusText = detected.statusText;
|
|
202
|
+
this.logger?.debug(`RFC: STATUS_LINE empty, detected ${statusCode} from exception XML`);
|
|
203
|
+
}
|
|
204
|
+
// Default to 200 OK only when no error was detected
|
|
205
|
+
if (!statusCode) {
|
|
206
|
+
statusCode = 200;
|
|
207
|
+
statusText = statusText || 'OK';
|
|
208
|
+
}
|
|
158
209
|
this.logger?.debug(`RFC ← ${statusCode} ${statusText} (${respBody.length} bytes)`);
|
|
159
210
|
const response = {
|
|
160
211
|
data: respBody,
|
|
@@ -181,6 +232,13 @@ class RfcAbapConnection {
|
|
|
181
232
|
throw new Error(`RFC call to SADT_REST_RFC_ENDPOINT failed: ${msg}`);
|
|
182
233
|
}
|
|
183
234
|
}
|
|
235
|
+
/**
|
|
236
|
+
* Reset the connection — for RFC this closes the session.
|
|
237
|
+
* Provides interface compatibility with HTTP connections.
|
|
238
|
+
*/
|
|
239
|
+
reset() {
|
|
240
|
+
this.close();
|
|
241
|
+
}
|
|
184
242
|
/**
|
|
185
243
|
* Close the RFC connection and release the ABAP session.
|
|
186
244
|
*/
|