@mcp-abap-adt/connection 5.0.0 → 6.0.1
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 +243 -1
- package/README.md +204 -48
- package/bin/sap-abap-auth.js +101 -13
- package/dist/auth/providers.d.ts +38 -9
- package/dist/auth/providers.d.ts.map +1 -1
- package/dist/auth/providers.js +46 -3
- package/dist/connection/AbstractAbapConnection.d.ts +83 -136
- package/dist/connection/AbstractAbapConnection.d.ts.map +1 -1
- package/dist/connection/AbstractAbapConnection.js +241 -763
- package/dist/connection/AdtCloudConnector.d.ts +12 -7
- package/dist/connection/AdtCloudConnector.d.ts.map +1 -1
- package/dist/connection/AdtCloudConnector.js +2 -6
- package/dist/connection/AdtOnPremConnector.d.ts +20 -7
- package/dist/connection/AdtOnPremConnector.d.ts.map +1 -1
- package/dist/connection/AdtOnPremConnector.js +2 -6
- package/dist/connection/CloudHttpTransport.d.ts +37 -0
- package/dist/connection/CloudHttpTransport.d.ts.map +1 -0
- package/dist/{session/CloudSecuritySessionStrategy.js → connection/CloudHttpTransport.js} +59 -49
- package/dist/connection/CredentialAbapConnection.d.ts +8 -41
- package/dist/connection/CredentialAbapConnection.d.ts.map +1 -1
- package/dist/connection/CredentialAbapConnection.js +44 -111
- package/dist/connection/HttpTransport.d.ts +178 -0
- package/dist/connection/HttpTransport.d.ts.map +1 -0
- package/dist/connection/HttpTransport.js +402 -0
- package/dist/connection/IAdtTransport.d.ts +232 -0
- package/dist/connection/IAdtTransport.d.ts.map +1 -0
- package/dist/connection/IAdtTransport.js +28 -0
- package/dist/connection/LegacyOnPremHttpTransport.d.ts +40 -0
- package/dist/connection/LegacyOnPremHttpTransport.d.ts.map +1 -0
- package/dist/connection/LegacyOnPremHttpTransport.js +57 -0
- package/dist/connection/OnPremHttpTransport.d.ts +45 -0
- package/dist/connection/OnPremHttpTransport.d.ts.map +1 -0
- package/dist/connection/OnPremHttpTransport.js +91 -0
- package/dist/connection/RfcTransport.d.ts +89 -0
- package/dist/connection/RfcTransport.d.ts.map +1 -0
- package/dist/connection/RfcTransport.js +270 -0
- package/dist/connection/rfcConversation.d.ts +44 -0
- package/dist/connection/rfcConversation.d.ts.map +1 -0
- package/dist/connection/rfcConversation.js +71 -0
- package/dist/index.d.ts +7 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -18
- package/dist/utils/timeouts.d.ts +6 -19
- package/dist/utils/timeouts.d.ts.map +1 -1
- package/dist/utils/timeouts.js +6 -22
- package/docs/INDEX.md +5 -2
- package/docs/INSTALLATION.md +28 -10
- package/docs/JWT_AUTH_TOOLS.md +20 -4
- package/docs/MIGRATION-6.0.md +359 -0
- package/docs/SCOPE.md +1 -1
- package/docs/STATEFUL_SESSION_GUIDE.md +86 -17
- package/docs/USAGE.md +260 -119
- package/examples/basic-connection.js +15 -3
- package/examples/jwt-with-token-refresh.js +15 -7
- package/examples/saml-connection.js +15 -2
- package/package.json +12 -11
- package/dist/__tests__/helpers/session.d.ts +0 -15
- package/dist/__tests__/helpers/session.d.ts.map +0 -1
- package/dist/__tests__/helpers/session.js +0 -19
- package/dist/auth/IAuthProvider.d.ts +0 -84
- package/dist/auth/IAuthProvider.d.ts.map +0 -1
- package/dist/auth/IAuthProvider.js +0 -21
- package/dist/connection/BaseAbapConnection.d.ts +0 -29
- package/dist/connection/BaseAbapConnection.d.ts.map +0 -1
- package/dist/connection/BaseAbapConnection.js +0 -81
- package/dist/connection/CertificateAbapConnection.d.ts +0 -35
- package/dist/connection/CertificateAbapConnection.d.ts.map +0 -1
- package/dist/connection/CertificateAbapConnection.js +0 -91
- package/dist/connection/JwtAbapConnection.d.ts +0 -131
- package/dist/connection/JwtAbapConnection.d.ts.map +0 -1
- package/dist/connection/JwtAbapConnection.js +0 -376
- package/dist/connection/KerberosAbapConnection.d.ts +0 -32
- package/dist/connection/KerberosAbapConnection.d.ts.map +0 -1
- package/dist/connection/KerberosAbapConnection.js +0 -128
- package/dist/connection/RfcAbapConnection.d.ts +0 -44
- package/dist/connection/RfcAbapConnection.d.ts.map +0 -1
- package/dist/connection/RfcAbapConnection.js +0 -324
- package/dist/connection/SamlAbapConnection.d.ts +0 -31
- package/dist/connection/SamlAbapConnection.d.ts.map +0 -1
- package/dist/connection/SamlAbapConnection.js +0 -81
- package/dist/connection/connectionFactory.d.ts +0 -25
- package/dist/connection/connectionFactory.d.ts.map +0 -1
- package/dist/connection/connectionFactory.js +0 -84
- package/dist/session/CloudSecuritySessionStrategy.d.ts +0 -32
- package/dist/session/CloudSecuritySessionStrategy.d.ts.map +0 -1
- package/dist/session/IcfSessionStrategy.d.ts +0 -27
- package/dist/session/IcfSessionStrategy.d.ts.map +0 -1
- package/dist/session/IcfSessionStrategy.js +0 -62
- package/dist/session/SessionStrategy.d.ts +0 -86
- package/dist/session/SessionStrategy.d.ts.map +0 -1
- package/dist/session/SessionStrategy.js +0 -33
- package/docs/superpowers/specs/2026-08-21-platform-connectors.md +0 -108
|
@@ -4,7 +4,11 @@
|
|
|
4
4
|
* Demonstrates simple connection to SAP system and making ADT request
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
const {
|
|
7
|
+
const {
|
|
8
|
+
OnPremHttpTransport,
|
|
9
|
+
AdtOnPremConnector,
|
|
10
|
+
BasicAuthProvider,
|
|
11
|
+
} = require('@mcp-abap-adt/connection');
|
|
8
12
|
|
|
9
13
|
async function main() {
|
|
10
14
|
// Configuration from environment or hardcoded
|
|
@@ -18,8 +22,16 @@ async function main() {
|
|
|
18
22
|
|
|
19
23
|
console.log('Creating connection to', config.url);
|
|
20
24
|
|
|
21
|
-
//
|
|
22
|
-
const connection =
|
|
25
|
+
// Which system (the class), which credential (the object). Neither is detected.
|
|
26
|
+
const connection = new AdtOnPremConnector(
|
|
27
|
+
config,
|
|
28
|
+
new BasicAuthProvider(config.username, config.password),
|
|
29
|
+
new OnPremHttpTransport(() => ({}), console, {
|
|
30
|
+
client: config.client,
|
|
31
|
+
baseUrl: config.url,
|
|
32
|
+
}),
|
|
33
|
+
console,
|
|
34
|
+
);
|
|
23
35
|
|
|
24
36
|
try {
|
|
25
37
|
// Connect and get CSRF token
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Example: JWT Connection with Automatic Token Refresh
|
|
3
3
|
*
|
|
4
|
-
* This example demonstrates how to create a
|
|
4
|
+
* This example demonstrates how to create a cloud connection with
|
|
5
5
|
* automatic token refresh using ITokenRefresher from auth-broker.
|
|
6
6
|
*
|
|
7
7
|
* When a **401** occurs, the connection automatically:
|
|
@@ -16,7 +16,11 @@
|
|
|
16
16
|
* change nothing.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
const {
|
|
19
|
+
const {
|
|
20
|
+
CloudHttpTransport,
|
|
21
|
+
AdtCloudConnector,
|
|
22
|
+
TokenAuthProvider,
|
|
23
|
+
} = require('@mcp-abap-adt/connection');
|
|
20
24
|
// const { AuthBroker } = require('@mcp-abap-adt/auth-broker');
|
|
21
25
|
|
|
22
26
|
// Simple logger
|
|
@@ -62,13 +66,17 @@ async function main() {
|
|
|
62
66
|
jwtToken: initialToken,
|
|
63
67
|
};
|
|
64
68
|
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
-
|
|
69
|
+
// The refresher IS the credential: `TokenAuthProvider` asks it for a token on
|
|
70
|
+
// every request, so a provider that renews on expiry renews without anyone
|
|
71
|
+
// here deciding to. A bare string would be a token with nothing behind it.
|
|
72
|
+
const connection = new AdtCloudConnector(
|
|
68
73
|
config,
|
|
74
|
+
new TokenAuthProvider(tokenRefresher),
|
|
75
|
+
new CloudHttpTransport(() => ({}), console, {
|
|
76
|
+
client: config.client,
|
|
77
|
+
baseUrl: config.url,
|
|
78
|
+
}),
|
|
69
79
|
logger,
|
|
70
|
-
undefined,
|
|
71
|
-
tokenRefresher,
|
|
72
80
|
);
|
|
73
81
|
|
|
74
82
|
try {
|
|
@@ -5,7 +5,11 @@
|
|
|
5
5
|
* Session cookies are expected from prior login flow.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
const {
|
|
8
|
+
const {
|
|
9
|
+
OnPremHttpTransport,
|
|
10
|
+
AdtOnPremConnector,
|
|
11
|
+
SamlAuthProvider,
|
|
12
|
+
} = require('@mcp-abap-adt/connection');
|
|
9
13
|
|
|
10
14
|
async function main() {
|
|
11
15
|
const config = {
|
|
@@ -22,7 +26,16 @@ async function main() {
|
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
console.log('Creating SAML connection to', config.url);
|
|
25
|
-
|
|
29
|
+
// The cookies ARE the credential — there is no Authorization header at all.
|
|
30
|
+
const connection = new AdtOnPremConnector(
|
|
31
|
+
config,
|
|
32
|
+
new SamlAuthProvider(config.sessionCookies),
|
|
33
|
+
new OnPremHttpTransport(() => ({}), console, {
|
|
34
|
+
client: config.client,
|
|
35
|
+
baseUrl: config.url,
|
|
36
|
+
}),
|
|
37
|
+
console,
|
|
38
|
+
);
|
|
26
39
|
|
|
27
40
|
try {
|
|
28
41
|
console.log('Connecting using session cookies...');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-abap-adt/connection",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.1",
|
|
4
4
|
"description": "ABAP connection layer for MCP ABAP ADT server",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -35,25 +35,26 @@
|
|
|
35
35
|
"url": "git+https://github.com/fr0ster/mcp-abap-connection.git"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
|
-
"chrono": "
|
|
39
|
-
"clean": "
|
|
40
|
-
"lint": "npx biome check --write src",
|
|
41
|
-
"lint:check": "npx biome check src",
|
|
42
|
-
"format": "npx biome format --write src",
|
|
43
|
-
"build": "npm run --silent clean && npx biome check src --diagnostic-level=error && npx tsc -p tsconfig.json",
|
|
38
|
+
"chrono": "node scripts/version-stats.mjs",
|
|
39
|
+
"clean": "node scripts/clean.mjs",
|
|
40
|
+
"lint": "npx biome check --write src scripts",
|
|
41
|
+
"lint:check": "npx biome check src scripts",
|
|
42
|
+
"format": "npx biome format --write src scripts",
|
|
43
|
+
"build": "npm run --silent clean && npx biome check src scripts --diagnostic-level=error && npx tsc -p tsconfig.json && npm run --silent typecheck:scripts",
|
|
44
44
|
"build:fast": "npx tsc -p tsconfig.json",
|
|
45
45
|
"test": "npm run --silent check:docs && jest",
|
|
46
|
-
"prepublishOnly": "npm run build && npm run check:docs",
|
|
47
|
-
"check:docs": "node scripts/check-docs.mjs"
|
|
46
|
+
"prepublishOnly": "npm run build && npm run check:docs && npm run --silent check:pack",
|
|
47
|
+
"check:docs": "node scripts/check-docs.mjs",
|
|
48
|
+
"typecheck:scripts": "npx tsc -p tsconfig.scripts.json",
|
|
49
|
+
"check:pack": "node scripts/check-pack.mjs"
|
|
48
50
|
},
|
|
49
51
|
"engines": {
|
|
50
52
|
"node": ">=18.0.0"
|
|
51
53
|
},
|
|
52
54
|
"dependencies": {
|
|
53
|
-
"@mcp-abap-adt/interfaces": "^
|
|
55
|
+
"@mcp-abap-adt/interfaces": "^21.0.0",
|
|
54
56
|
"axios": "^1.16.0",
|
|
55
57
|
"commander": "^14.0.3",
|
|
56
|
-
"express": "^5.1.0",
|
|
57
58
|
"open": "^11.0.0"
|
|
58
59
|
},
|
|
59
60
|
"optionalDependencies": {
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Test precondition: put a connection into the connected state without a
|
|
3
|
-
* network round trip.
|
|
4
|
-
*
|
|
5
|
-
* `connect()` is mandatory now, so a test whose subject is something else —
|
|
6
|
-
* timeouts, headers, retry classification — needs the session to exist before
|
|
7
|
-
* it can say anything. Establishing it for real would mean teaching every such
|
|
8
|
-
* mock to answer a CSRF fetch, which tests the wrong thing and adds retry
|
|
9
|
-
* delays to suites that are not about connecting.
|
|
10
|
-
*
|
|
11
|
-
* Tests that ARE about connecting use a real stub instead; see
|
|
12
|
-
* `connection/sessionComposition.test.ts`.
|
|
13
|
-
*/
|
|
14
|
-
export declare function markConnectedForTest(connection: unknown, fingerprint?: Map<string, string>): void;
|
|
15
|
-
//# sourceMappingURL=session.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/__tests__/helpers/session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,OAAO,EACnB,WAAW,GAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAA4C,GAC1E,IAAI,CAMN"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.markConnectedForTest = markConnectedForTest;
|
|
4
|
-
/**
|
|
5
|
-
* Test precondition: put a connection into the connected state without a
|
|
6
|
-
* network round trip.
|
|
7
|
-
*
|
|
8
|
-
* `connect()` is mandatory now, so a test whose subject is something else —
|
|
9
|
-
* timeouts, headers, retry classification — needs the session to exist before
|
|
10
|
-
* it can say anything. Establishing it for real would mean teaching every such
|
|
11
|
-
* mock to answer a CSRF fetch, which tests the wrong thing and adds retry
|
|
12
|
-
* delays to suites that are not about connecting.
|
|
13
|
-
*
|
|
14
|
-
* Tests that ARE about connecting use a real stub instead; see
|
|
15
|
-
* `connection/sessionComposition.test.ts`.
|
|
16
|
-
*/
|
|
17
|
-
function markConnectedForTest(connection, fingerprint = new Map([['SAP_SESSIONID_T_100', 'S1']])) {
|
|
18
|
-
connection.lifecycle.markConnected(fingerprint);
|
|
19
|
-
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* How a connection proves who it is — passed in, not inherited.
|
|
3
|
-
*
|
|
4
|
-
* The class a consumer takes says which SYSTEM it is dialling; this says how it
|
|
5
|
-
* authenticates there. The two are independent: a communication user against
|
|
6
|
-
* ABAP Cloud and a bearer token against on-prem are both ordinary, and a design
|
|
7
|
-
* where the credential picks the system's session mechanism gets one of them
|
|
8
|
-
* wrong whichever way it guesses.
|
|
9
|
-
*
|
|
10
|
-
* Deliberately not "give me a token". Four of the five ways in are not tokens:
|
|
11
|
-
* basic is a header built from a username, a certificate is TLS material and no
|
|
12
|
-
* header at all, and SPNEGO is a negotiation with the server. What every one of
|
|
13
|
-
* them has in common is small, and it is this.
|
|
14
|
-
*
|
|
15
|
-
* `establishSession()` is NOT here. Measured across all five implementations it
|
|
16
|
-
* is the same work — fetch a CSRF token from `/sap/bc/adt/discovery`, keep it,
|
|
17
|
-
* tolerate a failure — with the only difference being a step before it, which is
|
|
18
|
-
* `prepare()`.
|
|
19
|
-
*/
|
|
20
|
-
import type { AgentOptions } from 'node:https';
|
|
21
|
-
export interface IAuthProvider {
|
|
22
|
-
/** For logs, so which credential ran is never inferred from behaviour. */
|
|
23
|
-
readonly kind: string;
|
|
24
|
-
/**
|
|
25
|
-
* Get ready before anything is sent: load key material, unlock a store.
|
|
26
|
-
* Called once per establishment, before the first request.
|
|
27
|
-
*
|
|
28
|
-
* Not for tokens. A stateful token provider caches and renews on its own, so
|
|
29
|
-
* asking it IS the preparation — and holding what it returned would hide the
|
|
30
|
-
* renewal it exists to do.
|
|
31
|
-
*
|
|
32
|
-
* Optional because most credentials are ready as constructed. A credential
|
|
33
|
-
* that throws here fails the connect, which is correct — it has nothing to
|
|
34
|
-
* authenticate with.
|
|
35
|
-
*/
|
|
36
|
-
prepare?(): Promise<void>;
|
|
37
|
-
/**
|
|
38
|
-
* The `Authorization` header value, or `''` when this credential is not a
|
|
39
|
-
* header — a certificate authenticates through TLS and has none.
|
|
40
|
-
*
|
|
41
|
-
* **Asked per request, and asynchronous, because the answer can change.** A
|
|
42
|
-
* token provider checks expiry and renews behind this call; anything cached
|
|
43
|
-
* on this side would serve the stale token and defeat it. Cheap in the
|
|
44
|
-
* ordinary case for the same reason: the provider holds the token and only
|
|
45
|
-
* goes to the network when it has expired.
|
|
46
|
-
*/
|
|
47
|
-
authorizationHeader(): Promise<string>;
|
|
48
|
-
/**
|
|
49
|
-
* The server refused what this last handed out; get a new one.
|
|
50
|
-
*
|
|
51
|
-
* Separate from `authorizationHeader()` because the two questions are
|
|
52
|
-
* different, and the token contract says so: `getToken()` "may return cached
|
|
53
|
-
* token if still valid", while `refreshToken()` is documented as the one to
|
|
54
|
-
* call "when getToken() returned a token that was rejected by server". Asking
|
|
55
|
-
* the first again after a 401 gets the same rejected token back, and the
|
|
56
|
-
* renewal never happens.
|
|
57
|
-
*
|
|
58
|
-
* Omitted by credentials that cannot be renewed — a password is a password.
|
|
59
|
-
*/
|
|
60
|
-
renew?(): Promise<void>;
|
|
61
|
-
/**
|
|
62
|
-
* Cookies this credential authenticates with, for the ways in where the
|
|
63
|
-
* session was negotiated elsewhere and handed over — SAML is one.
|
|
64
|
-
*
|
|
65
|
-
* Part of the contract rather than a method a provider happens to have: the
|
|
66
|
-
* first version left it off, so `SamlAuthProvider` held the cookies, nothing
|
|
67
|
-
* ever asked for them, and the recommended replacement authenticated with
|
|
68
|
-
* nothing at all.
|
|
69
|
-
*/
|
|
70
|
-
cookies?(): string;
|
|
71
|
-
/**
|
|
72
|
-
* TLS options for credentials that live in the transport rather than in a
|
|
73
|
-
* header. Omitted by everything else.
|
|
74
|
-
*/
|
|
75
|
-
httpsAgentOptions?(): AgentOptions;
|
|
76
|
-
/**
|
|
77
|
-
* Fetch the CSRF token this credential's own way.
|
|
78
|
-
*
|
|
79
|
-
* Only SPNEGO needs it: its token is consumed by one request and the exchange
|
|
80
|
-
* is the fetch. Everything else leaves it out and gets the shared path.
|
|
81
|
-
*/
|
|
82
|
-
fetchCsrfToken?(url: string): Promise<string>;
|
|
83
|
-
}
|
|
84
|
-
//# sourceMappingURL=IAuthProvider.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"IAuthProvider.d.ts","sourceRoot":"","sources":["../../src/auth/IAuthProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1B;;;;;;;;;OASG;IACH,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAEvC;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAExB;;;;;;;;OAQG;IACH,OAAO,CAAC,IAAI,MAAM,CAAC;IAEnB;;;OAGG;IACH,iBAAiB,CAAC,IAAI,YAAY,CAAC;IAEnC;;;;;OAKG;IACH,cAAc,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC/C"}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* How a connection proves who it is — passed in, not inherited.
|
|
4
|
-
*
|
|
5
|
-
* The class a consumer takes says which SYSTEM it is dialling; this says how it
|
|
6
|
-
* authenticates there. The two are independent: a communication user against
|
|
7
|
-
* ABAP Cloud and a bearer token against on-prem are both ordinary, and a design
|
|
8
|
-
* where the credential picks the system's session mechanism gets one of them
|
|
9
|
-
* wrong whichever way it guesses.
|
|
10
|
-
*
|
|
11
|
-
* Deliberately not "give me a token". Four of the five ways in are not tokens:
|
|
12
|
-
* basic is a header built from a username, a certificate is TLS material and no
|
|
13
|
-
* header at all, and SPNEGO is a negotiation with the server. What every one of
|
|
14
|
-
* them has in common is small, and it is this.
|
|
15
|
-
*
|
|
16
|
-
* `establishSession()` is NOT here. Measured across all five implementations it
|
|
17
|
-
* is the same work — fetch a CSRF token from `/sap/bc/adt/discovery`, keep it,
|
|
18
|
-
* tolerate a failure — with the only difference being a step before it, which is
|
|
19
|
-
* `prepare()`.
|
|
20
|
-
*/
|
|
21
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { SapConfig } from '../config/sapConfig.js';
|
|
2
|
-
import type { ILogger } from '../logger.js';
|
|
3
|
-
import { AbstractAbapConnection } from './AbstractAbapConnection.js';
|
|
4
|
-
/**
|
|
5
|
-
* @deprecated The class you take should say which SYSTEM you are dialling,
|
|
6
|
-
* not which credential you hold — a session mechanism that rides along with
|
|
7
|
-
* the credential gets one of them wrong. Use `AdtOnPremConnector` with `BasicAuthProvider`:
|
|
8
|
-
*
|
|
9
|
-
* new AdtOnPremConnector(config, new BasicAuthProvider(user, pass), logger)
|
|
10
|
-
*
|
|
11
|
-
* Kept working, and not removed here: existing consumers are unaffected.
|
|
12
|
-
*/
|
|
13
|
-
export declare class BaseAbapConnection extends AbstractAbapConnection {
|
|
14
|
-
constructor(config: SapConfig, logger?: ILogger | null, sessionId?: string, options?: {
|
|
15
|
-
skipSessionType?: boolean;
|
|
16
|
-
});
|
|
17
|
-
/**
|
|
18
|
-
* Connect to SAP system with Basic Auth
|
|
19
|
-
* Fetches CSRF token which also establishes session cookies
|
|
20
|
-
*/
|
|
21
|
-
/**
|
|
22
|
-
* Establishes the session for this auth type. Called by
|
|
23
|
-
* AbstractAbapConnection.connect(), which owns the lifecycle around it.
|
|
24
|
-
*/
|
|
25
|
-
protected establishSession(): Promise<void>;
|
|
26
|
-
protected buildAuthorizationHeader(): string;
|
|
27
|
-
private static validateConfig;
|
|
28
|
-
}
|
|
29
|
-
//# sourceMappingURL=BaseAbapConnection.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"BaseAbapConnection.d.ts","sourceRoot":"","sources":["../../src/connection/BaseAbapConnection.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAErE;;;;;;;;GAQG;AACH,qBAAa,kBAAmB,SAAQ,sBAAsB;gBAE1D,MAAM,EAAE,SAAS,EACjB,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,EACvB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE;IAMzC;;;OAGG;IACH;;;OAGG;cACa,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IA6CjD,SAAS,CAAC,wBAAwB,IAAI,MAAM;IAU5C,OAAO,CAAC,MAAM,CAAC,cAAc;CAmB9B"}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.BaseAbapConnection = void 0;
|
|
4
|
-
const axios_1 = require("axios");
|
|
5
|
-
const AbstractAbapConnection_js_1 = require("./AbstractAbapConnection.js");
|
|
6
|
-
/**
|
|
7
|
-
* @deprecated The class you take should say which SYSTEM you are dialling,
|
|
8
|
-
* not which credential you hold — a session mechanism that rides along with
|
|
9
|
-
* the credential gets one of them wrong. Use `AdtOnPremConnector` with `BasicAuthProvider`:
|
|
10
|
-
*
|
|
11
|
-
* new AdtOnPremConnector(config, new BasicAuthProvider(user, pass), logger)
|
|
12
|
-
*
|
|
13
|
-
* Kept working, and not removed here: existing consumers are unaffected.
|
|
14
|
-
*/
|
|
15
|
-
class BaseAbapConnection extends AbstractAbapConnection_js_1.AbstractAbapConnection {
|
|
16
|
-
constructor(config, logger, sessionId, options) {
|
|
17
|
-
BaseAbapConnection.validateConfig(config);
|
|
18
|
-
super(config, logger || null, sessionId, options);
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Connect to SAP system with Basic Auth
|
|
22
|
-
* Fetches CSRF token which also establishes session cookies
|
|
23
|
-
*/
|
|
24
|
-
/**
|
|
25
|
-
* Establishes the session for this auth type. Called by
|
|
26
|
-
* AbstractAbapConnection.connect(), which owns the lifecycle around it.
|
|
27
|
-
*/
|
|
28
|
-
async establishSession() {
|
|
29
|
-
const baseUrl = await this.getBaseUrl();
|
|
30
|
-
const discoveryUrl = `${baseUrl}/sap/bc/adt/discovery`;
|
|
31
|
-
this.logger?.debug(`[DEBUG] BaseAbapConnection - Connecting to SAP system: ${discoveryUrl}`);
|
|
32
|
-
try {
|
|
33
|
-
// Try to get CSRF token (this will also get cookies)
|
|
34
|
-
const token = await this.fetchCsrfToken(discoveryUrl);
|
|
35
|
-
this.setCsrfToken(token);
|
|
36
|
-
this.logger?.debug('Successfully connected to SAP system', {
|
|
37
|
-
hasCsrfToken: !!this.getCsrfToken(),
|
|
38
|
-
hasCookies: !!this.getCookies(),
|
|
39
|
-
cookieLength: this.getCookies()?.length || 0,
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
catch (error) {
|
|
43
|
-
// For Basic auth, log warning but don't fail
|
|
44
|
-
// The retry logic in makeAdtRequest will handle transient errors automatically
|
|
45
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
46
|
-
this.logger?.warn(`[WARN] BaseAbapConnection - Could not connect to SAP system upfront: ${errorMsg}. Will retry on first request.`);
|
|
47
|
-
// Still try to extract cookies from error response if available
|
|
48
|
-
if (error instanceof axios_1.AxiosError && error.response?.headers) {
|
|
49
|
-
// updateCookiesFromResponse is private, but cookies are extracted in fetchCsrfToken
|
|
50
|
-
if (this.getCookies()) {
|
|
51
|
-
this.logger?.debug(`[DEBUG] BaseAbapConnection - Cookies extracted from error response during connect (first 100 chars): ${this.getCookies()?.substring(0, 100)}...`);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
// Rethrow: a resolved connect() must mean a usable session exists. This
|
|
55
|
-
// used to swallow and resolve anyway, deferring establishment to the
|
|
56
|
-
// first request — coherent only while that lazy path existed. Without it,
|
|
57
|
-
// swallowing would leave a connection that reports success, holds
|
|
58
|
-
// nothing, and refuses every request.
|
|
59
|
-
throw error;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
buildAuthorizationHeader() {
|
|
63
|
-
const { username, password } = this.getConfig();
|
|
64
|
-
const safeUsername = username ?? '';
|
|
65
|
-
const safePassword = password ?? '';
|
|
66
|
-
const token = Buffer.from(`${safeUsername}:${safePassword}`).toString('base64');
|
|
67
|
-
return `Basic ${token}`;
|
|
68
|
-
}
|
|
69
|
-
static validateConfig(config) {
|
|
70
|
-
if (config.authType !== 'basic') {
|
|
71
|
-
throw new Error(`Basic authentication connection expects authType "basic", got "${config.authType}"`);
|
|
72
|
-
}
|
|
73
|
-
if (!config.username || !config.password) {
|
|
74
|
-
throw new Error('Basic authentication requires both username and password');
|
|
75
|
-
}
|
|
76
|
-
if (!config.client) {
|
|
77
|
-
throw new Error('Basic authentication requires SAP_CLIENT to be provided');
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
exports.BaseAbapConnection = BaseAbapConnection;
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { AgentOptions } from 'node:https';
|
|
2
|
-
import type { ICertificateMaterialLoader } from '@mcp-abap-adt/interfaces';
|
|
3
|
-
import type { SapConfig } from '../config/sapConfig.js';
|
|
4
|
-
import type { ILogger } from '../logger.js';
|
|
5
|
-
import { AbstractAbapConnection } from './AbstractAbapConnection.js';
|
|
6
|
-
/**
|
|
7
|
-
* @deprecated The class you take should say which SYSTEM you are dialling,
|
|
8
|
-
* not which credential you hold — a session mechanism that rides along with
|
|
9
|
-
* the credential gets one of them wrong. Use `AdtOnPremConnector` with `CertificateAuthProvider`:
|
|
10
|
-
*
|
|
11
|
-
* new AdtOnPremConnector(config, new CertificateAuthProvider(loader, config), logger)
|
|
12
|
-
*
|
|
13
|
-
* Kept working, and not removed here: existing consumers are unaffected.
|
|
14
|
-
*/
|
|
15
|
-
export declare class CertificateAbapConnection extends AbstractAbapConnection {
|
|
16
|
-
private loader;
|
|
17
|
-
private material;
|
|
18
|
-
constructor(config: SapConfig, logger?: ILogger | null, sessionId?: string, loader?: ICertificateMaterialLoader);
|
|
19
|
-
private static validateConfig;
|
|
20
|
-
protected ensureMaterial(): Promise<void>;
|
|
21
|
-
/**
|
|
22
|
-
* Loads certificate material and primes the session. MUST be called before the first
|
|
23
|
-
* request — the TLS agent is built lazily and needs the client cert present.
|
|
24
|
-
*/
|
|
25
|
-
/**
|
|
26
|
-
* Establishes the session for this auth type. Called by
|
|
27
|
-
* AbstractAbapConnection.connect(), which owns the lifecycle around it.
|
|
28
|
-
*/
|
|
29
|
-
/** The material has to be loaded before anything is sent, preflight included. */
|
|
30
|
-
protected prepareCredential(): Promise<void>;
|
|
31
|
-
protected establishSession(): Promise<void>;
|
|
32
|
-
protected getHttpsAgentOptions(): AgentOptions;
|
|
33
|
-
protected buildAuthorizationHeader(): string;
|
|
34
|
-
}
|
|
35
|
-
//# sourceMappingURL=CertificateAbapConnection.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"CertificateAbapConnection.d.ts","sourceRoot":"","sources":["../../src/connection/CertificateAbapConnection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAEV,0BAA0B,EAC3B,MAAM,0BAA0B,CAAC;AAGlC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAErE;;;;;;;;GAQG;AACH,qBAAa,yBAA0B,SAAQ,sBAAsB;IACnE,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,QAAQ,CAAqC;gBAGnD,MAAM,EAAE,SAAS,EACjB,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,EACvB,SAAS,CAAC,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,0BAA0B;IAOrC,OAAO,CAAC,MAAM,CAAC,cAAc;cAyBb,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAM/C;;;OAGG;IACH;;;OAGG;IACH,iFAAiF;cACxD,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;cAI3C,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IA6BjD,SAAS,CAAC,oBAAoB,IAAI,YAAY;IAU9C,SAAS,CAAC,wBAAwB,IAAI,MAAM;CAG7C"}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CertificateAbapConnection = void 0;
|
|
4
|
-
const axios_1 = require("axios");
|
|
5
|
-
const FileCertificateMaterialLoader_js_1 = require("../auth/FileCertificateMaterialLoader.js");
|
|
6
|
-
const AbstractAbapConnection_js_1 = require("./AbstractAbapConnection.js");
|
|
7
|
-
/**
|
|
8
|
-
* @deprecated The class you take should say which SYSTEM you are dialling,
|
|
9
|
-
* not which credential you hold — a session mechanism that rides along with
|
|
10
|
-
* the credential gets one of them wrong. Use `AdtOnPremConnector` with `CertificateAuthProvider`:
|
|
11
|
-
*
|
|
12
|
-
* new AdtOnPremConnector(config, new CertificateAuthProvider(loader, config), logger)
|
|
13
|
-
*
|
|
14
|
-
* Kept working, and not removed here: existing consumers are unaffected.
|
|
15
|
-
*/
|
|
16
|
-
class CertificateAbapConnection extends AbstractAbapConnection_js_1.AbstractAbapConnection {
|
|
17
|
-
loader;
|
|
18
|
-
material = null;
|
|
19
|
-
constructor(config, logger, sessionId, loader) {
|
|
20
|
-
CertificateAbapConnection.validateConfig(config);
|
|
21
|
-
super(config, logger || null, sessionId);
|
|
22
|
-
this.loader = loader ?? new FileCertificateMaterialLoader_js_1.FileCertificateMaterialLoader();
|
|
23
|
-
}
|
|
24
|
-
static validateConfig(config) {
|
|
25
|
-
if (config.authType !== 'certificate') {
|
|
26
|
-
throw new Error(`Certificate connection expects authType "certificate", got "${config.authType}"`);
|
|
27
|
-
}
|
|
28
|
-
if (config.connectionType === 'rfc') {
|
|
29
|
-
throw new Error('Certificate auth is not supported with connectionType "rfc".');
|
|
30
|
-
}
|
|
31
|
-
const hasPem = !!(config.certPath && config.certKeyPath); // complete PEM pair present
|
|
32
|
-
const hasPfx = !!config.certPfxPath;
|
|
33
|
-
if (!hasPem && !hasPfx) {
|
|
34
|
-
throw new Error('Certificate auth requires certPfxPath OR (certPath AND certKeyPath).');
|
|
35
|
-
}
|
|
36
|
-
if ((config.certPath || config.certKeyPath) && config.certPfxPath) {
|
|
37
|
-
throw new Error('Certificate auth: provide either PEM pair OR PFX, not both.');
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
async ensureMaterial() {
|
|
41
|
-
if (!this.material) {
|
|
42
|
-
this.material = await this.loader.load(this.getConfig());
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Loads certificate material and primes the session. MUST be called before the first
|
|
47
|
-
* request — the TLS agent is built lazily and needs the client cert present.
|
|
48
|
-
*/
|
|
49
|
-
/**
|
|
50
|
-
* Establishes the session for this auth type. Called by
|
|
51
|
-
* AbstractAbapConnection.connect(), which owns the lifecycle around it.
|
|
52
|
-
*/
|
|
53
|
-
/** The material has to be loaded before anything is sent, preflight included. */
|
|
54
|
-
async prepareCredential() {
|
|
55
|
-
await this.ensureMaterial();
|
|
56
|
-
}
|
|
57
|
-
async establishSession() {
|
|
58
|
-
await this.ensureMaterial();
|
|
59
|
-
const baseUrl = await this.getBaseUrl();
|
|
60
|
-
const discoveryUrl = `${baseUrl}/sap/bc/adt/discovery`;
|
|
61
|
-
try {
|
|
62
|
-
const token = await this.fetchCsrfToken(discoveryUrl);
|
|
63
|
-
this.setCsrfToken(token);
|
|
64
|
-
}
|
|
65
|
-
catch (error) {
|
|
66
|
-
this.logger?.warn(`[WARN] CertificateAbapConnection - connect deferred: ${error instanceof Error ? error.message : String(error)}`);
|
|
67
|
-
if (error instanceof axios_1.AxiosError && error.response?.headers) {
|
|
68
|
-
if (this.getCookies()) {
|
|
69
|
-
this.logger?.debug(`[DEBUG] CertificateAbapConnection - Cookies extracted from error response during connect (first 100 chars): ${this.getCookies()?.substring(0, 100)}...`);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
// Rethrow: a resolved connect() must mean a usable session exists. This
|
|
73
|
-
// used to swallow and resolve anyway, deferring establishment to the
|
|
74
|
-
// first request — coherent only while that lazy path existed. Without it,
|
|
75
|
-
// swallowing would leave a connection that reports success, holds
|
|
76
|
-
// nothing, and refuses every request.
|
|
77
|
-
throw error;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
getHttpsAgentOptions() {
|
|
81
|
-
if (!this.material) {
|
|
82
|
-
throw new Error('CertificateAbapConnection: certificate material not loaded. Call connect() before making requests.');
|
|
83
|
-
}
|
|
84
|
-
const { cert, key, pfx, passphrase } = this.material;
|
|
85
|
-
return { cert, key, pfx, passphrase };
|
|
86
|
-
}
|
|
87
|
-
buildAuthorizationHeader() {
|
|
88
|
-
return '';
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
exports.CertificateAbapConnection = CertificateAbapConnection;
|