@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;AAqD1D;;;;;;;;;;;;;;;;;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;IA6G9B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAc5B,OAAO,CAAC,MAAM,CAAC,cAAc;CAqB9B"}
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
- let uri = options.url;
104
- // Add sap-client to URI if not present
105
- if (this.config.client && !uri.includes('sap-client')) {
106
- uri +=
107
- (uri.includes('?') ? '&' : '?') + `sap-client=${this.config.client}`;
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
- const statusCode = resp.STATUS_LINE?.CODE || resp.STATUS_CODE || 200;
143
- const statusText = resp.STATUS_LINE?.REASON || resp.STATUS_TEXT || 'OK';
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
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-abap-adt/connection",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "description": "ABAP connection layer for MCP ABAP ADT server",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",