@mcp-abap-adt/connection 5.0.0 → 6.0.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.
Files changed (91) hide show
  1. package/CHANGELOG.md +134 -1
  2. package/README.md +204 -48
  3. package/dist/auth/providers.d.ts +38 -9
  4. package/dist/auth/providers.d.ts.map +1 -1
  5. package/dist/auth/providers.js +46 -3
  6. package/dist/connection/AbstractAbapConnection.d.ts +83 -136
  7. package/dist/connection/AbstractAbapConnection.d.ts.map +1 -1
  8. package/dist/connection/AbstractAbapConnection.js +241 -763
  9. package/dist/connection/AdtCloudConnector.d.ts +12 -7
  10. package/dist/connection/AdtCloudConnector.d.ts.map +1 -1
  11. package/dist/connection/AdtCloudConnector.js +2 -6
  12. package/dist/connection/AdtOnPremConnector.d.ts +20 -7
  13. package/dist/connection/AdtOnPremConnector.d.ts.map +1 -1
  14. package/dist/connection/AdtOnPremConnector.js +2 -6
  15. package/dist/connection/CloudHttpTransport.d.ts +37 -0
  16. package/dist/connection/CloudHttpTransport.d.ts.map +1 -0
  17. package/dist/{session/CloudSecuritySessionStrategy.js → connection/CloudHttpTransport.js} +59 -49
  18. package/dist/connection/CredentialAbapConnection.d.ts +8 -41
  19. package/dist/connection/CredentialAbapConnection.d.ts.map +1 -1
  20. package/dist/connection/CredentialAbapConnection.js +44 -111
  21. package/dist/connection/HttpTransport.d.ts +178 -0
  22. package/dist/connection/HttpTransport.d.ts.map +1 -0
  23. package/dist/connection/HttpTransport.js +402 -0
  24. package/dist/connection/IAdtTransport.d.ts +232 -0
  25. package/dist/connection/IAdtTransport.d.ts.map +1 -0
  26. package/dist/connection/IAdtTransport.js +28 -0
  27. package/dist/connection/LegacyOnPremHttpTransport.d.ts +40 -0
  28. package/dist/connection/LegacyOnPremHttpTransport.d.ts.map +1 -0
  29. package/dist/connection/LegacyOnPremHttpTransport.js +57 -0
  30. package/dist/connection/OnPremHttpTransport.d.ts +45 -0
  31. package/dist/connection/OnPremHttpTransport.d.ts.map +1 -0
  32. package/dist/connection/OnPremHttpTransport.js +91 -0
  33. package/dist/connection/RfcTransport.d.ts +89 -0
  34. package/dist/connection/RfcTransport.d.ts.map +1 -0
  35. package/dist/connection/RfcTransport.js +256 -0
  36. package/dist/connection/rfcConversation.d.ts +44 -0
  37. package/dist/connection/rfcConversation.d.ts.map +1 -0
  38. package/dist/connection/rfcConversation.js +71 -0
  39. package/dist/index.d.ts +7 -8
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +21 -18
  42. package/dist/utils/timeouts.d.ts +6 -19
  43. package/dist/utils/timeouts.d.ts.map +1 -1
  44. package/dist/utils/timeouts.js +6 -22
  45. package/docs/INDEX.md +5 -2
  46. package/docs/INSTALLATION.md +28 -10
  47. package/docs/JWT_AUTH_TOOLS.md +20 -4
  48. package/docs/MIGRATION-6.0.md +359 -0
  49. package/docs/SCOPE.md +1 -1
  50. package/docs/STATEFUL_SESSION_GUIDE.md +86 -17
  51. package/docs/USAGE.md +260 -119
  52. package/examples/basic-connection.js +15 -3
  53. package/examples/jwt-with-token-refresh.js +15 -7
  54. package/examples/saml-connection.js +15 -2
  55. package/package.json +12 -10
  56. package/dist/__tests__/helpers/session.d.ts +0 -15
  57. package/dist/__tests__/helpers/session.d.ts.map +0 -1
  58. package/dist/__tests__/helpers/session.js +0 -19
  59. package/dist/auth/IAuthProvider.d.ts +0 -84
  60. package/dist/auth/IAuthProvider.d.ts.map +0 -1
  61. package/dist/auth/IAuthProvider.js +0 -21
  62. package/dist/connection/BaseAbapConnection.d.ts +0 -29
  63. package/dist/connection/BaseAbapConnection.d.ts.map +0 -1
  64. package/dist/connection/BaseAbapConnection.js +0 -81
  65. package/dist/connection/CertificateAbapConnection.d.ts +0 -35
  66. package/dist/connection/CertificateAbapConnection.d.ts.map +0 -1
  67. package/dist/connection/CertificateAbapConnection.js +0 -91
  68. package/dist/connection/JwtAbapConnection.d.ts +0 -131
  69. package/dist/connection/JwtAbapConnection.d.ts.map +0 -1
  70. package/dist/connection/JwtAbapConnection.js +0 -376
  71. package/dist/connection/KerberosAbapConnection.d.ts +0 -32
  72. package/dist/connection/KerberosAbapConnection.d.ts.map +0 -1
  73. package/dist/connection/KerberosAbapConnection.js +0 -128
  74. package/dist/connection/RfcAbapConnection.d.ts +0 -44
  75. package/dist/connection/RfcAbapConnection.d.ts.map +0 -1
  76. package/dist/connection/RfcAbapConnection.js +0 -324
  77. package/dist/connection/SamlAbapConnection.d.ts +0 -31
  78. package/dist/connection/SamlAbapConnection.d.ts.map +0 -1
  79. package/dist/connection/SamlAbapConnection.js +0 -81
  80. package/dist/connection/connectionFactory.d.ts +0 -25
  81. package/dist/connection/connectionFactory.d.ts.map +0 -1
  82. package/dist/connection/connectionFactory.js +0 -84
  83. package/dist/session/CloudSecuritySessionStrategy.d.ts +0 -32
  84. package/dist/session/CloudSecuritySessionStrategy.d.ts.map +0 -1
  85. package/dist/session/IcfSessionStrategy.d.ts +0 -27
  86. package/dist/session/IcfSessionStrategy.d.ts.map +0 -1
  87. package/dist/session/IcfSessionStrategy.js +0 -62
  88. package/dist/session/SessionStrategy.d.ts +0 -86
  89. package/dist/session/SessionStrategy.d.ts.map +0 -1
  90. package/dist/session/SessionStrategy.js +0 -33
  91. package/docs/superpowers/specs/2026-08-21-platform-connectors.md +0 -108
@@ -0,0 +1,256 @@
1
+ "use strict";
2
+ /**
3
+ * An ADT request carried over RFC.
4
+ *
5
+ * `SADT_REST_RFC_ENDPOINT` is the standard FM Eclipse ADT uses for on-prem ADT
6
+ * through JCo, and what it carries is a request line, header fields and a body
7
+ * — an HTTP request in all but the wire. So this translates, and translating is
8
+ * the whole of its job.
9
+ *
10
+ * It exists because an RFC conversation is inherently stateful: one ABAP
11
+ * session for the connection's lifetime, which is the way through HTTP 423
12
+ * "invalid lock handle" on legacy systems (BASIS < 7.50) where stateful HTTP
13
+ * sessions are not usable.
14
+ *
15
+ * **What is NOT here.** Cookies, the CSRF token, `x-sap-adt-sessiontype` and
16
+ * the session lifecycle belong to the connection above this seam and are
17
+ * already in `request.headers` by the time `send()` is called. A transport that
18
+ * also captured cookies would be doing that work twice, and the two copies
19
+ * would disagree the first time one of them was cleared.
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.RfcTransport = void 0;
23
+ const node_crypto_1 = require("node:crypto");
24
+ /**
25
+ * ADT exception types, mapped to what they would have been over HTTP. Standard
26
+ * types, returned in `<exc:exception>` XML.
27
+ */
28
+ const EXCEPTION_STATUS = {
29
+ ExceptionResourceNotFound: { code: 404, text: 'Not Found' },
30
+ ExceptionResourceNoAuthorization: { code: 403, text: 'Forbidden' },
31
+ ExceptionResourceAlreadyExists: { code: 409, text: 'Conflict' },
32
+ ExceptionResourceLocked: { code: 423, text: 'Locked' },
33
+ ExceptionBadRequest: { code: 400, text: 'Bad Request' },
34
+ ExceptionNotSupported: { code: 501, text: 'Not Implemented' },
35
+ ExceptionConflict: { code: 409, text: 'Conflict' },
36
+ };
37
+ function statusFromExceptionXml(body) {
38
+ const type = /<exc:type[^>]*>([^<]+)<\/exc:type>/.exec(body)?.[1]?.trim();
39
+ return ((type ? EXCEPTION_STATUS[type] : undefined) ?? {
40
+ code: 500,
41
+ text: 'Internal Server Error',
42
+ });
43
+ }
44
+ function message(e) {
45
+ if (e instanceof Error)
46
+ return e.message;
47
+ if (e && typeof e === 'object')
48
+ return JSON.stringify(e);
49
+ return String(e);
50
+ }
51
+ /** Axios's own default, which the classification above this seam is written against. */
52
+ const admits2xx = (status) => status >= 200 && status < 300;
53
+ class RfcTransport {
54
+ connect;
55
+ logger;
56
+ kind = 'rfc';
57
+ /** Which system this wire is for. Read by the compiler, never at runtime. */
58
+ system = 'onprem';
59
+ conversation = null;
60
+ /** Names the conversation, and so the ABAP session it carries. */
61
+ conversationId = '';
62
+ /**
63
+ * Nothing to fold in. `SADT_REST_RFC_ENDPOINT` answers with two header
64
+ * fields — `~server_protocol` and `content-type` — on every call, including
65
+ * one that asks for a token with `x-csrf-token: fetch`, and on a stateful
66
+ * POST. Measured on E19. There is no ICM in this path, so there is no ICF
67
+ * session to cookie and no application server to be redispatched between.
68
+ */
69
+ ingest() { }
70
+ /** None, and never any: see `ingest()`. */
71
+ cookies() {
72
+ return null;
73
+ }
74
+ /**
75
+ * Nothing to establish. `open()` made the ABAP session, and there is no token
76
+ * to earn: this endpoint answers `x-csrf-token: fetch` with the same two
77
+ * header fields it answers everything else with. A wire with no
78
+ * cross-site request to forge against needs no token to prove one was not.
79
+ */
80
+ async establish(_context) { }
81
+ /** None: see `establish()`. */
82
+ csrfToken() {
83
+ return null;
84
+ }
85
+ /**
86
+ * Ignored. Nothing on this wire reads a token, and keeping one would be
87
+ * state that never leaves the object.
88
+ */
89
+ adoptCsrfToken() { }
90
+ /**
91
+ * The conversation, which IS the session — so it is fingerprinted by its own
92
+ * existence rather than by an address the server hands out.
93
+ */
94
+ /** The conversation IS the session, so it exists exactly while that does. */
95
+ sessionEstablished() {
96
+ return this.conversation?.alive ?? false;
97
+ }
98
+ sessionFingerprint() {
99
+ const fingerprint = new Map();
100
+ if (this.conversation?.alive) {
101
+ fingerprint.set('rfc-conversation', this.conversationId);
102
+ }
103
+ return fingerprint;
104
+ }
105
+ /** None: there is no dispatcher in front of this wire to stay bound to. */
106
+ affinityHeaders() {
107
+ return {};
108
+ }
109
+ /**
110
+ * Nothing to forget separately. The session ends when the conversation does,
111
+ * and that is `close()` — a wire whose state could be dropped while the
112
+ * conversation stayed open would be claiming a session it had disowned.
113
+ */
114
+ forgetSession() { }
115
+ /**
116
+ * The client is built by a factory rather than constructed here: the SDK is
117
+ * an optional dependency loaded by `require` at open time, and a transport
118
+ * that reached for it in its constructor could not be built at all on a
119
+ * machine without it.
120
+ */
121
+ constructor(connect, logger = null) {
122
+ this.connect = connect;
123
+ this.logger = logger;
124
+ }
125
+ async open() {
126
+ if (this.conversation?.alive)
127
+ return;
128
+ const conversation = this.connect();
129
+ try {
130
+ await conversation.open();
131
+ }
132
+ catch (e) {
133
+ throw new Error(`Failed to open RFC connection: ${message(e)}`);
134
+ }
135
+ this.conversation = conversation;
136
+ // Minted here, where the session begins. A conversation opened after an
137
+ // earlier one closed is a DIFFERENT ABAP session, and the fingerprint has
138
+ // to say so — a constant would report `unchanged` across a reconnect and
139
+ // hide exactly the replacement the identity policy exists to catch.
140
+ this.conversationId = (0, node_crypto_1.randomUUID)();
141
+ this.logger?.debug('RFC conversation opened (stateful by nature)');
142
+ }
143
+ /** Never throws, and a repeat call finds nothing owed. */
144
+ async close() {
145
+ const conversation = this.conversation;
146
+ if (!conversation)
147
+ return;
148
+ this.conversation = null;
149
+ this.conversationId = '';
150
+ try {
151
+ await conversation.close();
152
+ this.logger?.debug('RFC conversation closed');
153
+ }
154
+ catch (e) {
155
+ this.logger?.debug(`RFC close error: ${message(e)}`);
156
+ }
157
+ }
158
+ async send(request) {
159
+ if (!this.conversation?.alive) {
160
+ throw new Error('RFC transport is not open. Call connect() first.');
161
+ }
162
+ const method = request.method.toUpperCase();
163
+ // HTTP clients serialise `params`; RFC has no such step, so they go into
164
+ // the URI here or they do not travel at all.
165
+ let uri = request.url;
166
+ const query = Object.entries(request.params ?? {}).filter(([, v]) => v !== undefined && v !== null);
167
+ if (query.length > 0) {
168
+ const serialised = new URLSearchParams(query.map(([k, v]) => [k, String(v)])).toString();
169
+ uri += (uri.includes('?') ? '&' : '?') + serialised;
170
+ }
171
+ const headerFields = Object.entries(request.headers ?? {}).map(([NAME, VALUE]) => ({ NAME, VALUE: String(VALUE) }));
172
+ // ADT refuses a request with no Accept — `400 ExceptionResourceBadRequest:
173
+ // Accept header missing`, measured on E19. Over HTTP axios supplies the
174
+ // default and nobody notices; this endpoint forwards only what it is
175
+ // handed, so without this the same call dies on this wire alone.
176
+ if (!headerFields.some((h) => h.NAME.toLowerCase() === 'accept')) {
177
+ headerFields.push({ NAME: 'Accept', VALUE: '*/*' });
178
+ }
179
+ const body = request.data !== undefined && request.data !== null
180
+ ? String(request.data)
181
+ : '';
182
+ if (body &&
183
+ !headerFields.some((h) => h.NAME.toLowerCase() === 'content-type')) {
184
+ headerFields.push({
185
+ NAME: 'Content-Type',
186
+ VALUE: 'text/plain; charset=utf-8',
187
+ });
188
+ }
189
+ this.logger?.debug(`RFC → ${method} ${uri}`);
190
+ let raw;
191
+ try {
192
+ raw = await this.conversation.call('SADT_REST_RFC_ENDPOINT', {
193
+ REQUEST: {
194
+ REQUEST_LINE: {
195
+ METHOD: method,
196
+ URI: uri,
197
+ VERSION: 'HTTP/1.1',
198
+ },
199
+ HEADER_FIELDS: headerFields,
200
+ MESSAGE_BODY: body ? Buffer.from(body, 'utf-8') : Buffer.alloc(0),
201
+ },
202
+ });
203
+ }
204
+ catch (e) {
205
+ // An RFC-level failure, not an answer: nothing came back to classify.
206
+ const msg = message(e);
207
+ this.logger?.error(`RFC call failed: ${msg}`);
208
+ throw new Error(`RFC call to SADT_REST_RFC_ENDPOINT failed: ${msg}`);
209
+ }
210
+ const answer = raw.RESPONSE ?? raw;
211
+ const rawCode = answer.STATUS_LINE?.STATUS_CODE ?? answer.STATUS_LINE?.CODE;
212
+ let status = typeof rawCode === 'string'
213
+ ? Number.parseInt(rawCode, 10)
214
+ : (rawCode ?? 0);
215
+ let statusText = answer.STATUS_LINE?.REASON_PHRASE ?? answer.STATUS_LINE?.REASON ?? '';
216
+ const data = answer.MESSAGE_BODY
217
+ ? Buffer.isBuffer(answer.MESSAGE_BODY)
218
+ ? answer.MESSAGE_BODY.toString('utf-8')
219
+ : String(answer.MESSAGE_BODY)
220
+ : '';
221
+ const headers = {};
222
+ for (const field of answer.HEADER_FIELDS ?? []) {
223
+ if (field.NAME && field.VALUE !== undefined) {
224
+ headers[String(field.NAME).toLowerCase()] = field.VALUE;
225
+ }
226
+ }
227
+ // BASIS < 7.50 answers without populating STATUS_LINE. Left alone, a
228
+ // failure would read as 200 with an error document in the body — which is
229
+ // the green run that inspected nothing, one layer down.
230
+ if (!status && data.includes('<exc:exception')) {
231
+ const detected = statusFromExceptionXml(data);
232
+ status = detected.code;
233
+ statusText = detected.text;
234
+ this.logger?.debug(`RFC: STATUS_LINE empty, read ${status} out of the exception XML`);
235
+ }
236
+ if (!status) {
237
+ status = 200;
238
+ statusText = statusText || 'OK';
239
+ }
240
+ this.logger?.debug(`RFC ← ${status} ${statusText} (${data.length} bytes)`);
241
+ const response = {
242
+ status,
243
+ statusText,
244
+ headers,
245
+ data,
246
+ };
247
+ const admits = request.validateStatus ?? admits2xx;
248
+ if (!admits(status)) {
249
+ const error = new Error(`Request failed with status ${status}: ${method} ${uri}`);
250
+ error.response = response;
251
+ throw error;
252
+ }
253
+ return response;
254
+ }
255
+ }
256
+ exports.RfcTransport = RfcTransport;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * An RFC conversation, from the config a consumer already holds.
3
+ *
4
+ * `RfcTransport` takes a factory rather than connection parameters, and that is
5
+ * deliberate: `@mcp-abap-adt/sap-rfc-lite` needs the SAP NW RFC SDK on the
6
+ * machine, and a transport that reached for it in its constructor could not be
7
+ * built at all where it is absent. But a factory is a poor front door — without
8
+ * this, reaching the RFC wire means every consumer writing the `require` and
9
+ * deriving `ashost` and `sysnr` for themselves, which is the derivation the
10
+ * per-transport connection class used to do for them.
11
+ *
12
+ * So the derivation lives here, once, and the SDK is still only touched when a
13
+ * conversation is actually opened.
14
+ */
15
+ import type { SapConfig } from '../config/sapConfig.js';
16
+ import type { IRfcConversation } from './RfcTransport.js';
17
+ /** What the native client is constructed with. */
18
+ export interface RfcConnectionParams {
19
+ ashost: string;
20
+ sysnr: string;
21
+ client: string;
22
+ user: string;
23
+ passwd: string;
24
+ lang: string;
25
+ }
26
+ /**
27
+ * Read out of the config, never asked of the server.
28
+ *
29
+ * The system number comes off the HTTP port by the SAP convention that 80XX is
30
+ * the ICM port for system XX — the convention the port itself follows, not a
31
+ * guess about the deployment. `SAP_SYSNR` overrides it for a port that follows
32
+ * no convention, which is the case on a system reached through 50400.
33
+ */
34
+ export declare function rfcParamsFrom(config: SapConfig): RfcConnectionParams;
35
+ /**
36
+ * The factory `RfcTransport` asks for.
37
+ *
38
+ * The SDK is loaded when a conversation is opened, not when this is called, so
39
+ * a consumer can build the transport on a machine that has no SDK and find out
40
+ * at `connect()` rather than at construction — with a message that says what to
41
+ * install.
42
+ */
43
+ export declare function rfcConversationFrom(config: SapConfig): () => IRfcConversation;
44
+ //# sourceMappingURL=rfcConversation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rfcConversation.d.ts","sourceRoot":"","sources":["../../src/connection/rfcConversation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,kDAAkD;AAClD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,mBAAmB,CAoBpE;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,gBAAgB,CAmB7E"}
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ /**
3
+ * An RFC conversation, from the config a consumer already holds.
4
+ *
5
+ * `RfcTransport` takes a factory rather than connection parameters, and that is
6
+ * deliberate: `@mcp-abap-adt/sap-rfc-lite` needs the SAP NW RFC SDK on the
7
+ * machine, and a transport that reached for it in its constructor could not be
8
+ * built at all where it is absent. But a factory is a poor front door — without
9
+ * this, reaching the RFC wire means every consumer writing the `require` and
10
+ * deriving `ashost` and `sysnr` for themselves, which is the derivation the
11
+ * per-transport connection class used to do for them.
12
+ *
13
+ * So the derivation lives here, once, and the SDK is still only touched when a
14
+ * conversation is actually opened.
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.rfcParamsFrom = rfcParamsFrom;
18
+ exports.rfcConversationFrom = rfcConversationFrom;
19
+ /**
20
+ * Read out of the config, never asked of the server.
21
+ *
22
+ * The system number comes off the HTTP port by the SAP convention that 80XX is
23
+ * the ICM port for system XX — the convention the port itself follows, not a
24
+ * guess about the deployment. `SAP_SYSNR` overrides it for a port that follows
25
+ * no convention, which is the case on a system reached through 50400.
26
+ */
27
+ function rfcParamsFrom(config) {
28
+ if (!config.url) {
29
+ throw new Error('An RFC conversation needs a url to take its host from');
30
+ }
31
+ if (!config.username || !config.password) {
32
+ throw new Error('An RFC conversation needs both a username and a password');
33
+ }
34
+ const parsed = new URL(config.url);
35
+ const port = Number.parseInt(parsed.port || '8000', 10);
36
+ const derived = String(port - 8000).padStart(2, '0');
37
+ return {
38
+ ashost: parsed.hostname,
39
+ sysnr: process.env.SAP_SYSNR?.trim() || derived,
40
+ client: config.client || '000',
41
+ user: config.username,
42
+ passwd: config.password,
43
+ lang: 'EN',
44
+ };
45
+ }
46
+ /**
47
+ * The factory `RfcTransport` asks for.
48
+ *
49
+ * The SDK is loaded when a conversation is opened, not when this is called, so
50
+ * a consumer can build the transport on a machine that has no SDK and find out
51
+ * at `connect()` rather than at construction — with a message that says what to
52
+ * install.
53
+ */
54
+ function rfcConversationFrom(config) {
55
+ const params = rfcParamsFrom(config);
56
+ return () => {
57
+ let Client;
58
+ try {
59
+ // Dynamic, because the SDK is an optional peer: it needs the SAP NW RFC
60
+ // SDK installed on the machine, and most consumers travel over HTTP.
61
+ // biome-ignore lint/correctness/noNodejsModules: optional by design
62
+ Client = require('@mcp-abap-adt/sap-rfc-lite').Client;
63
+ }
64
+ catch (error) {
65
+ throw new Error('@mcp-abap-adt/sap-rfc-lite is not available. To take the RFC wire, ' +
66
+ 'install the SAP NW RFC SDK and run: npm install @mcp-abap-adt/sap-rfc-lite. ' +
67
+ `Details: ${error instanceof Error ? error.message : String(error)}`);
68
+ }
69
+ return new Client(params);
70
+ };
71
+ }
package/dist/index.d.ts CHANGED
@@ -1,21 +1,20 @@
1
1
  export type { IWebSocketCloseInfo, IWebSocketConnectOptions, IWebSocketMessageEnvelope, IWebSocketMessageHandler, IWebSocketTransport, } from '@mcp-abap-adt/interfaces';
2
2
  export { FileCertificateMaterialLoader } from './auth/FileCertificateMaterialLoader.js';
3
- export type { IAuthProvider } from './auth/IAuthProvider.js';
4
3
  export { BasicAuthProvider, CertificateAuthProvider, SamlAuthProvider, TokenAuthProvider, } from './auth/providers.js';
5
4
  export type { SapAuthType, SapConfig, SapConnectionType, } from './config/sapConfig.js';
6
5
  export { sapConfigSignature } from './config/sapConfig.js';
7
6
  export type { AbapConnection, AbapRequestOptions, } from './connection/AbapConnection.js';
8
7
  export { AdtCloudConnector } from './connection/AdtCloudConnector.js';
9
8
  export { AdtOnPremConnector } from './connection/AdtOnPremConnector.js';
10
- export { BaseAbapConnection, BaseAbapConnection as OnPremAbapConnection, } from './connection/BaseAbapConnection.js';
11
- export { CertificateAbapConnection } from './connection/CertificateAbapConnection.js';
12
- export { createAbapConnection } from './connection/connectionFactory.js';
9
+ export { CloudHttpTransport } from './connection/CloudHttpTransport.js';
13
10
  export { CSRF_CONFIG, CSRF_ERROR_MESSAGES } from './connection/csrfConfig.js';
14
11
  export { GenericWebSocketTransport, type IWebSocketFactory, type IWebSocketLike, } from './connection/GenericWebSocketTransport.js';
15
- export { JwtAbapConnection, JwtAbapConnection as CloudAbapConnection, } from './connection/JwtAbapConnection.js';
16
- export { KerberosAbapConnection } from './connection/KerberosAbapConnection.js';
17
- export { RfcAbapConnection } from './connection/RfcAbapConnection.js';
18
- export { SamlAbapConnection } from './connection/SamlAbapConnection.js';
12
+ export { HttpTransport } from './connection/HttpTransport.js';
13
+ export type { IAdtEstablishContext, IAdtSessionContext, IAdtTransport, IAdtTransportRequest, IAdtTransportResponse, ICloudTransport, IOnPremTransport, } from './connection/IAdtTransport.js';
14
+ export { LegacyOnPremHttpTransport } from './connection/LegacyOnPremHttpTransport.js';
15
+ export { OnPremHttpTransport } from './connection/OnPremHttpTransport.js';
16
+ export { type IRfcConversation, RfcTransport, } from './connection/RfcTransport.js';
17
+ export { type RfcConnectionParams, rfcConversationFrom, rfcParamsFrom, } from './connection/rfcConversation.js';
19
18
  export type { ILogger } from './logger.js';
20
19
  export { getTimeout, getTimeoutConfig, type TimeoutConfig, } from './utils/timeouts.js';
21
20
  //# sourceMappingURL=index.d.ts.map
@@ -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;AACxF,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,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;AAOxE,OAAO,EACL,kBAAkB,EAClB,kBAAkB,IAAI,oBAAoB,GAC3C,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,yBAAyB,EAAE,MAAM,2CAA2C,CAAC;AAEtF,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAEzE,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EACL,yBAAyB,EACzB,KAAK,iBAAiB,EACtB,KAAK,cAAc,GACpB,MAAM,2CAA2C,CAAC;AACnD,OAAO,EACL,iBAAiB,EACjB,iBAAiB,IAAI,mBAAmB,GACzC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,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,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/dist/index.js CHANGED
@@ -1,9 +1,13 @@
1
1
  "use strict";
2
2
  // Types - re-exported from interfaces package with backward compatibility aliases
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.getTimeoutConfig = exports.getTimeout = exports.SamlAbapConnection = exports.RfcAbapConnection = exports.KerberosAbapConnection = exports.CloudAbapConnection = exports.JwtAbapConnection = exports.GenericWebSocketTransport = exports.CSRF_ERROR_MESSAGES = exports.CSRF_CONFIG = exports.createAbapConnection = exports.CertificateAbapConnection = exports.OnPremAbapConnection = exports.BaseAbapConnection = exports.AdtOnPremConnector = exports.AdtCloudConnector = exports.sapConfigSignature = exports.TokenAuthProvider = exports.SamlAuthProvider = exports.CertificateAuthProvider = exports.BasicAuthProvider = exports.FileCertificateMaterialLoader = void 0;
4
+ exports.getTimeoutConfig = exports.getTimeout = exports.rfcParamsFrom = exports.rfcConversationFrom = exports.RfcTransport = exports.OnPremHttpTransport = exports.LegacyOnPremHttpTransport = exports.HttpTransport = exports.GenericWebSocketTransport = exports.CSRF_ERROR_MESSAGES = exports.CSRF_CONFIG = exports.CloudHttpTransport = exports.AdtOnPremConnector = exports.AdtCloudConnector = exports.sapConfigSignature = exports.TokenAuthProvider = exports.SamlAuthProvider = exports.CertificateAuthProvider = exports.BasicAuthProvider = exports.FileCertificateMaterialLoader = void 0;
5
5
  var FileCertificateMaterialLoader_js_1 = require("./auth/FileCertificateMaterialLoader.js");
6
6
  Object.defineProperty(exports, "FileCertificateMaterialLoader", { enumerable: true, get: function () { return FileCertificateMaterialLoader_js_1.FileCertificateMaterialLoader; } });
7
+ // IAuthProvider is deliberately NOT re-exported. It lives in
8
+ // @mcp-abap-adt/interfaces and a consumer imports it from there — the same rule
9
+ // the session-lifecycle vocabulary follows below, and for the same reason: two
10
+ // names for one contract let the two drift.
7
11
  var providers_js_1 = require("./auth/providers.js");
8
12
  Object.defineProperty(exports, "BasicAuthProvider", { enumerable: true, get: function () { return providers_js_1.BasicAuthProvider; } });
9
13
  Object.defineProperty(exports, "CertificateAuthProvider", { enumerable: true, get: function () { return providers_js_1.CertificateAuthProvider; } });
@@ -16,35 +20,34 @@ var AdtCloudConnector_js_1 = require("./connection/AdtCloudConnector.js");
16
20
  Object.defineProperty(exports, "AdtCloudConnector", { enumerable: true, get: function () { return AdtCloudConnector_js_1.AdtCloudConnector; } });
17
21
  var AdtOnPremConnector_js_1 = require("./connection/AdtOnPremConnector.js");
18
22
  Object.defineProperty(exports, "AdtOnPremConnector", { enumerable: true, get: function () { return AdtOnPremConnector_js_1.AdtOnPremConnector; } });
23
+ var CloudHttpTransport_js_1 = require("./connection/CloudHttpTransport.js");
24
+ Object.defineProperty(exports, "CloudHttpTransport", { enumerable: true, get: function () { return CloudHttpTransport_js_1.CloudHttpTransport; } });
19
25
  // The session lifecycle vocabulary — ISessionLifecycleAware, ADT_SESSION_ERROR —
20
26
  // is deliberately NOT exported here. It lives in @mcp-abap-adt/interfaces, and a
21
27
  // consumer imports it from there: re-exporting a contract type gives it two
22
28
  // names and lets the two drift.
23
29
  // Connection classes - only final implementations
24
30
  // Deprecated aliases for backward compatibility
25
- var BaseAbapConnection_js_1 = require("./connection/BaseAbapConnection.js");
26
- Object.defineProperty(exports, "BaseAbapConnection", { enumerable: true, get: function () { return BaseAbapConnection_js_1.BaseAbapConnection; } });
27
- Object.defineProperty(exports, "OnPremAbapConnection", { enumerable: true, get: function () { return BaseAbapConnection_js_1.BaseAbapConnection; } });
28
- var CertificateAbapConnection_js_1 = require("./connection/CertificateAbapConnection.js");
29
- Object.defineProperty(exports, "CertificateAbapConnection", { enumerable: true, get: function () { return CertificateAbapConnection_js_1.CertificateAbapConnection; } });
30
- // Factory
31
- var connectionFactory_js_1 = require("./connection/connectionFactory.js");
32
- Object.defineProperty(exports, "createAbapConnection", { enumerable: true, get: function () { return connectionFactory_js_1.createAbapConnection; } });
33
31
  // CSRF configuration
34
32
  var csrfConfig_js_1 = require("./connection/csrfConfig.js");
35
33
  Object.defineProperty(exports, "CSRF_CONFIG", { enumerable: true, get: function () { return csrfConfig_js_1.CSRF_CONFIG; } });
36
34
  Object.defineProperty(exports, "CSRF_ERROR_MESSAGES", { enumerable: true, get: function () { return csrfConfig_js_1.CSRF_ERROR_MESSAGES; } });
37
35
  var GenericWebSocketTransport_js_1 = require("./connection/GenericWebSocketTransport.js");
38
36
  Object.defineProperty(exports, "GenericWebSocketTransport", { enumerable: true, get: function () { return GenericWebSocketTransport_js_1.GenericWebSocketTransport; } });
39
- var JwtAbapConnection_js_1 = require("./connection/JwtAbapConnection.js");
40
- Object.defineProperty(exports, "JwtAbapConnection", { enumerable: true, get: function () { return JwtAbapConnection_js_1.JwtAbapConnection; } });
41
- Object.defineProperty(exports, "CloudAbapConnection", { enumerable: true, get: function () { return JwtAbapConnection_js_1.JwtAbapConnection; } });
42
- var KerberosAbapConnection_js_1 = require("./connection/KerberosAbapConnection.js");
43
- Object.defineProperty(exports, "KerberosAbapConnection", { enumerable: true, get: function () { return KerberosAbapConnection_js_1.KerberosAbapConnection; } });
44
- var RfcAbapConnection_js_1 = require("./connection/RfcAbapConnection.js");
45
- Object.defineProperty(exports, "RfcAbapConnection", { enumerable: true, get: function () { return RfcAbapConnection_js_1.RfcAbapConnection; } });
46
- var SamlAbapConnection_js_1 = require("./connection/SamlAbapConnection.js");
47
- Object.defineProperty(exports, "SamlAbapConnection", { enumerable: true, get: function () { return SamlAbapConnection_js_1.SamlAbapConnection; } });
37
+ // The transport axis. Both ends are objects, so a caller can name either.
38
+ var HttpTransport_js_1 = require("./connection/HttpTransport.js");
39
+ Object.defineProperty(exports, "HttpTransport", { enumerable: true, get: function () { return HttpTransport_js_1.HttpTransport; } });
40
+ var LegacyOnPremHttpTransport_js_1 = require("./connection/LegacyOnPremHttpTransport.js");
41
+ Object.defineProperty(exports, "LegacyOnPremHttpTransport", { enumerable: true, get: function () { return LegacyOnPremHttpTransport_js_1.LegacyOnPremHttpTransport; } });
42
+ var OnPremHttpTransport_js_1 = require("./connection/OnPremHttpTransport.js");
43
+ Object.defineProperty(exports, "OnPremHttpTransport", { enumerable: true, get: function () { return OnPremHttpTransport_js_1.OnPremHttpTransport; } });
44
+ var RfcTransport_js_1 = require("./connection/RfcTransport.js");
45
+ Object.defineProperty(exports, "RfcTransport", { enumerable: true, get: function () { return RfcTransport_js_1.RfcTransport; } });
46
+ // The front door to the RFC wire: the derivation a consumer would otherwise
47
+ // copy, and the SDK loaded only when a conversation is opened.
48
+ var rfcConversation_js_1 = require("./connection/rfcConversation.js");
49
+ Object.defineProperty(exports, "rfcConversationFrom", { enumerable: true, get: function () { return rfcConversation_js_1.rfcConversationFrom; } });
50
+ Object.defineProperty(exports, "rfcParamsFrom", { enumerable: true, get: function () { return rfcConversation_js_1.rfcParamsFrom; } });
48
51
  // Timeouts
49
52
  var timeouts_js_1 = require("./utils/timeouts.js");
50
53
  Object.defineProperty(exports, "getTimeout", { enumerable: true, get: function () { return timeouts_js_1.getTimeout; } });
@@ -5,27 +5,14 @@ export declare function getTimeout(type?: 'default' | 'csrf' | 'long' | number):
5
5
  /**
6
6
  * Large ceiling timeout applied while a connection is inside an uninterruptible
7
7
  * critical section (lock → modify → unlock). A short per-request timeout must
8
- * not abort such a request mid-flight: aborting tears down the socket, which
9
- * drops the stateful ADT session and orphans the lock handle (object left
10
- * locked and inactive). Configurable via SAP_TIMEOUT_CRITICAL (ms).
8
+ * not abort such a request mid-flight — not because aborting ends anything on
9
+ * the server, but because it ends what the CLIENT knows: the modification may
10
+ * or may not have been applied, and the handle `unlock` needs is gone, while
11
+ * the lock and the ABAP session holding it sit there until that server-side
12
+ * idle timeout, which this side can neither read nor influence.
13
+ * Configurable via SAP_TIMEOUT_CRITICAL (ms).
11
14
  * Default 600000 (10 minutes) — a generous ceiling that still guards against a
12
15
  * permanently dead socket hanging forever.
13
16
  */
14
17
  export declare function getCriticalSectionTimeout(): number;
15
- /**
16
- * How long `disconnect()` may spend telling the server the session is done.
17
- *
18
- * **Zero by default: after a disconnect nothing waits on the answer.** Waiting
19
- * is for steps whose successor depends on the server having caught up — lock,
20
- * update, unlock, activate, each needing the one before it to have landed.
21
- * A teardown has no successor: the session is marked unneeded, the server
22
- * reclaims it whenever it reclaims it, and a caller blocked on that round trip
23
- * has bought nothing while holding up the serializing tail, where every later
24
- * connect and disconnect queues behind it.
25
- *
26
- * The knob exists for a caller that wants a bounded wait anyway — a test
27
- * asserting the logoff landed, a script that would rather see the failure —
28
- * and is theirs to set per call via `ISessionLifecycleAware.disconnect`.
29
- */
30
- export declare function getReleaseDeadline(): number;
31
18
  //# sourceMappingURL=timeouts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"timeouts.d.ts","sourceRoot":"","sources":["../../src/utils/timeouts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAG/D,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC;AAE3C,wBAAgB,gBAAgB,IAAI,cAAc,CAajD;AAED,wBAAgB,UAAU,CACxB,IAAI,GAAE,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,MAAkB,GACrD,MAAM,CAOR;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,CAElD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C"}
1
+ {"version":3,"file":"timeouts.d.ts","sourceRoot":"","sources":["../../src/utils/timeouts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAG/D,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC;AAE3C,wBAAgB,gBAAgB,IAAI,cAAc,CAajD;AAED,wBAAgB,UAAU,CACxB,IAAI,GAAE,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,MAAkB,GACrD,MAAM,CAOR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,CAElD"}
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getTimeoutConfig = getTimeoutConfig;
4
4
  exports.getTimeout = getTimeout;
5
5
  exports.getCriticalSectionTimeout = getCriticalSectionTimeout;
6
- exports.getReleaseDeadline = getReleaseDeadline;
7
6
  function getTimeoutConfig() {
8
7
  const defaultTimeout = parseInt(process.env.SAP_TIMEOUT_DEFAULT || '45000', 10);
9
8
  const csrfTimeout = parseInt(process.env.SAP_TIMEOUT_CSRF || '15000', 10);
@@ -24,30 +23,15 @@ function getTimeout(type = 'default') {
24
23
  /**
25
24
  * Large ceiling timeout applied while a connection is inside an uninterruptible
26
25
  * critical section (lock → modify → unlock). A short per-request timeout must
27
- * not abort such a request mid-flight: aborting tears down the socket, which
28
- * drops the stateful ADT session and orphans the lock handle (object left
29
- * locked and inactive). Configurable via SAP_TIMEOUT_CRITICAL (ms).
26
+ * not abort such a request mid-flight — not because aborting ends anything on
27
+ * the server, but because it ends what the CLIENT knows: the modification may
28
+ * or may not have been applied, and the handle `unlock` needs is gone, while
29
+ * the lock and the ABAP session holding it sit there until that server-side
30
+ * idle timeout, which this side can neither read nor influence.
31
+ * Configurable via SAP_TIMEOUT_CRITICAL (ms).
30
32
  * Default 600000 (10 minutes) — a generous ceiling that still guards against a
31
33
  * permanently dead socket hanging forever.
32
34
  */
33
35
  function getCriticalSectionTimeout() {
34
36
  return parseInt(process.env.SAP_TIMEOUT_CRITICAL || '600000', 10);
35
37
  }
36
- /**
37
- * How long `disconnect()` may spend telling the server the session is done.
38
- *
39
- * **Zero by default: after a disconnect nothing waits on the answer.** Waiting
40
- * is for steps whose successor depends on the server having caught up — lock,
41
- * update, unlock, activate, each needing the one before it to have landed.
42
- * A teardown has no successor: the session is marked unneeded, the server
43
- * reclaims it whenever it reclaims it, and a caller blocked on that round trip
44
- * has bought nothing while holding up the serializing tail, where every later
45
- * connect and disconnect queues behind it.
46
- *
47
- * The knob exists for a caller that wants a bounded wait anyway — a test
48
- * asserting the logoff landed, a script that would rather see the failure —
49
- * and is theirs to set per call via `ISessionLifecycleAware.disconnect`.
50
- */
51
- function getReleaseDeadline() {
52
- return parseInt(process.env.SAP_RELEASE_DEADLINE_MS || '0', 10);
53
- }
package/docs/INDEX.md CHANGED
@@ -15,6 +15,7 @@ mcp-abap-connection/
15
15
  │ ├── INSTALLATION.md # Setup and installation guide
16
16
  │ ├── USAGE.md # API documentation and examples
17
17
  │ ├── MIGRATION-2.0.md # Moving to the explicit session lifecycle
18
+ │ ├── MIGRATION-6.0.md # the factory and the per-credential classes go; RFC is a transport
18
19
  │ ├── MIGRATION-4.0.md # JWT error classification: 401 refreshes, 403 propagates
19
20
  │ ├── SCOPE.md # What this package does and does not own
20
21
  │ ├── STATEFUL_SESSION_GUIDE.md # Stateful requests and lock windows
@@ -43,6 +44,7 @@ mcp-abap-connection/
43
44
  - 🔑 [JWT Auth Tools](./JWT_AUTH_TOOLS.md) - CLI tool for browser-based authentication
44
45
 
45
46
  ### Upgrading
47
+ - 🚚 [Migrating to 6.0.0](./MIGRATION-6.0.md) - the factory and the per-credential classes are removed; the RFC wire is a transport you hand to the on-prem connector
46
48
  - 🧱 [Migrating to 4.0.0](./MIGRATION-4.0.md) - JWT error classification: a 401 refreshes, a 403 propagates with the server's message
47
49
  - 🧱 [Migrating to 2.0.0](./MIGRATION-2.0.md) - The explicit session lifecycle: `connect()` is required
48
50
 
@@ -72,8 +74,9 @@ mcp-abap-connection/
72
74
  ### API Reference
73
75
  - **Connection Interface**: [USAGE.md - API Reference](./USAGE.md#api-reference)
74
76
  - **Configuration Types**: [USAGE.md - Configuration Types](./USAGE.md#configuration-types)
75
- - **Factory Function**: `createAbapConnection()`
76
- - **Connection Classes**: `BaseAbapConnection`, `JwtAbapConnection`
77
+ - **Connectors**: `AdtOnPremConnector`, `AdtCloudConnector`
78
+ - **Credentials**: `BasicAuthProvider`, `TokenAuthProvider`, `SamlAuthProvider`, `CertificateAuthProvider`
79
+ - **Transports**: `HttpTransport`, `RfcTransport` (+ `rfcConversationFrom()`)
77
80
 
78
81
  ## Version Highlights
79
82