@mcp-abap-adt/connection 8.0.1 → 8.1.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.
- package/CHANGELOG.md +28 -0
- package/README.md +14 -0
- package/dist/connection/RfcTransport.d.ts +23 -1
- package/dist/connection/RfcTransport.d.ts.map +1 -1
- package/dist/connection/RfcTransport.js +73 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/docs/USAGE.md +21 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [8.1.0] - 2026-09-21
|
|
11
|
+
|
|
12
|
+
**The RFC wire can be asked for its payload, and what it logs is safe to
|
|
13
|
+
paste.** `RFC → METHOD URI` did not show a body that goes missing or gets
|
|
14
|
+
mis-serialised before it reaches `SADT_REST_RFC_ENDPOINT`. Nothing existing
|
|
15
|
+
changes: the channel is off until asked for.
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- `RfcTransport` can be asked to log the wire: a third constructor argument
|
|
20
|
+
`{ logWire?, maxLoggedBodyChars? }`, off by default, adds the request header
|
|
21
|
+
fields, the request body and the response body to the debug channel. This is
|
|
22
|
+
what shows a payload that was mis-serialised before it reached
|
|
23
|
+
`SADT_REST_RFC_ENDPOINT`. Credential header values (`Authorization`, any
|
|
24
|
+
`Cookie`, anything matching `token`, `secret`, `password`, `credential` or an
|
|
25
|
+
API key) are replaced with `[redacted]` — the names are kept — and a body is
|
|
26
|
+
clipped at `maxLoggedBodyChars`, 2000 by default — `0` logs the size alone,
|
|
27
|
+
`Infinity` asks for the whole body, and a negative or `NaN` ceiling falls
|
|
28
|
+
back to the default rather than throwing. Bodies are not redacted, only
|
|
29
|
+
clipped.
|
|
30
|
+
|
|
31
|
+
It is a flag rather than something inferred from the presence of a logger
|
|
32
|
+
because `ILogger` carries no level predicate: `logger?.debug()` cannot tell
|
|
33
|
+
an enabled debug channel from one that discards, so without the flag every
|
|
34
|
+
caller passing a logger would build a copy of every body on the wire and
|
|
35
|
+
throw it away. `HttpTransport` logs no bodies at any setting.
|
|
36
|
+
|
|
10
37
|
## [8.0.1] - 2026-09-08
|
|
11
38
|
|
|
12
39
|
**Documentation only — 7.0.0 and 8.0.0 shipped without their migration note.**
|
|
@@ -1535,6 +1562,7 @@ const connection = createAbapConnection(config, logger);
|
|
|
1535
1562
|
- Permission errors (403 with "ExceptionResourceNoAccess") no longer trigger JWT refresh loops
|
|
1536
1563
|
- Proper separation: base class handles HTTP/session, concrete classes handle auth-specific errors
|
|
1537
1564
|
[Unreleased]: https://github.com/fr0ster/mcp-abap-connection/compare/v8.0.1...HEAD
|
|
1565
|
+
[8.1.0]: https://github.com/fr0ster/mcp-abap-connection/compare/v8.0.1...v8.1.0
|
|
1538
1566
|
[8.0.1]: https://github.com/fr0ster/mcp-abap-connection/compare/v8.0.0...v8.0.1
|
|
1539
1567
|
[8.0.0]: https://github.com/fr0ster/mcp-abap-connection/compare/v7.0.0...v8.0.0
|
|
1540
1568
|
[7.0.0]: https://github.com/fr0ster/mcp-abap-connection/compare/v6.1.0...v7.0.0
|
package/README.md
CHANGED
|
@@ -656,6 +656,20 @@ const connection = new AdtOnPremConnector(
|
|
|
656
656
|
);
|
|
657
657
|
```
|
|
658
658
|
|
|
659
|
+
A third argument turns on the wire log, which is off by default:
|
|
660
|
+
|
|
661
|
+
```typescript
|
|
662
|
+
new RfcTransport(rfcConversationFrom(config), logger, { logWire: true });
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
It adds three debug lines per request — header fields, request body, response
|
|
666
|
+
body — which is how you see that a payload was mis-serialised before it reached
|
|
667
|
+
`SADT_REST_RFC_ENDPOINT`. Credential header values are replaced with
|
|
668
|
+
`[redacted]` and bodies are clipped at `maxLoggedBodyChars` (2000). The bodies
|
|
669
|
+
themselves are not redacted, so read a captured log before pasting it into an
|
|
670
|
+
issue. `HttpTransport` never logs bodies, so this is the one wire whose debug
|
|
671
|
+
channel can be asked for the payload.
|
|
672
|
+
|
|
659
673
|
#### `CSRF_CONFIG` and `CSRF_ERROR_MESSAGES`
|
|
660
674
|
|
|
661
675
|
**New in 0.1.13+:** Exported constants for consistent CSRF token handling across different connection implementations.
|
|
@@ -26,9 +26,29 @@ export interface IRfcConversation {
|
|
|
26
26
|
call(fm: string, params: Record<string, unknown>): Promise<Record<string, any>>;
|
|
27
27
|
readonly alive: boolean;
|
|
28
28
|
}
|
|
29
|
+
/** What this wire does beyond carrying the request. */
|
|
30
|
+
export interface IRfcTransportOptions {
|
|
31
|
+
/**
|
|
32
|
+
* Whether the debug channel also carries the request headers and both
|
|
33
|
+
* bodies. Off by default, and deliberately not inferred from the presence
|
|
34
|
+
* of a logger: `ILogger` has no level predicate, so `logger?.debug()` cannot
|
|
35
|
+
* tell an enabled debug channel from a discarded one — without this flag
|
|
36
|
+
* every caller who passes a logger at all would pay to build and throw away
|
|
37
|
+
* a copy of every body on the wire.
|
|
38
|
+
*/
|
|
39
|
+
logWire?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Ceiling on a logged body, in characters. Defaults to 2000. `0` logs the
|
|
42
|
+
* size and none of the bytes, `Infinity` asks for the whole body, and a
|
|
43
|
+
* negative or `NaN` value falls back to the default rather than throwing —
|
|
44
|
+
* a debug option is not worth failing a connection over.
|
|
45
|
+
*/
|
|
46
|
+
maxLoggedBodyChars?: number;
|
|
47
|
+
}
|
|
29
48
|
export declare class RfcTransport implements IOnPremTransport {
|
|
30
49
|
private readonly connect;
|
|
31
50
|
private readonly logger;
|
|
51
|
+
private readonly options;
|
|
32
52
|
readonly kind = "rfc";
|
|
33
53
|
/** Which system this wire is for. Read by the compiler, never at runtime. */
|
|
34
54
|
readonly system: "onprem";
|
|
@@ -80,7 +100,9 @@ export declare class RfcTransport implements IOnPremTransport {
|
|
|
80
100
|
* that reached for it in its constructor could not be built at all on a
|
|
81
101
|
* machine without it.
|
|
82
102
|
*/
|
|
83
|
-
constructor(connect: () => IRfcConversation, logger?: ILogger | null);
|
|
103
|
+
constructor(connect: () => IRfcConversation, logger?: ILogger | null, options?: IRfcTransportOptions);
|
|
104
|
+
/** Cut a body down to what a log line may carry. */
|
|
105
|
+
private clipped;
|
|
84
106
|
open(): Promise<void>;
|
|
85
107
|
/** Never throws, and a repeat call finds nothing owed. */
|
|
86
108
|
close(): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RfcTransport.d.ts","sourceRoot":"","sources":["../../src/connection/RfcTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EACV,oBAAoB,EAEpB,oBAAoB,EACpB,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,oBAAoB,CAAC;AAE5B,sFAAsF;AACtF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,CACF,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;
|
|
1
|
+
{"version":3,"file":"RfcTransport.d.ts","sourceRoot":"","sources":["../../src/connection/RfcTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EACV,oBAAoB,EAEpB,oBAAoB,EACpB,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,oBAAoB,CAAC;AAE5B,sFAAsF;AACtF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,CACF,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAgFD,uDAAuD;AACvD,MAAM,WAAW,oBAAoB;IACnC;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAKD,qBAAa,YAAa,YAAW,gBAAgB;IA+EjD,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAhF1B,QAAQ,CAAC,IAAI,SAAS;IAEtB,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAG,QAAQ,CAAU;IAEpC,OAAO,CAAC,YAAY,CAAiC;IACrD,kEAAkE;IAClE,OAAO,CAAC,cAAc,CAAM;IAE5B;;;;;;OAMG;IACH,MAAM,IAAI,IAAI;IAEd,2CAA2C;IAC3C,OAAO,IAAI,IAAI;IAIf;;;;;OAKG;IACG,SAAS,CAAC,QAAQ,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAE9D,+BAA+B;IAC/B,SAAS,IAAI,IAAI;IAIjB;;;OAGG;IACH,cAAc,IAAI,IAAI;IAEtB;;;OAGG;IACH,6EAA6E;IAC7E,kBAAkB,IAAI,OAAO;IAI7B,kBAAkB,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAQzC,2EAA2E;IAC3E,eAAe,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAIzC;;;;OAIG;IACH,aAAa,IAAI,IAAI;IAErB;;;;;OAKG;gBAEgB,OAAO,EAAE,MAAM,gBAAgB,EAC/B,MAAM,GAAE,OAAO,GAAG,IAAW,EAC7B,OAAO,GAAE,oBAAyB;IAGrD,oDAAoD;IACpD,OAAO,CAAC,OAAO;IAcT,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAiB3B,0DAA0D;IACpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAatB,IAAI,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;CAkK1E"}
|
|
@@ -48,11 +48,52 @@ function message(e) {
|
|
|
48
48
|
return JSON.stringify(e);
|
|
49
49
|
return String(e);
|
|
50
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Header names whose VALUE must never reach a log.
|
|
53
|
+
*
|
|
54
|
+
* `Authorization` carries the Basic-auth credential in plain (base64, but that
|
|
55
|
+
* is not encryption) form — and it is not the only one. `request.headers`
|
|
56
|
+
* reaches this wire verbatim from the caller, so a consumer's `Cookie`
|
|
57
|
+
* (`SAP_SESSIONID_*`, `MYSAPSSO2`), an `x-csrf-token` or its own `X-Api-Key`
|
|
58
|
+
* arrives here too. A log line advertised as safe to paste into an issue has
|
|
59
|
+
* to be safe for the headers nobody here anticipated, so this matches by
|
|
60
|
+
* pattern rather than by the list we happened to think of.
|
|
61
|
+
*/
|
|
62
|
+
const SECRET_HEADER_PATTERNS = [
|
|
63
|
+
/authorization/i,
|
|
64
|
+
/cookie/i,
|
|
65
|
+
/token/i,
|
|
66
|
+
/secret/i,
|
|
67
|
+
/password/i,
|
|
68
|
+
/credential/i,
|
|
69
|
+
/api[-_]?key/i,
|
|
70
|
+
];
|
|
71
|
+
/**
|
|
72
|
+
* The NAME is kept and only the VALUE goes — a redacted header still says it
|
|
73
|
+
* was sent, which is half of what the log is read for.
|
|
74
|
+
*/
|
|
75
|
+
function redactHeaders(fields) {
|
|
76
|
+
return fields.map((field) => SECRET_HEADER_PATTERNS.some((pattern) => pattern.test(field.NAME))
|
|
77
|
+
? { ...field, VALUE: '[redacted]' }
|
|
78
|
+
: field);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* How much of a body a log line carries before it is cut. An ADT payload is
|
|
82
|
+
* an ABAP source or a repository listing: whole ones are megabytes, and a log
|
|
83
|
+
* sink handed a single line that size is a problem of its own.
|
|
84
|
+
*/
|
|
85
|
+
const DEFAULT_MAX_LOGGED_BODY_CHARS = 2000;
|
|
86
|
+
function clip(text, max) {
|
|
87
|
+
return text.length <= max
|
|
88
|
+
? text
|
|
89
|
+
: `${text.slice(0, max)}… (+${text.length - max} more chars)`;
|
|
90
|
+
}
|
|
51
91
|
/** Axios's own default, which the classification above this seam is written against. */
|
|
52
92
|
const admits2xx = (status) => status >= 200 && status < 300;
|
|
53
93
|
class RfcTransport {
|
|
54
94
|
connect;
|
|
55
95
|
logger;
|
|
96
|
+
options;
|
|
56
97
|
kind = 'rfc';
|
|
57
98
|
/** Which system this wire is for. Read by the compiler, never at runtime. */
|
|
58
99
|
system = 'onprem';
|
|
@@ -118,9 +159,22 @@ class RfcTransport {
|
|
|
118
159
|
* that reached for it in its constructor could not be built at all on a
|
|
119
160
|
* machine without it.
|
|
120
161
|
*/
|
|
121
|
-
constructor(connect, logger = null) {
|
|
162
|
+
constructor(connect, logger = null, options = {}) {
|
|
122
163
|
this.connect = connect;
|
|
123
164
|
this.logger = logger;
|
|
165
|
+
this.options = options;
|
|
166
|
+
}
|
|
167
|
+
/** Cut a body down to what a log line may carry. */
|
|
168
|
+
clipped(text) {
|
|
169
|
+
const asked = this.options.maxLoggedBodyChars ?? DEFAULT_MAX_LOGGED_BODY_CHARS;
|
|
170
|
+
// A nonsense ceiling is a typo in a debug option, and a debug option is
|
|
171
|
+
// not worth failing a connection over — but it is worth not honouring. A
|
|
172
|
+
// negative one reaches `slice(0, -n)`, which drops the END of the body
|
|
173
|
+
// while the line still says the rest was merely clipped: a log that lies
|
|
174
|
+
// about what it cut is worse than one that cut too much. `NaN` compares
|
|
175
|
+
// false against every bound, so the test is for the good case.
|
|
176
|
+
const ceiling = asked >= 0 ? Math.floor(asked) : DEFAULT_MAX_LOGGED_BODY_CHARS;
|
|
177
|
+
return clip(text, ceiling);
|
|
124
178
|
}
|
|
125
179
|
async open() {
|
|
126
180
|
if (this.conversation?.alive)
|
|
@@ -187,6 +241,19 @@ class RfcTransport {
|
|
|
187
241
|
});
|
|
188
242
|
}
|
|
189
243
|
this.logger?.debug(`RFC → ${method} ${uri}`);
|
|
244
|
+
// `RFC → METHOD URI` alone was not enough to debug a body that goes
|
|
245
|
+
// missing or gets mis-serialised on the way to `SADT_REST_RFC_ENDPOINT`
|
|
246
|
+
// (found chasing a `superPackage` that disappeared before it reached
|
|
247
|
+
// SAP) — the actual bytes matter, so the debug channel carries them too
|
|
248
|
+
// when the caller asks for it, redacted and clipped so a captured log is
|
|
249
|
+
// safe to paste into an issue and small enough to want to.
|
|
250
|
+
if (this.logger && this.options.logWire) {
|
|
251
|
+
this.logger.debug(`RFC HEADERS: ${JSON.stringify(redactHeaders(headerFields))}`);
|
|
252
|
+
// A GET has no body, and `RFC BODY (0 chars):` says nothing.
|
|
253
|
+
if (body) {
|
|
254
|
+
this.logger.debug(`RFC BODY (${body.length} chars): ${this.clipped(body)}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
190
257
|
// `request.timeout` is deliberately not read, and the absence of the word
|
|
191
258
|
// here is what made that look like an oversight (#42).
|
|
192
259
|
//
|
|
@@ -252,6 +319,11 @@ class RfcTransport {
|
|
|
252
319
|
statusText = statusText || 'OK';
|
|
253
320
|
}
|
|
254
321
|
this.logger?.debug(`RFC ← ${status} ${statusText} (${data.length} bytes)`);
|
|
322
|
+
// The line above already carries the size, so an empty body needs no line
|
|
323
|
+
// of its own.
|
|
324
|
+
if (this.logger && this.options.logWire && data) {
|
|
325
|
+
this.logger.debug(`RFC RESPONSE BODY: ${this.clipped(data)}`);
|
|
326
|
+
}
|
|
255
327
|
const response = {
|
|
256
328
|
status,
|
|
257
329
|
statusText,
|
package/dist/index.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export { HttpTransport } from './connection/HttpTransport.js';
|
|
|
13
13
|
export type { IAdtEstablishContext, IAdtSessionContext, IAdtTransport, IAdtTransportRequest, IAdtTransportResponse, ICloudTransport, IOnPremTransport, } from './connection/IAdtTransport.js';
|
|
14
14
|
export { LegacyOnPremHttpTransport } from './connection/LegacyOnPremHttpTransport.js';
|
|
15
15
|
export { OnPremHttpTransport } from './connection/OnPremHttpTransport.js';
|
|
16
|
-
export { type IRfcConversation, RfcTransport, } from './connection/RfcTransport.js';
|
|
16
|
+
export { type IRfcConversation, type IRfcTransportOptions, RfcTransport, } from './connection/RfcTransport.js';
|
|
17
17
|
export { type RfcConnectionParams, rfcConversationFrom, rfcParamsFrom, } from './connection/rfcConversation.js';
|
|
18
18
|
export type { ILogger } from './logger.js';
|
|
19
19
|
export { getTimeout, getTimeoutConfig, type TimeoutConfig, } from './utils/timeouts.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,YAAY,EACV,mBAAmB,EACnB,wBAAwB,EACxB,yBAAyB,EACzB,wBAAwB,EACxB,mBAAmB,GACpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,6BAA6B,EAAE,MAAM,yCAAyC,CAAC;AAKxF,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,WAAW,EACX,SAAS,EACT,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D,YAAY,EACV,cAAc,EACd,kBAAkB,GACnB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAQxE,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EACL,yBAAyB,EACzB,KAAK,iBAAiB,EACtB,KAAK,cAAc,GACpB,MAAM,2CAA2C,CAAC;AAEnD,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,YAAY,EACV,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,EACb,oBAAoB,EACpB,qBAAqB,EACrB,eAAe,EACf,gBAAgB,GACjB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,yBAAyB,EAAE,MAAM,2CAA2C,CAAC;AACtF,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,EACL,KAAK,gBAAgB,EACrB,YAAY,GACb,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EACL,KAAK,mBAAmB,EACxB,mBAAmB,EACnB,aAAa,GACd,MAAM,iCAAiC,CAAC;AACzC,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,KAAK,aAAa,GACnB,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,YAAY,EACV,mBAAmB,EACnB,wBAAwB,EACxB,yBAAyB,EACzB,wBAAwB,EACxB,mBAAmB,GACpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,6BAA6B,EAAE,MAAM,yCAAyC,CAAC;AAKxF,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,WAAW,EACX,SAAS,EACT,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D,YAAY,EACV,cAAc,EACd,kBAAkB,GACnB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAQxE,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EACL,yBAAyB,EACzB,KAAK,iBAAiB,EACtB,KAAK,cAAc,GACpB,MAAM,2CAA2C,CAAC;AAEnD,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,YAAY,EACV,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,EACb,oBAAoB,EACpB,qBAAqB,EACrB,eAAe,EACf,gBAAgB,GACjB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,yBAAyB,EAAE,MAAM,2CAA2C,CAAC;AACtF,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,YAAY,GACb,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EACL,KAAK,mBAAmB,EACxB,mBAAmB,EACnB,aAAa,GACd,MAAM,iCAAiC,CAAC;AACzC,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,KAAK,aAAa,GACnB,MAAM,qBAAqB,CAAC"}
|
package/docs/USAGE.md
CHANGED
|
@@ -794,7 +794,7 @@ establishing, and whatever session state it keeps.
|
|
|
794
794
|
|
|
795
795
|
```text
|
|
796
796
|
new HttpTransport(agentOptions?, logger?, { client?, baseUrl? })
|
|
797
|
-
new RfcTransport(connect: () => IRfcConversation, logger?)
|
|
797
|
+
new RfcTransport(connect: () => IRfcConversation, logger?, { logWire?, maxLoggedBodyChars? })
|
|
798
798
|
```
|
|
799
799
|
|
|
800
800
|
`HttpTransport` is the ordinary wire, and you name it because the connector
|
|
@@ -804,6 +804,26 @@ what the connectors' type parameters admit. `RfcTransport`
|
|
|
804
804
|
you build with `rfcConversationFrom(config)`, which derives `ashost` and `sysnr`
|
|
805
805
|
and loads the SAP NW RFC SDK only when a conversation opens.
|
|
806
806
|
|
|
807
|
+
**`logWire` dumps the wire, and is off.** With it on, `RfcTransport` adds three
|
|
808
|
+
debug lines per request — the header fields, the request body and the response
|
|
809
|
+
body — which is what tells you a payload was mis-serialised before it reached
|
|
810
|
+
`SADT_REST_RFC_ENDPOINT`. Credential header values (`Authorization`, any
|
|
811
|
+
`Cookie`, anything matching `token`, `secret`, `password`, `credential` or an
|
|
812
|
+
API key) are replaced with `[redacted]`, the names are kept, and a body is cut
|
|
813
|
+
at `maxLoggedBodyChars` (2000 by default) so a class source does not arrive as
|
|
814
|
+
one multi-megabyte line — `0` logs the size alone, `Infinity` asks for the
|
|
815
|
+
whole body, and a negative or `NaN` ceiling falls back to the default instead
|
|
816
|
+
of throwing. Read what you captured before pasting it anywhere: a
|
|
817
|
+
body is not redacted, only clipped.
|
|
818
|
+
|
|
819
|
+
It is a flag and not something inferred from the logger, because `ILogger` has
|
|
820
|
+
no level predicate — `logger?.debug()` cannot tell an enabled debug channel
|
|
821
|
+
from one that discards. Without the flag, every caller who passes a logger at
|
|
822
|
+
all would pay to build a copy of every body on the wire and throw it away.
|
|
823
|
+
`HttpTransport` logs no bodies at any setting, so "turn debug on" means
|
|
824
|
+
different things on the two wires; this is the only one that can be asked for
|
|
825
|
+
the payload.
|
|
826
|
+
|
|
807
827
|
The two differ in what they have, not in what they are asked:
|
|
808
828
|
|
|
809
829
|
| | HTTP | RFC |
|