@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.
Files changed (92) hide show
  1. package/CHANGELOG.md +243 -1
  2. package/README.md +204 -48
  3. package/bin/sap-abap-auth.js +101 -13
  4. package/dist/auth/providers.d.ts +38 -9
  5. package/dist/auth/providers.d.ts.map +1 -1
  6. package/dist/auth/providers.js +46 -3
  7. package/dist/connection/AbstractAbapConnection.d.ts +83 -136
  8. package/dist/connection/AbstractAbapConnection.d.ts.map +1 -1
  9. package/dist/connection/AbstractAbapConnection.js +241 -763
  10. package/dist/connection/AdtCloudConnector.d.ts +12 -7
  11. package/dist/connection/AdtCloudConnector.d.ts.map +1 -1
  12. package/dist/connection/AdtCloudConnector.js +2 -6
  13. package/dist/connection/AdtOnPremConnector.d.ts +20 -7
  14. package/dist/connection/AdtOnPremConnector.d.ts.map +1 -1
  15. package/dist/connection/AdtOnPremConnector.js +2 -6
  16. package/dist/connection/CloudHttpTransport.d.ts +37 -0
  17. package/dist/connection/CloudHttpTransport.d.ts.map +1 -0
  18. package/dist/{session/CloudSecuritySessionStrategy.js → connection/CloudHttpTransport.js} +59 -49
  19. package/dist/connection/CredentialAbapConnection.d.ts +8 -41
  20. package/dist/connection/CredentialAbapConnection.d.ts.map +1 -1
  21. package/dist/connection/CredentialAbapConnection.js +44 -111
  22. package/dist/connection/HttpTransport.d.ts +178 -0
  23. package/dist/connection/HttpTransport.d.ts.map +1 -0
  24. package/dist/connection/HttpTransport.js +402 -0
  25. package/dist/connection/IAdtTransport.d.ts +232 -0
  26. package/dist/connection/IAdtTransport.d.ts.map +1 -0
  27. package/dist/connection/IAdtTransport.js +28 -0
  28. package/dist/connection/LegacyOnPremHttpTransport.d.ts +40 -0
  29. package/dist/connection/LegacyOnPremHttpTransport.d.ts.map +1 -0
  30. package/dist/connection/LegacyOnPremHttpTransport.js +57 -0
  31. package/dist/connection/OnPremHttpTransport.d.ts +45 -0
  32. package/dist/connection/OnPremHttpTransport.d.ts.map +1 -0
  33. package/dist/connection/OnPremHttpTransport.js +91 -0
  34. package/dist/connection/RfcTransport.d.ts +89 -0
  35. package/dist/connection/RfcTransport.d.ts.map +1 -0
  36. package/dist/connection/RfcTransport.js +270 -0
  37. package/dist/connection/rfcConversation.d.ts +44 -0
  38. package/dist/connection/rfcConversation.d.ts.map +1 -0
  39. package/dist/connection/rfcConversation.js +71 -0
  40. package/dist/index.d.ts +7 -8
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +21 -18
  43. package/dist/utils/timeouts.d.ts +6 -19
  44. package/dist/utils/timeouts.d.ts.map +1 -1
  45. package/dist/utils/timeouts.js +6 -22
  46. package/docs/INDEX.md +5 -2
  47. package/docs/INSTALLATION.md +28 -10
  48. package/docs/JWT_AUTH_TOOLS.md +20 -4
  49. package/docs/MIGRATION-6.0.md +359 -0
  50. package/docs/SCOPE.md +1 -1
  51. package/docs/STATEFUL_SESSION_GUIDE.md +86 -17
  52. package/docs/USAGE.md +260 -119
  53. package/examples/basic-connection.js +15 -3
  54. package/examples/jwt-with-token-refresh.js +15 -7
  55. package/examples/saml-connection.js +15 -2
  56. package/package.json +12 -11
  57. package/dist/__tests__/helpers/session.d.ts +0 -15
  58. package/dist/__tests__/helpers/session.d.ts.map +0 -1
  59. package/dist/__tests__/helpers/session.js +0 -19
  60. package/dist/auth/IAuthProvider.d.ts +0 -84
  61. package/dist/auth/IAuthProvider.d.ts.map +0 -1
  62. package/dist/auth/IAuthProvider.js +0 -21
  63. package/dist/connection/BaseAbapConnection.d.ts +0 -29
  64. package/dist/connection/BaseAbapConnection.d.ts.map +0 -1
  65. package/dist/connection/BaseAbapConnection.js +0 -81
  66. package/dist/connection/CertificateAbapConnection.d.ts +0 -35
  67. package/dist/connection/CertificateAbapConnection.d.ts.map +0 -1
  68. package/dist/connection/CertificateAbapConnection.js +0 -91
  69. package/dist/connection/JwtAbapConnection.d.ts +0 -131
  70. package/dist/connection/JwtAbapConnection.d.ts.map +0 -1
  71. package/dist/connection/JwtAbapConnection.js +0 -376
  72. package/dist/connection/KerberosAbapConnection.d.ts +0 -32
  73. package/dist/connection/KerberosAbapConnection.d.ts.map +0 -1
  74. package/dist/connection/KerberosAbapConnection.js +0 -128
  75. package/dist/connection/RfcAbapConnection.d.ts +0 -44
  76. package/dist/connection/RfcAbapConnection.d.ts.map +0 -1
  77. package/dist/connection/RfcAbapConnection.js +0 -324
  78. package/dist/connection/SamlAbapConnection.d.ts +0 -31
  79. package/dist/connection/SamlAbapConnection.d.ts.map +0 -1
  80. package/dist/connection/SamlAbapConnection.js +0 -81
  81. package/dist/connection/connectionFactory.d.ts +0 -25
  82. package/dist/connection/connectionFactory.d.ts.map +0 -1
  83. package/dist/connection/connectionFactory.js +0 -84
  84. package/dist/session/CloudSecuritySessionStrategy.d.ts +0 -32
  85. package/dist/session/CloudSecuritySessionStrategy.d.ts.map +0 -1
  86. package/dist/session/IcfSessionStrategy.d.ts +0 -27
  87. package/dist/session/IcfSessionStrategy.d.ts.map +0 -1
  88. package/dist/session/IcfSessionStrategy.js +0 -62
  89. package/dist/session/SessionStrategy.d.ts +0 -86
  90. package/dist/session/SessionStrategy.d.ts.map +0 -1
  91. package/dist/session/SessionStrategy.js +0 -33
  92. 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 { createAbapConnection } = require('@mcp-abap-adt/connection');
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
- // Create connection (factory auto-detects cloud vs on-premise)
22
- const connection = createAbapConnection(config, console);
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 JwtAbapConnection with
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 { JwtAbapConnection } = require('@mcp-abap-adt/connection');
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
- // Create connection with token refresher
66
- // 4th parameter is the ITokenRefresher
67
- const connection = new JwtAbapConnection(
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 { createAbapConnection } = require('@mcp-abap-adt/connection');
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
- const connection = createAbapConnection(config, console);
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": "5.0.0",
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": "./tools/version-stats.sh",
39
- "clean": "rm -rf dist tsconfig.tsbuildinfo",
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": "^12.0.0",
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;