@mcp-abap-adt/connection 1.10.1 → 2.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.
- package/CHANGELOG.md +758 -0
- package/README.md +42 -11
- package/dist/__tests__/helpers/session.d.ts +15 -0
- package/dist/__tests__/helpers/session.d.ts.map +1 -0
- package/dist/__tests__/helpers/session.js +19 -0
- package/dist/auth/ntlm.d.ts +15 -0
- package/dist/auth/ntlm.d.ts.map +1 -1
- package/dist/auth/ntlm.js +38 -0
- package/dist/connection/AbstractAbapConnection.d.ts +163 -11
- package/dist/connection/AbstractAbapConnection.d.ts.map +1 -1
- package/dist/connection/AbstractAbapConnection.js +351 -14
- package/dist/connection/BaseAbapConnection.d.ts +5 -1
- package/dist/connection/BaseAbapConnection.d.ts.map +1 -1
- package/dist/connection/BaseAbapConnection.js +11 -1
- package/dist/connection/CertificateAbapConnection.d.ts +5 -1
- package/dist/connection/CertificateAbapConnection.d.ts.map +1 -1
- package/dist/connection/CertificateAbapConnection.js +11 -1
- package/dist/connection/JwtAbapConnection.d.ts +3 -2
- package/dist/connection/JwtAbapConnection.d.ts.map +1 -1
- package/dist/connection/JwtAbapConnection.js +19 -8
- package/dist/connection/KerberosAbapConnection.d.ts +5 -1
- package/dist/connection/KerberosAbapConnection.d.ts.map +1 -1
- package/dist/connection/KerberosAbapConnection.js +54 -3
- package/dist/connection/SamlAbapConnection.d.ts +5 -1
- package/dist/connection/SamlAbapConnection.d.ts.map +1 -1
- package/dist/connection/SamlAbapConnection.js +11 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/session/SessionLifecycle.d.ts +131 -0
- package/dist/session/SessionLifecycle.d.ts.map +1 -0
- package/dist/session/SessionLifecycle.js +301 -0
- package/docs/INDEX.md +106 -0
- package/docs/INSTALLATION.md +304 -0
- package/docs/JWT_AUTH_TOOLS.md +142 -0
- package/docs/MIGRATION-2.0.md +125 -0
- package/docs/SCOPE.md +44 -0
- package/docs/STATEFUL_SESSION_GUIDE.md +121 -0
- package/docs/USAGE.md +749 -0
- package/examples/README.md +112 -0
- package/examples/basic-connection.js +55 -0
- package/examples/jwt-with-token-refresh.js +87 -0
- package/examples/saml-connection.js +52 -0
- package/examples/websocket-transport.js +87 -0
- package/package.json +11 -4
package/docs/SCOPE.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Scope and Boundaries
|
|
2
|
+
|
|
3
|
+
This package is **one component of the `@mcp-abap-adt/*` family**. Each package owns one concern; together they form an SAP ABAP tooling stack. Keeping the boundaries clear is important — several features that look natural to add here actually belong in sibling packages, and some that look missing (like RFC-to-cloud) do not exist anywhere in the ecosystem because the underlying technology does not support them.
|
|
4
|
+
|
|
5
|
+
## What this package does
|
|
6
|
+
|
|
7
|
+
- **HTTP transport to SAP ADT** — request dispatch, CSRF token fetch, cookie and session handling, stateful/stateless session control.
|
|
8
|
+
- **The session lifecycle** — establishing a session and refusing to work without one, tearing it down without cutting in-flight requests, tracking which SAP session it is talking to, and telling the caller when that session is lost while a lock is held. See [USAGE.md — Session Lifecycle](./USAGE.md#session-lifecycle).
|
|
9
|
+
- **RFC transport to on-premise SAP** — via `@mcp-abap-adt/sap-rfc-lite` + NW RFC SDK, calling `SADT_REST_RFC_ENDPOINT` (the same FM Eclipse ADT uses on on-prem).
|
|
10
|
+
- **Applying credentials** handed to it by the caller (Basic user/password, Bearer JWT, SAML session cookies).
|
|
11
|
+
|
|
12
|
+
## What this package does NOT do, and where it lives instead
|
|
13
|
+
|
|
14
|
+
| Concern | Belongs in |
|
|
15
|
+
|---|---|
|
|
16
|
+
| Token acquisition (SAML/OAuth2 flows, browser login, PKCE) | `@mcp-abap-adt/auth-broker` |
|
|
17
|
+
| Token validation, refresh, re-authentication, expiry tracking | consumer via `ITokenProvider` (from `@mcp-abap-adt/interfaces`) |
|
|
18
|
+
| Session state persistence across processes | `@mcp-abap-adt/auth-broker` |
|
|
19
|
+
| Auth-type constants, provider error codes, auth lifecycle contracts | `@mcp-abap-adt/interfaces` |
|
|
20
|
+
|
|
21
|
+
The rule: **if it is about *acquiring* or *refreshing* credentials, it is not our job.** We receive credentials that are valid at call time and use them. The consumer is responsible for handing us fresh ones — they know their IdP, their refresh cadence, their re-auth UX.
|
|
22
|
+
|
|
23
|
+
## Why there is no RFC to SAP BTP / cloud
|
|
24
|
+
|
|
25
|
+
Short answer: because SAP does not support it that way, and Eclipse ADT does not do it that way either.
|
|
26
|
+
|
|
27
|
+
**1. Eclipse ADT talks to cloud over HTTP, not RFC.**
|
|
28
|
+
The `com.sap.adt.communication.http.*` package is the only transport Eclipse ADT uses for ADT itself. Cloud login in Eclipse goes through `SamlWithReentranceTicketLogonFacade` → `IcfEndpointBasedSystemUrlInfoProvider` → `HttpLowLevelConnection.sendRequest`. This is an HTTP flow via the ABAP ICF (Internet Communication Framework) endpoint, with a browser SAML login minting a short-lived reentrance ticket, which is then exchanged for a `MYSAPSSO2` session cookie over HTTP. There is no RFC anywhere in this path. JCo/RFC calls that appear in Eclipse logs come from unrelated features (GUI integration, JCo destination tests) — not ADT.
|
|
29
|
+
|
|
30
|
+
**2. NW RFC SDK has no JWT or SAML-2.0-XML logon parameter.**
|
|
31
|
+
Inspection of `sapnwrfc.h` and the SDK's reference `sapnwrfc.ini` confirms the supported client logon parameters are: `USER`/`PASSWD`, `X509CERT`, `MYSAPSSO2` (accepts SSO2 tickets and SAP-internal "assertion tickets", *not* SAML 2.0 XML assertions), plus SNC (`SNC_QOP`, `SNC_MYNAME`, `SNC_PARTNERNAME`, `SNC_LIB`) for Kerberos/x509 over RFC. For WebSocket-RFC: `WSHOST`/`WSPORT`, `ALIAS_USER`, `TLS_CLIENT_PSE`, `TLS_CLIENT_CERTIFICATE_LOGON`. No `JWT`, no `BEARER`, no `SAML_ASSERTION`, no `OAUTH` keys exist in the SDK headers.
|
|
32
|
+
|
|
33
|
+
**3. `@mcp-abap-adt/sap-rfc-lite` is a pure passthrough.**
|
|
34
|
+
It forwards every `(name, value)` pair from the JS `Client(params)` object to `RFC_CONNECTION_PARAMETER[]` without filtering. So the wrapper is not a constraint — the constraint is the SDK itself.
|
|
35
|
+
|
|
36
|
+
**4. For BTP on-prem scenarios (Cloud Connector), the JWT→x509/SNC swap happens server-side in the CC.** The client-side RFC call still carries classic credentials (x509 + SNC), not the JWT. Supporting that would be adding SNC-over-RFC for on-prem backends behind a CC tunnel — an on-prem extension, not a "cloud RFC" feature.
|
|
37
|
+
|
|
38
|
+
**Conclusion:** "RFC to cloud" is not a missing feature that would be useful to add; it is a category error. ADT to cloud = HTTP (already supported here). RFC to on-prem = supported here via `connectionType: 'rfc'`. Anything claiming a third combination does not map to what the SAP stack actually exposes.
|
|
39
|
+
|
|
40
|
+
## See also
|
|
41
|
+
|
|
42
|
+
- [`INSTALLATION.md`](./INSTALLATION.md)
|
|
43
|
+
- [`USAGE.md`](./USAGE.md)
|
|
44
|
+
- Sibling packages: `@mcp-abap-adt/interfaces`, `@mcp-abap-adt/sap-rfc-lite`, `@mcp-abap-adt/auth-broker`
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Stateful Session Guide (Connection Layer)
|
|
2
|
+
|
|
3
|
+
> **The header is not what tracks your lock.** `setSessionType('stateful')` sets
|
|
4
|
+
> a per-request header and nothing more — another handler can flip it back while
|
|
5
|
+
> your lock is genuinely open, and a batch never sets it at all. Tell the
|
|
6
|
+
> connection about the lock itself with `beginWindow()` / `endWindow()`: that is
|
|
7
|
+
> what a teardown waits for, what refuses to be abandoned silently, and what
|
|
8
|
+
> makes a replaced session fatal instead of unnoticed. See
|
|
9
|
+
> [USAGE.md — Session Lifecycle](./USAGE.md#session-lifecycle).
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
This document explains how `@mcp-abap-adt/connection` manages HTTP-level session state for SAP ADT requests.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Session Responsibilities
|
|
17
|
+
|
|
18
|
+
- Fetch and cache CSRF token (per connection instance)
|
|
19
|
+
- Store/reuse SAP cookies (`SAP_SESSIONID`, `sap-usercontext`, etc.)
|
|
20
|
+
- Track WHICH SAP session a connection is in, and refuse to work once it is lost
|
|
21
|
+
|
|
22
|
+
The connection layer **does not** decide when to lock/unlock objects—that logic lives in the ADT clients. Instead it ensures every request shares the same HTTP session when desired.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Enabling Stateful Sessions
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { createAbapConnection } from '@mcp-abap-adt/connection';
|
|
30
|
+
|
|
31
|
+
const connection = createAbapConnection(config, logger);
|
|
32
|
+
await connection.connect(); // required before any request
|
|
33
|
+
|
|
34
|
+
// Enable stateful session mode (adds x-sap-adt-sessiontype: stateful header)
|
|
35
|
+
connection.setSessionType('stateful');
|
|
36
|
+
|
|
37
|
+
// Now all requests share the same session (cookies, CSRF token)
|
|
38
|
+
await connection.makeAdtRequest({ method: 'GET', url: '/sap/bc/adt/discovery' });
|
|
39
|
+
|
|
40
|
+
// Switch back to stateless
|
|
41
|
+
connection.setSessionType('stateless');
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Knowing Which Session You Are In
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { BaseAbapConnection } from '@mcp-abap-adt/connection';
|
|
50
|
+
|
|
51
|
+
// getSessionIdentity() is on the HTTP connection classes, NOT on the
|
|
52
|
+
// IAbapConnection type that createAbapConnection() returns.
|
|
53
|
+
const connection = new BaseAbapConnection(config, logger);
|
|
54
|
+
await connection.connect();
|
|
55
|
+
|
|
56
|
+
// Which SAP session this connection is talking to. Changes only when the
|
|
57
|
+
// session itself is replaced — the CSRF cookie is deliberately excluded, since
|
|
58
|
+
// it rotates on a token refresh within one and the same session.
|
|
59
|
+
const identity = connection.getSessionIdentity(); // e.g. 'SAP_SESSIONID_A4H_001=...'
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Exporting and importing session state is **not** part of this package: the
|
|
63
|
+
methods that once did it were removed in 0.2.0, and persistence belongs to
|
|
64
|
+
[`@mcp-abap-adt/auth-broker`](https://www.npmjs.com/package/@mcp-abap-adt/auth-broker).
|
|
65
|
+
|
|
66
|
+
Handing a session to another worker, or resuming one in a CLI tool, therefore
|
|
67
|
+
goes through that package — and whatever it restores, the locks do not come
|
|
68
|
+
back with it: a lock handle from a session this connection did not open is
|
|
69
|
+
dead, and the connection says so rather than letting you use it.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Request Hooks
|
|
74
|
+
|
|
75
|
+
Every ADT request issued through `makeAdtRequest` automatically:
|
|
76
|
+
|
|
77
|
+
1. Ensures a CSRF token is available (`HEAD ...` with `x-csrf-token: fetch` if missing).
|
|
78
|
+
2. Adds the cached token + cookies to headers.
|
|
79
|
+
3. Updates stored cookies if SAP returns `set-cookie`.
|
|
80
|
+
4. Retries once when CSRF token is invalid/expired.
|
|
81
|
+
|
|
82
|
+
This logic is transparent to callers (Builders, handlers, CLI scripts).
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Interaction With ADT Clients
|
|
87
|
+
|
|
88
|
+
- Builders receive the `AbapConnection` instance and optionally a `sessionId`.
|
|
89
|
+
- `@mcp-abap-adt/connection` keeps the HTTP session alive; Builders keep the ADT session consistent.
|
|
90
|
+
- A workflow cannot be resumed by restoring HTTP state into this package: the
|
|
91
|
+
methods that once did that were removed in 0.2.0. Establish a session with
|
|
92
|
+
`connect()` and take the locks again — a lock handle from a previous session
|
|
93
|
+
is dead, and the connection will say so with `ADT_SESSION_REPLACED` rather
|
|
94
|
+
than let you use it.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Troubleshooting
|
|
99
|
+
|
|
100
|
+
- **CSRF token errors**: discard the session and establish a new one. `reset()`
|
|
101
|
+
does that, but it lives on the HTTP connection classes and is **not** on the
|
|
102
|
+
`IAbapConnection` type `createAbapConnection()` returns — reach it through a
|
|
103
|
+
concrete type:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import { BaseAbapConnection } from '@mcp-abap-adt/connection';
|
|
107
|
+
|
|
108
|
+
const connection = new BaseAbapConnection(config, logger);
|
|
109
|
+
connection.reset(); // queues the cleanup; refuses requests meanwhile
|
|
110
|
+
await connection.connect(); // a new session, explicitly
|
|
111
|
+
```
|
|
112
|
+
- **Session expired**: reauthenticate to obtain a new session.
|
|
113
|
+
- **Multiple connections**: each `createAbapConnection` instance maintains its own cookie jar; share the instance if you need continuity.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Related Docs
|
|
118
|
+
|
|
119
|
+
- [USAGE.md — Session Lifecycle](./USAGE.md#session-lifecycle) – connect/disconnect, lock windows, a lost session
|
|
120
|
+
- [MIGRATION-2.0.md](./MIGRATION-2.0.md) – what the explicit lifecycle changed for callers
|
|
121
|
+
|