abap-local-client 1.4.6 → 1.4.8
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.
- package/package.json +1 -1
- package/sso-sap-client.mjs +18 -5
- package/xml-utils.js +16 -2
- package/xml-utils.mjs +43 -12
package/package.json
CHANGED
package/sso-sap-client.mjs
CHANGED
|
@@ -483,7 +483,7 @@ class SAPClient {
|
|
|
483
483
|
return { success: !hasErrors && response.status >= 200 && response.status < 300, status: response.status, statusText: response.statusText, headers: response.headers, data: { raw: response.data, ...extractedData }, ...(errorMessages.length > 0 && { error: `SAP validation failed: ${errorMessages.join('; ')}`, errorDetails: errorMessages }) };
|
|
484
484
|
} catch (err) {
|
|
485
485
|
console.error(` ❌ RFC error: ${err.message}`);
|
|
486
|
-
return { success: false, status: 0, error: err.message, data: null };
|
|
486
|
+
return { success: false, status: 0, statusText: 'RFC Error', error: err.message, data: { raw: null } };
|
|
487
487
|
}
|
|
488
488
|
}
|
|
489
489
|
|
|
@@ -583,11 +583,24 @@ class SAPClient {
|
|
|
583
583
|
console.error(` ❌ RESPONSE HEADERS:`);
|
|
584
584
|
for (const [k, v] of Object.entries(error.response.headers)) console.error(` ❌ ${k}: ${v}`);
|
|
585
585
|
}
|
|
586
|
-
const
|
|
586
|
+
const rawBody = typeof error.response?.data === 'string'
|
|
587
587
|
? error.response.data
|
|
588
|
-
: JSON.stringify(error.response
|
|
589
|
-
if (
|
|
590
|
-
|
|
588
|
+
: (error.response?.data ? JSON.stringify(error.response.data) : null);
|
|
589
|
+
if (rawBody) console.error(` ❌ RESPONSE BODY:\n${rawBody}`);
|
|
590
|
+
|
|
591
|
+
// Extract the real SAP error message from the XML body (exc:exception, etc.)
|
|
592
|
+
const { hasErrors, errorMessages } = parseSAPResponse(rawBody || '');
|
|
593
|
+
const sapError = hasErrors ? errorMessages.join('; ') : null;
|
|
594
|
+
const errorMsg = sapError || error.message;
|
|
595
|
+
if (sapError) console.error(` ❌ SAP error: ${sapError}`);
|
|
596
|
+
|
|
597
|
+
return {
|
|
598
|
+
success: false,
|
|
599
|
+
status,
|
|
600
|
+
statusText: error.response?.statusText,
|
|
601
|
+
error: errorMsg,
|
|
602
|
+
data: { raw: rawBody, ...(hasErrors && { errorMessages }) },
|
|
603
|
+
};
|
|
591
604
|
}
|
|
592
605
|
}
|
|
593
606
|
|
package/xml-utils.js
CHANGED
|
@@ -50,8 +50,22 @@ export function parseSAPResponse(xmlString) {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
//
|
|
54
|
-
|
|
53
|
+
// exc:exception — generic SAP ADT error (e.g. SQL query syntax errors, 4xx responses)
|
|
54
|
+
const exc = parsed['exc:exception'];
|
|
55
|
+
if (exc) {
|
|
56
|
+
const msg = exc['message'] || exc['localizedMessage'] || exc['@_message'] || '';
|
|
57
|
+
const typeId = exc['type']?.['@_id'] || exc['namespace']?.['@_id'] || '';
|
|
58
|
+
const text = [msg, typeId].filter(Boolean).join(' — ');
|
|
59
|
+
if (text) return { hasErrors: true, errorMessages: [text], parsedData: parsed };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// iaex:exception — another SAP error envelope
|
|
63
|
+
const iaex = parsed['iaex:exception'];
|
|
64
|
+
if (iaex) {
|
|
65
|
+
const msg = iaex['iaex:message'] || iaex['message'] || '';
|
|
66
|
+
if (msg) return { hasErrors: true, errorMessages: [String(msg)], parsedData: parsed };
|
|
67
|
+
}
|
|
68
|
+
|
|
55
69
|
return { hasErrors: false, errorMessages: [], parsedData: parsed };
|
|
56
70
|
} catch (error) {
|
|
57
71
|
console.error(' âš ï¸ XML parsing failed:', error.message);
|
package/xml-utils.mjs
CHANGED
|
@@ -7,7 +7,8 @@ const xmlParser = new XMLParser({
|
|
|
7
7
|
});
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Parse SAP XML response and check for errors
|
|
10
|
+
* Parse SAP XML response and check for errors.
|
|
11
|
+
* Handles: chkrun syntax errors, exc:exception envelope, adtcore activation errors.
|
|
11
12
|
* Returns: { hasErrors: boolean, errorMessages: string[], parsedData: object }
|
|
12
13
|
*/
|
|
13
14
|
export function parseSAPResponse(xmlString) {
|
|
@@ -17,14 +18,14 @@ export function parseSAPResponse(xmlString) {
|
|
|
17
18
|
|
|
18
19
|
try {
|
|
19
20
|
const parsed = xmlParser.parse(xmlString);
|
|
20
|
-
|
|
21
|
-
//
|
|
21
|
+
|
|
22
|
+
// ── 1. Syntax check errors (chkrun:checkMessage with type="E") ──────────
|
|
22
23
|
if (parsed['chkrun:checkRunReports']) {
|
|
23
24
|
const report = parsed['chkrun:checkRunReports']['chkrun:checkReport'];
|
|
24
25
|
const messageList = report?.['chkrun:checkMessageList'];
|
|
25
|
-
|
|
26
|
+
|
|
26
27
|
if (messageList && messageList['chkrun:checkMessage']) {
|
|
27
|
-
const messages = Array.isArray(messageList['chkrun:checkMessage'])
|
|
28
|
+
const messages = Array.isArray(messageList['chkrun:checkMessage'])
|
|
28
29
|
? messageList['chkrun:checkMessage']
|
|
29
30
|
: [messageList['chkrun:checkMessage']];
|
|
30
31
|
|
|
@@ -34,9 +35,7 @@ export function parseSAPResponse(xmlString) {
|
|
|
34
35
|
let line = null;
|
|
35
36
|
if (msg['@_chkrun:uri'] && msg['@_chkrun:uri'].includes('#start=')) {
|
|
36
37
|
const match = msg['@_chkrun:uri'].match(/#start=(\d+),(\d+)/);
|
|
37
|
-
if (match)
|
|
38
|
-
line = parseInt(match[1]);
|
|
39
|
-
}
|
|
38
|
+
if (match) line = parseInt(match[1]);
|
|
40
39
|
}
|
|
41
40
|
const text = msg['@_chkrun:shortText'] || 'Unknown error';
|
|
42
41
|
const lineInfo = line ? ` (line ${line})` : '';
|
|
@@ -50,11 +49,43 @@ export function parseSAPResponse(xmlString) {
|
|
|
50
49
|
}
|
|
51
50
|
}
|
|
52
51
|
|
|
53
|
-
//
|
|
54
|
-
|
|
52
|
+
// ── 2. exc:exception — SAP ADT error envelope ────────────────────────────
|
|
53
|
+
// Used by: SQL queries, create object, activate, and most 4xx responses
|
|
54
|
+
// Formats seen:
|
|
55
|
+
// <exc:exception xmlns:exc="http://www.sap.com/abapxml/types/exception">
|
|
56
|
+
// <message>Syntax error in ABAP Open SQL: ...</message>
|
|
57
|
+
// </exc:exception>
|
|
58
|
+
// <exc:exception xmlns:exc="http://www.sap.com/abapxml/types/communicationframework">
|
|
59
|
+
// <message lang="EN">Verificacao da condicao fracassou.</message>
|
|
60
|
+
// <localizedMessage lang="PT">...</localizedMessage>
|
|
61
|
+
// </exc:exception>
|
|
62
|
+
const excKey = Object.keys(parsed).find(k => k === 'exc:exception' || k.endsWith(':exception'));
|
|
63
|
+
if (excKey) {
|
|
64
|
+
const exc = parsed[excKey];
|
|
65
|
+
let msg = null;
|
|
66
|
+
|
|
67
|
+
const msgNode = exc?.message;
|
|
68
|
+
if (typeof msgNode === 'string') {
|
|
69
|
+
msg = msgNode;
|
|
70
|
+
} else if (typeof msgNode === 'object' && msgNode !== null) {
|
|
71
|
+
const msgs = Array.isArray(msgNode) ? msgNode : [msgNode];
|
|
72
|
+
const en = msgs.find(m => m['@_lang'] === 'EN' || m['@_xml:lang'] === 'EN');
|
|
73
|
+
msg = (en ? en['#text'] : msgs[0]?.['#text']) || null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// fallback: localizedMessage
|
|
77
|
+
if (!msg) {
|
|
78
|
+
const loc = exc?.localizedMessage;
|
|
79
|
+
if (typeof loc === 'string') msg = loc;
|
|
80
|
+
else if (typeof loc === 'object' && loc !== null) msg = loc?.['#text'] || null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (msg) return { hasErrors: true, errorMessages: [msg], parsedData: parsed };
|
|
84
|
+
}
|
|
85
|
+
|
|
55
86
|
return { hasErrors: false, errorMessages: [], parsedData: parsed };
|
|
56
|
-
} catch (
|
|
57
|
-
console.error('
|
|
87
|
+
} catch (err) {
|
|
88
|
+
console.error(' XML parsing failed:', err.message);
|
|
58
89
|
return { hasErrors: false, errorMessages: [], parsedData: null };
|
|
59
90
|
}
|
|
60
91
|
}
|