@mcp-abap-adt/connection 1.10.2 → 3.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 (44) hide show
  1. package/CHANGELOG.md +827 -0
  2. package/README.md +44 -11
  3. package/dist/__tests__/helpers/session.d.ts +15 -0
  4. package/dist/__tests__/helpers/session.d.ts.map +1 -0
  5. package/dist/__tests__/helpers/session.js +19 -0
  6. package/dist/auth/ntlm.d.ts +15 -0
  7. package/dist/auth/ntlm.d.ts.map +1 -1
  8. package/dist/auth/ntlm.js +38 -0
  9. package/dist/connection/AbstractAbapConnection.d.ts +180 -12
  10. package/dist/connection/AbstractAbapConnection.d.ts.map +1 -1
  11. package/dist/connection/AbstractAbapConnection.js +398 -19
  12. package/dist/connection/BaseAbapConnection.d.ts +5 -1
  13. package/dist/connection/BaseAbapConnection.d.ts.map +1 -1
  14. package/dist/connection/BaseAbapConnection.js +11 -1
  15. package/dist/connection/CertificateAbapConnection.d.ts +5 -1
  16. package/dist/connection/CertificateAbapConnection.d.ts.map +1 -1
  17. package/dist/connection/CertificateAbapConnection.js +11 -1
  18. package/dist/connection/JwtAbapConnection.d.ts +3 -2
  19. package/dist/connection/JwtAbapConnection.d.ts.map +1 -1
  20. package/dist/connection/JwtAbapConnection.js +19 -8
  21. package/dist/connection/KerberosAbapConnection.d.ts +5 -1
  22. package/dist/connection/KerberosAbapConnection.d.ts.map +1 -1
  23. package/dist/connection/KerberosAbapConnection.js +54 -3
  24. package/dist/connection/SamlAbapConnection.d.ts +5 -1
  25. package/dist/connection/SamlAbapConnection.d.ts.map +1 -1
  26. package/dist/connection/SamlAbapConnection.js +11 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +4 -0
  29. package/dist/session/SessionLifecycle.d.ts +50 -70
  30. package/dist/session/SessionLifecycle.d.ts.map +1 -1
  31. package/dist/session/SessionLifecycle.js +59 -158
  32. package/docs/INDEX.md +106 -0
  33. package/docs/INSTALLATION.md +304 -0
  34. package/docs/JWT_AUTH_TOOLS.md +142 -0
  35. package/docs/MIGRATION-2.0.md +114 -0
  36. package/docs/SCOPE.md +44 -0
  37. package/docs/STATEFUL_SESSION_GUIDE.md +122 -0
  38. package/docs/USAGE.md +745 -0
  39. package/examples/README.md +112 -0
  40. package/examples/basic-connection.js +55 -0
  41. package/examples/jwt-with-token-refresh.js +87 -0
  42. package/examples/saml-connection.js +52 -0
  43. package/examples/websocket-transport.js +87 -0
  44. package/package.json +11 -4
package/CHANGELOG.md ADDED
@@ -0,0 +1,827 @@
1
+ # Changelog
2
+
3
+ All notable changes to the `@mcp-abap-adt/connection` package will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [3.0.0] - 2026-08-03
11
+
12
+ Undoes two mistakes from 2.0.0, four days old. Everything else that release
13
+ carried — mandatory `connect()`, replaced-session detection, session verdicts
14
+ surviving the retry layers, the Kerberos diagnosis — is unchanged.
15
+
16
+ ### Changed — BREAKING
17
+ - **`disconnect()` returns `Promise<void>` and waits for nothing.** It used to
18
+ drain in-flight requests before clearing anything, and that drain had an
19
+ unbounded tail: a request whose caller chose no timeout — a legitimate choice
20
+ for a long poll — could hold a teardown open forever. Because lifecycle
21
+ transitions are serialized, every later `connect()` queued behind it. We
22
+ published a `disconnect()` that resolves; that path could not.
23
+
24
+ Deciding when to disconnect is the caller's, and so is preparing for it.
25
+ Requests in flight now run to completion untouched — nothing is aborted — and
26
+ the session state is cleared at once. Requires `@mcp-abap-adt/interfaces`
27
+ **^12.0.0**.
28
+ - **A replaced session is always fatal.** It used to be tolerated when no lock
29
+ window was open. Windows are gone (below), and this layer does not know that a
30
+ lock exists, what object it covers or what would release it — so the rule is
31
+ written from what it can know: the ABAP session we were speaking to is not the
32
+ one we are speaking to now, and anything held against the old one is dead.
33
+ Being wrong in this direction costs a reconnect; being wrong the other way
34
+ costs a lock nobody can find.
35
+
36
+ ### Removed — BREAKING
37
+ - **`beginWindow()` / `endWindow()`**, and the window accounting in
38
+ `SessionLifecycle`. They were added in 2.0.0 and never worked: `beginWindow()`
39
+ put a label in a map and touched no timeout. The protection they were assumed
40
+ to provide — a span where a short per-request timeout must not abort a
41
+ request — is `beginCriticalSection()` / `endCriticalSection()`, which has done
42
+ it since 1.9.0, is reference-counted, and is **unchanged by this release**. Two
43
+ mechanisms for one idea, and the one promoted into the public API was the
44
+ no-op. Nothing called it: zero callers across every repository that depends on
45
+ this package.
46
+
47
+ ### Added
48
+ - **Session-generation fencing.** Removing the wait means a request can settle
49
+ after a later `connect()` established a new session, and the response path
50
+ mutates shared state — cookies, the identity policy, the CSRF cache. A stale
51
+ response would write over the new session and could be read as a replacement,
52
+ tearing down a session that is perfectly healthy. Every lease now carries the
53
+ generation it was admitted under, and a response whose generation is not
54
+ current has its effects skipped. It still resolves normally to its own caller:
55
+ fencing suppresses effects, not results.
56
+
57
+ Deliberately not the teardown epoch. Only a caller-initiated teardown moves the
58
+ epoch — a recovery must not cancel itself — so after a session loss and a
59
+ successful recovery, requests from the dead session carry the same epoch as the
60
+ new one and pass straight through a fence built on it.
61
+
62
+ The fence sits at the **top of the error path**, before anything reads or
63
+ writes shared state — not merely before the response headers are applied.
64
+ Everything below it acts on the connection rather than on the request: a late
65
+ 400 "session not found" would tear down the healthy session established since,
66
+ and a late 401/403 would clear the live session's state, fetch a fresh CSRF
67
+ token and **retry** — replaying a mutation from a dead session inside the live
68
+ one. A stale request now gets its error back and nothing else happens.
69
+
70
+ ### Fixed
71
+ - **Our own re-establishment no longer reads as someone else's replacement.**
72
+ With a replacement now always fatal, a deliberate re-authentication would have
73
+ torn the connection down: `invalidateSession()` dropped the cookies but kept
74
+ the tracked identity, so the next cookie looked foreign. Both it and the
75
+ establishment path now forget the identity first. The distinction that matters
76
+ is not "was a lock held" but "did we cause this".
77
+
78
+ ## [2.0.0] - 2026-07-29
79
+
80
+ The connection owns its session now, and says so. Before this release a stateful
81
+ ADT session could be replaced underneath a caller holding a lock — silently,
82
+ under an unchanged `sap-adt-connection-id`, with no way for either side to
83
+ notice. That is what orphans an edit lock and leaves an object inactive and
84
+ locked with nobody able to say whether the connector changed or the session
85
+ broke. Migration guide: [`docs/MIGRATION-2.0.md`](docs/MIGRATION-2.0.md).
86
+
87
+ ### Changed — BREAKING
88
+ - **`connect()` is mandatory, and it rejects when it fails.** `makeAdtRequest()` now refuses with `ADT_NOT_CONNECTED` unless the connection was explicitly connected, and `connect()` no longer swallows a failed establishment: it used to log a warning, resolve anyway and defer establishment to the first request, which was coherent only while that lazy path existed. Removing it means a swallowed failure would leave a connection reporting success while holding nothing. A caller that never checked `connect()` now fails at startup rather than at the first request — the better failure, but a new one.
89
+ - **Consumers must call `connect()` before the first request.** Requests are also refused after `disconnect()` and after `reset()`, until the next `connect()`. An in-flight request is not cut off: a teardown drains before it clears anything.
90
+
91
+ ### Added
92
+ - **`disconnect(): Promise<ITeardownReport>`.** Resolves rather than throws, and reports what the teardown could not finish: `abandonedWindows` names the lock windows still open when the bounded wait gave up, `releasePending` says a transport release is still outstanding. A caller learns which locks it must clean up by hand instead of discovering them on the next developer's screen.
93
+ - **`isConnected()` and `getSessionIdentity()`.** The session is observable now: whether a caller may work, and which ABAP session it would work over. The identity is derived from the `SAP_SESSIONID*` cookies and deliberately excludes `sap-XSRF_*`, which rotates on a token refresh *within* one session — folding it in would report an ordinary refresh as a new session.
94
+ - **`beginWindow(label)` / `endWindow(token)`.** Marks a span that must not lose its session, such as the interval between LOCK and UNLOCK. A teardown requested during an open window waits for it, bounded by an absolute ceiling measured from the request; on expiry the window is reported as abandoned rather than silently dropped.
95
+ - **The session lifecycle is on the shared contract, as capability atoms.** `AbstractAbapConnection` now declares `implements ISessionLifecycleAware, ILockWindowAware` from `@mcp-abap-adt/interfaces` 11.5.0, and `ITeardownReport`, `WindowToken`, `ADT_SESSION_ERROR` and `AdtSessionErrorCode` come from there. **Import them from `@mcp-abap-adt/interfaces`, not from this package** — it deliberately does not re-export them, because a contract type with two names is a contract type that can drift.
96
+
97
+ Atoms rather than five more methods on `IAbapConnection`: that interface is the minimum every transport can honour, and `RfcAbapConnection` owns no HTTP session and can open no lock window. Requiring these of every connection would force a transport with no session to implement a lie. Narrow to the atom you need — `IAbapConnection & ILockWindowAware` — and the compiler rejects an RFC connection at the call site instead of failing at runtime.
98
+
99
+ ### Fixed
100
+ - **A replaced session is now detected and raised instead of absorbed.** Responses are observed through one path that updates the cookies *and* applies the identity policy together; ten call sites used to update the cookies alone, which mutated the fingerprint and made a replacement indistinguishable from the session it replaced. A lost session raises `ADT_SESSION_REPLACED` and tears down, rather than letting the next request run against a session the caller never opened.
101
+ - **Session verdicts survive the retry layers.** Three nested catches — the CSRF retry, the 401-on-GET path and the endpoint fallback — used to swallow a session verdict and retry into a *new* session, where the replacement read as `unchanged` and the loss was gone for good.
102
+ - **A failed establishment leaves nothing behind.** A rejecting response could still carry a `Set-Cookie`, and every auth subclass treats a cookie as proof that auth is settled, so the *next* `connect()` went out with no credentials at all and failed for an unrelated reason. Transport state and the session identity are both dropped when `establishSession()` throws; `getSessionIdentity()` no longer names a session that was never established.
103
+ - **Kerberos: the first challenge is diagnosed, not the fourth.** The connect-time CSRF fetch inherited a 3-retry default while a GSS token is one-shot, so the diagnosis was drawn from a replayed — or credential-less — request. Multi-leg SPNEGO (RFC 4559) is still unsupported, but a landscape that needs it now fails at `connect()` saying so, instead of being misreported as rejected credentials.
104
+ - **The CSRF token fetch stays inside the ADT conversation** (also released in 1.10.1).
105
+ - **The test suite is green on a clean install.** `rfc-params.test.ts` called `jest.mock()` on `@mcp-abap-adt/sap-rfc-lite`, an **optional** dependency with a native build against the SAP NW RFC SDK. On any machine without that SDK npm skips it silently and `jest.mock()` cannot resolve it, so the suite failed — for everyone but whoever had a `node_modules` left over from an install that succeeded. Mocked `{ virtual: true }` now: the test replaces the module entirely and never wanted the real one.
106
+
107
+ ### Security
108
+ - Production audit is clean. `brace-expansion` remains reachable only through `jest` and is pinned by an override; it never ships.
109
+
110
+ ### Dependencies
111
+ - `@mcp-abap-adt/interfaces` 7.2.0 → **11.5.0**, now a real requirement rather than a version bump: this release imports the connection capability atoms from it. Crossing 8–11 was a no-op — those breaking changes are all in ADT object capability types, which the connector never imports — and it also closes the drift against `adt-clients` and `auth-providers`, both already on 11.x.
112
+
113
+ ## [1.10.2] - 2026-07-27
114
+
115
+ ### Added
116
+ - **`SessionLifecycle` — the session-lifecycle core, internal for now.** Owns what the connection cannot express today: session state and identity, a serializing tail for lifecycle transitions, admission accounting with a teardown epoch, lock windows counted per occurrence, and a drain bounded by an absolute ceiling. It knows nothing of SAP, HTTP, RFC or cookies — identities are opaque `name → value` maps, windows are opaque labels — which is why its 29 tests need no server. **Not exported from the package index and not yet used by any connection**, so this release changes no behaviour and no public API; it lands the piece that the rest of the session work (fr0ster/mcp-abap-connection#15) will be composed from. Design: `docs/superpowers/specs/2026-07-27-session-lifecycle-design.md` in `@mcp-abap-adt/adt-clients`.
117
+
118
+ ## [1.10.1] - 2026-07-27
119
+
120
+ ### Fixed
121
+ - **CSRF token fetch now stays inside the ADT conversation.** `makeAdtRequest` sends `sap-adt-connection-id` on every request, for all session types, but the token fetch assembled its own headers (auth + `x-csrf-token: fetch` + `Accept` + `Cookie`) and omitted it. A fetch triggered while a lock was held therefore reached the server as a caller that merely presented the same cookies, with no way for either side to relate it to the conversation that opened the session. The fetch now carries the connection id like every other request.
122
+
123
+ ## [1.10.0] - 2026-07-16
124
+
125
+ ### Added
126
+ - **Uninterruptible critical sections for lock → modify → unlock chains.** A short per-request timeout was aborting requests mid-flight during a stateful lock → PUT/activate → unlock chain; aborting the socket drops the stateful ADT session and orphans the lock handle, leaving the object **locked and inactive**. New connection methods `beginCriticalSection()` / `endCriticalSection()` (reference-counted) plus `isInCriticalSection()`: while in a critical section, `makeAdtRequest` raises the effective timeout to a large ceiling (`getCriticalSectionTimeout()`, env `SAP_TIMEOUT_CRITICAL`, default `600000` ms) instead of the short per-request timeout, so slow PUT/activate/unlock requests run to completion rather than being interrupted. Consumers wrap a mutating operation with `beginCriticalSection()` before locking and `endCriticalSection()` in a `finally` after unlocking. Additive and backward-compatible (no behavior change outside a critical section).
127
+
128
+ ## [1.9.1] - 2026-05-24
129
+
130
+ ### Added
131
+ - **NTLM hard-reject for Kerberos auth.** When `KerberosAbapConnection` receives a 401/403 whose `WWW-Authenticate` header indicates NTLM (direct `NTLM` scheme, or an NTLM token tunneled via `Negotiate` — base64 prefix `TlRMTVNTUAA` = `NTLMSSP\0`), it now throws a clear error instead of swallowing it. Prevents a silent downgrade to weaker NTLM; only Kerberos/SPNEGO is accepted. New `isNtlmChallenge()` helper (`src/auth/ntlm.ts`).
132
+
133
+ ## [1.9.0] - 2026-05-24
134
+
135
+ ### Added
136
+
137
+ - **Certificate (mTLS) authentication** — `CertificateAbapConnection` injects client-cert material into the axios `https.Agent` via a new protected `getHttpsAgentOptions()` hook on `AbstractAbapConnection`. Material loaded from PEM (`certPath`+`certKeyPath`) or PFX (`certPfxPath`+`certPassphrase`) by the injectable `FileCertificateMaterialLoader` (`ICertificateMaterialLoader`).
138
+ - **Kerberos / SPNEGO authentication** — `KerberosAbapConnection` generates a single-leg Negotiate token locally via `generateSpnegoToken()` (lazy wrapper over the optional `kerberos` native package, declared in `optionalDependencies`), sends `Authorization: Negotiate <token>` on the first request, then reuses the SAP session cookie.
139
+ - `createAbapConnection()` routes `authType: 'certificate'` and `'kerberos'`; both reject `connectionType: 'rfc'`. New optional `certLoader` factory option.
140
+ - `sapConfigSignature()` includes cert paths / SPN (secrets never embedded — passphrase recorded as `'set'`/null only).
141
+
142
+ ### Notes
143
+
144
+ - Certificate and Kerberos are connection-layer auth types (on-prem HTTP); they bypass the auth-broker and auth-providers. Requires `@mcp-abap-adt/interfaces@^7.2.0`.
145
+ - Both connections require `connect()` before the first request; calling a request first fails loudly (cert: throws on missing material; kerberos: throws on missing token).
146
+
147
+ ## [1.7.0] - 2026-04-14
148
+
149
+ ### Changed
150
+
151
+ - Update `@mcp-abap-adt/interfaces` to `^7.0.0` (adds `ServiceBindingVariant` type and `connect()` method in `IAbapConnection`)
152
+
153
+ ## 1.5.3 - 2026-03-12
154
+
155
+ ### Added
156
+ - **RFC stateful session support**: `setSessionType('stateful')` now injects `x-sap-adt-sessiontype: stateful` header and captures `set-cookie` from LOCK responses for cookie replay in subsequent requests (PUT, UNLOCK). This enables lock/update/unlock workflows for package objects over RFC, which require HTTP session ownership validation. `setSessionType('stateless')` clears the captured cookie.
157
+
158
+ ## 1.5.2 - 2026-03-12
159
+
160
+ ### Added
161
+ - **RFC debug logging**: `RfcAbapConnection` now logs full request headers, request body, response headers, and response body at `debug` level. Enable with `DEBUG_CONNECTORS=true` and `AUTH_LOG_LEVEL=debug`.
162
+
163
+ ## [1.5.1] - 2026-03-09
164
+
165
+ ### Fixed
166
+ - **RFC query params encoding**: `RfcAbapConnection.makeAdtRequest` now encodes `params` into the URI query string. Previously `params` were silently ignored, causing failures for package validation, transport checks, and any ADT operation using query parameters over RFC connections.
167
+
168
+ ## [1.4.2] - 2026-03-06
169
+
170
+ ### Added
171
+ - `reset()` method on `RfcAbapConnection` — delegates to `close()` for interface compatibility with HTTP connections.
172
+
173
+ ## [1.4.1] - 2026-03-06
174
+
175
+ ### Fixed
176
+ - Fix RFC STATUS_LINE parsing: use correct field names `STATUS_CODE`/`REASON_PHRASE` (not `CODE`/`REASON`). STATUS_CODE is returned as string — now parsed with `parseInt`.
177
+ - Remove `sap-client` URI parameter from RFC requests — the RFC session is already logged into the correct client via connection parameters. Adding `sap-client` caused "object not found" on some systems.
178
+ - Add fallback exception XML detection: when STATUS_LINE is empty (legacy systems), parse `<exc:exception>` body to derive HTTP status codes (404, 403, 409, 423, etc.).
179
+
180
+ ## [1.4.0] - 2026-03-06
181
+
182
+ ### Added
183
+ - `RfcAbapConnection` — RFC-based connection for legacy SAP systems (BASIS < 7.50) that don't support stateful HTTP sessions. Uses standard `SADT_REST_RFC_ENDPOINT` FM (the same FM that Eclipse ADT uses via JCo) to tunnel ADT REST requests over RFC. Solves HTTP 423 "invalid lock handle" on older systems.
184
+ - `authType: 'rfc'` support in `createAbapConnection()` factory.
185
+ - RFC connection parameters (ashost, sysnr) are derived from the existing `config.url` field — no config changes needed.
186
+
187
+ ### Changed
188
+ - Updated dependency `@mcp-abap-adt/interfaces` to `^2.7.0` (adds `'rfc'` to `SapAuthType` union).
189
+
190
+ ### Notes
191
+ - `node-rfc` is **not** a declared dependency. Users who need RFC connections must install it manually (`npm install node-rfc`) along with SAP NW RFC SDK.
192
+ - RFC connections are inherently stateful — `setSessionType()` is a no-op.
193
+
194
+ ## [1.1.0] - 2026-02-13
195
+
196
+ ### Added
197
+ - Added generic `GenericWebSocketTransport` implementation with injected WS factory and message envelope handling.
198
+ - Re-exported WebSocket transport interfaces from `@mcp-abap-adt/interfaces` and transport class from package root.
199
+
200
+ ### Changed
201
+ - Updated dependency `@mcp-abap-adt/interfaces` to `^2.4.0`.
202
+
203
+ ## [1.0.1] - 2026-02-10
204
+
205
+ ### Changed
206
+ - Dependency updates: `axios`, `commander`, `@biomejs/biome`, `@types/node`.
207
+
208
+ ## [1.0.0] - 2026-02-10
209
+
210
+ ### Added
211
+ - `SamlAbapConnection` for cookie-based SAML sessions and `createAbapConnection` support for `authType: 'saml'`.
212
+ - SAML session cookie support in `SapConfig` and `sapConfigSignature()`.
213
+ - Unit tests for SAML connection, connection factory routing, and config signature.
214
+
215
+ ### Changed
216
+ - **Conditional Logging Support**: Connection package now fully supports conditional logging via `undefined` logger
217
+ - When `undefined` is passed as logger parameter, connection operates silently (no logging output)
218
+ - This enables test environments to control logging verbosity via environment variables
219
+ - Tests can now pass `undefined` logger when `DEBUG_CONNECTION`, `DEBUG_CONN`, or `DEBUG_CONNECTORS` are not set
220
+ - Connection uses optional chaining (`logger?.info()`, `logger?.debug()`, etc.) for all logging calls
221
+ - No breaking changes - existing code with logger continues to work as before
222
+
223
+ ## [0.2.8] - 2025-12-24
224
+
225
+ ### Changed
226
+ - **Dependencies**: Updated `@mcp-abap-adt/interfaces` from `^0.2.5` to `^0.2.13`
227
+
228
+ ## [0.2.7] - 2025-12-23
229
+ ### Fixed
230
+ - Fixed LICENSE file - corrected copyright attribution (removed incorrect fork author)
231
+
232
+ ## [0.2.6] - 2025-12-22
233
+
234
+ ### Changed
235
+ - **Biome Migration**: Migrated from ESLint/Prettier to Biome for linting and formatting
236
+ - Added `@biomejs/biome` as dev dependency
237
+ - Added `lint`, `lint:check`, and `format` scripts to package.json
238
+ - Integrated Biome check into build process (`npx biome check src --diagnostic-level=error`)
239
+ - Updated Node.js imports to use `node:` protocol (`crypto`, `https`)
240
+ - **Type Safety**: Improved type safety by replacing `any` with `unknown`
241
+ - `AbstractAbapConnection.ts`: `updateCookiesFromResponse` method parameter changed from `Record<string, any>` to `Record<string, unknown>`
242
+ - `tokenRefresh.ts`: `error` parameter in catch block changed from `any` to `unknown` with added type guards
243
+
244
+ ### Fixed
245
+ - Fixed computed property access by using literal keys where possible (`Authorization`, `Accept`, `Cookie` headers)
246
+ - Fixed non-null assertions by adding proper null checks (`JwtAbapConnection.ts`)
247
+ - Fixed optional chaining usage in `tokenRefresh.ts`
248
+ - Removed unused imports (`AbapConnection.ts`)
249
+ - Improved error handling with proper type guards for `unknown` error types
250
+
251
+ ## [0.2.5] - 2025-12-21
252
+
253
+ ### Added
254
+ - **connectionFactory tokenRefresher**: `createAbapConnection()` now accepts optional 4th parameter `tokenRefresher`
255
+ - Passes through to `JwtAbapConnection` for automatic token refresh DI
256
+ - Enables external token management via `AuthBroker.createTokenRefresher()`
257
+
258
+ ## [0.2.4] - 2025-12-21
259
+
260
+ ### Added
261
+ - **ITokenRefresher Support**: `JwtAbapConnection` now supports automatic token refresh via dependency injection
262
+ - New optional `tokenRefresher` parameter in constructor
263
+ - If provided, 401/403 errors trigger automatic token refresh and request retry
264
+ - If not provided, legacy behavior (throw error on expired token)
265
+ - Works with `AuthBroker.createTokenRefresher(destination)` from `@mcp-abap-adt/auth-broker`
266
+
267
+ ### Changed
268
+ - **Dependencies**: Updated `@mcp-abap-adt/interfaces` to `^0.2.5`
269
+ - New `ITokenRefresher` interface for token management DI
270
+ - Simplified `IAbapConnection` interface
271
+
272
+ ### Usage Example
273
+ ```typescript
274
+ import { JwtAbapConnection } from '@mcp-abap-adt/connection';
275
+ import { AuthBroker } from '@mcp-abap-adt/auth-broker';
276
+
277
+ // Create token refresher from broker
278
+ const tokenRefresher = broker.createTokenRefresher('TRIAL');
279
+
280
+ // Inject into connection - 401/403 handled automatically
281
+ const connection = new JwtAbapConnection(config, logger, sessionId, tokenRefresher);
282
+ ```
283
+
284
+ ## [0.2.3] - 2025-12-19
285
+
286
+ ### Fixed
287
+ - **Network Error Detection**: Add proper detection and handling of network-level errors in `AbstractAbapConnection.makeAdtRequest()`
288
+ - Detect network errors: `ECONNREFUSED`, `ETIMEDOUT`, `ENOTFOUND`, `ECONNRESET`, `ENETUNREACH`, `EHOSTUNREACH`
289
+ - Skip retry logic for network errors (CSRF token retry, 401 cookie retry)
290
+ - Throw network errors immediately with clear error message
291
+ - Prevents confusing error messages when VPN is down or server is unreachable
292
+ - Network errors now clearly indicate infrastructure issues vs application errors
293
+
294
+ ### Changed
295
+ - **Error Handling**: Improved error handling logic to distinguish between network errors and HTTP errors
296
+ - Network errors (connection issues) are now handled separately from HTTP errors (401, 403, 404)
297
+ - No retry attempts for network errors (retries cannot fix infrastructure issues)
298
+ - Better error logging with network error context
299
+
300
+ ### Documentation
301
+ - Added "Network Error Detection" section to `docs/USAGE.md` with examples and best practices
302
+ - Documented all detected network error codes and their meanings
303
+ - Added error handling examples showing how to handle network vs HTTP errors
304
+
305
+ ## [0.2.2] - 2025-12-13
306
+
307
+ ### Fixed
308
+ - Add missing `ILogger` import from `@mcp-abap-adt/interfaces` to restore TypeScript build
309
+
310
+ ## [0.2.1] - 2025-12-13
311
+
312
+ ### Changed
313
+ - Dependency bump: `@mcp-abap-adt/interfaces` → `^0.1.16` to align with latest interfaces release
314
+ - Repository metadata: point package links to `fr0ster/mcp-abap-connection` (correct repo)
315
+
316
+ ## [0.2.0] - 2025-12-08
317
+
318
+ ### Breaking Changes
319
+
320
+ - **Token Refresh Removed**: Token refresh functionality has been completely removed from this package
321
+ - `refreshToken()` method removed from `JwtAbapConnection`
322
+ - `canRefreshToken()` method removed from `JwtAbapConnection`
323
+ - All automatic token refresh logic removed from connection classes
324
+ - Token refresh is now handled exclusively by `@mcp-abap-adt/auth-broker` package
325
+ - This is a breaking change - code that relied on connection-level token refresh will need to use auth-broker instead
326
+
327
+ - **Logger is Optional**: Logger parameter is now optional in all connection constructors
328
+ - `BaseAbapConnection`, `JwtAbapConnection`, and `createAbapConnection()` now accept `logger?: ILogger | null`
329
+ - All logger calls use optional chaining (`logger?.info()`, `logger?.debug()`, etc.)
330
+ - If no logger is provided, no logging output is produced (no-op behavior)
331
+ - This allows using connections without requiring a logger instance
332
+
333
+ - **Session Storage Removed**: Session storage functionality has been completely removed from this package
334
+ - `sessionStorage` parameter removed from all connection constructors (`BaseAbapConnection`, `JwtAbapConnection`, `createAbapConnection()`)
335
+ - All session storage methods removed: `setSessionStorage()`, `getSessionStorage()`, `loadSessionState()`, `saveSessionState()`, `clearSessionState()`, `getSessionState()`, `setSessionState()`
336
+ - `FileSessionStorage` utility class removed
337
+ - Session state persistence is now handled exclusively by `@mcp-abap-adt/auth-broker` package
338
+ - Connection package now handles only HTTP communication and session headers (cookies, CSRF tokens) without persistence
339
+ - This is a breaking change - code that relied on connection-level session storage will need to use auth-broker instead
340
+
341
+ ### Changed
342
+
343
+ - **Connection Package Scope**: Package now focuses solely on HTTP connection management
344
+ - Removed all token refresh logic from `JwtAbapConnection`
345
+ - Removed all token refresh logic from `connect()`, `makeAdtRequest()`, and `fetchCsrfToken()` methods
346
+ - Removed all session storage and state persistence logic
347
+ - Connection package now handles only HTTP communication and session headers (cookies, CSRF tokens)
348
+ - Token lifecycle management and session state persistence are delegated to auth-broker package
349
+
350
+ ### Removed
351
+
352
+ - **Token Refresh Methods**:
353
+ - `refreshToken()` method removed from `JwtAbapConnection`
354
+ - `canRefreshToken()` method removed from `JwtAbapConnection`
355
+ - `tokenRefreshInProgress` private field removed
356
+ - Import of `refreshJwtToken` utility removed
357
+
358
+ - **Token Refresh Tests**:
359
+ - `auto-refresh.test.ts` removed
360
+ - Replaced with simplified `jwt-connection.test.ts` that tests only configuration validation
361
+
362
+ - **Session Storage Components**:
363
+ - `FileSessionStorage` utility class removed
364
+ - `ISessionStorage` and `SessionState` type exports removed
365
+ - All session storage related imports and exports removed
366
+
367
+ ### Migration Guide
368
+
369
+ If you were using token refresh functionality:
370
+
371
+ **Before (0.1.x)**:
372
+ ```typescript
373
+ const connection = new JwtAbapConnection(config, logger);
374
+ if (connection.canRefreshToken()) {
375
+ await connection.refreshToken();
376
+ }
377
+ ```
378
+
379
+ **After (0.2.0)**:
380
+ ```typescript
381
+ // Token refresh is now handled by auth-broker
382
+ // Connection package only handles HTTP communication
383
+ const connection = new JwtAbapConnection(config, logger);
384
+ // No refreshToken() or canRefreshToken() methods available
385
+ ```
386
+
387
+ **Logger Usage**:
388
+ ```typescript
389
+ // Logger is now optional
390
+ const connection = new JwtAbapConnection(config); // No logger - no logging output
391
+ const connection = new JwtAbapConnection(config, logger); // With logger - logging enabled
392
+ const connection = new JwtAbapConnection(config, null); // Explicitly no logger
393
+ ```
394
+
395
+ If you were using session storage functionality:
396
+
397
+ **Before (0.1.x)**:
398
+ ```typescript
399
+ import { FileSessionStorage } from '@mcp-abap-adt/connection';
400
+
401
+ const sessionStorage = new FileSessionStorage();
402
+ const connection = new JwtAbapConnection(config, logger, sessionStorage);
403
+ await connection.saveSessionState();
404
+ const state = await connection.getSessionState();
405
+ ```
406
+
407
+ **After (0.2.0)**:
408
+ ```typescript
409
+ // Session storage is now handled by auth-broker
410
+ // Connection package only handles HTTP communication
411
+ const connection = new JwtAbapConnection(config, logger);
412
+ // No sessionStorage parameter, no saveSessionState() or getSessionState() methods
413
+ ```
414
+
415
+ ## [0.1.15] - 2025-12-05
416
+
417
+ ### Changed
418
+ - **Logger Interface Migration**: Migrated from specialized logger methods to standard `ILogger` interface
419
+ - Replaced `logger.csrfToken()` calls with standard `debug()` and `error()` methods
420
+ - Replaced `logger.tlsConfig()` calls with standard `debug()` method
421
+ - Now uses only `ILogger` interface from `@mcp-abap-adt/interfaces` without dependency on concrete logger implementation
422
+ - Follows Dependency Inversion Principle - depends on interface, not implementation
423
+
424
+ ### Added
425
+ - **npm Configuration**: Added `.npmrc` file with `prefer-online=true` to ensure packages are installed from npmjs.com registry instead of local file system dependencies
426
+
427
+ ## [0.1.14] - 2025-12-04
428
+
429
+ ### Added
430
+ - **Interfaces Package Integration**: Migrated to use `@mcp-abap-adt/interfaces` package for all interface definitions
431
+ - All interfaces now imported from shared package
432
+ - Backward compatibility maintained with type aliases
433
+ - Dependency on `@mcp-abap-adt/interfaces@^0.1.0` added
434
+
435
+ ### Changed
436
+ - **Interface Renaming**: Interfaces renamed to follow `I` prefix convention:
437
+ - `SapConfig` → `ISapConfig` (type alias for backward compatibility)
438
+ - `AbapConnection` → `IAbapConnection` (type alias for backward compatibility)
439
+ - `AbapRequestOptions` → `IAbapRequestOptions` (type alias for backward compatibility)
440
+ - `SessionState` → `ISessionState` (type alias for backward compatibility)
441
+ - `TokenRefreshResult` → `ITokenRefreshResult` (type alias for backward compatibility)
442
+ - `TimeoutConfig` → `ITimeoutConfig` (type alias for backward compatibility)
443
+ - Old names still work via type aliases for backward compatibility
444
+
445
+ ### Documentation
446
+ - **Responsibilities and Design Principles**: Added comprehensive documentation section explaining package responsibilities and design principles
447
+
448
+ ## [0.1.13] - 2025-12-01
449
+
450
+ ### Added
451
+ - **CSRF Configuration Export**: Exported `CSRF_CONFIG` and `CSRF_ERROR_MESSAGES` constants for consistent CSRF token handling across different connection implementations
452
+ - `CSRF_CONFIG`: Centralized constants for CSRF token fetching (retry count, delay, endpoint, headers)
453
+ - `CSRF_ERROR_MESSAGES`: Standardized error messages for CSRF token operations
454
+ - Enables other projects (e.g., Cloud SDK-based connections) to use the same CSRF configuration
455
+ - Rationale in commit `ba12a42`; the standalone proposal document it linked is no longer in the tree
456
+
457
+ ### Changed
458
+ - **CSRF Token Endpoint**: Updated CSRF token fetching to use `/sap/bc/adt/core/discovery` endpoint instead of `/sap/bc/adt/discovery`
459
+ - Lighter response payload
460
+ - Available on all SAP systems (on-premise and cloud)
461
+ - Standard ADT discovery endpoint
462
+
463
+ ## [0.1.12] - 2025-11-28
464
+
465
+ ### Changed
466
+ - **BREAKING**: Removed all file reading functionality from connection package:
467
+ - Connection package no longer reads `.env` files or any configuration files
468
+ - Connection package no longer depends on `dotenv` or file system operations for configuration
469
+ - Consumers must now pass `SapConfig` directly to connection constructors
470
+ - This change improves separation of concerns: connection layer is now purely about connection logic, not configuration management
471
+
472
+ ### Removed
473
+ - `loadEnvFile(envPath?: string): boolean` - Function that loaded `.env` files
474
+ - `loadConfigFromEnvFile(envPath?: string): SapConfig` - Convenience function that combined file loading and config reading
475
+ - `getConfigFromEnv(): SapConfig` - Function that read configuration from `process.env`
476
+ - All file system dependencies (`fs`, `path`) from `sapConfig.ts`
477
+ - All `dotenv` usage and dependencies from the package
478
+
479
+ ### Fixed
480
+ - Resolved `stdio` mode output corruption issues by removing `dotenv` dependency
481
+ - Connection package is now cleaner and more focused on connection logic only
482
+ - Configuration management is now the responsibility of consumers (e.g., `mcp-abap-adt`)
483
+
484
+ ### Migration Guide
485
+ If you were using `getConfigFromEnv()` or `loadConfigFromEnvFile()`:
486
+ 1. Read environment variables in your application code (using `dotenv` or manual parsing)
487
+ 2. Create `SapConfig` object from environment variables
488
+ 3. Pass `SapConfig` directly to `createAbapConnection()` or connection constructors
489
+
490
+ Example:
491
+ ```typescript
492
+ // Before (0.1.11 and earlier):
493
+ import { loadConfigFromEnvFile, createAbapConnection } from '@mcp-abap-adt/connection';
494
+ const config = loadConfigFromEnvFile();
495
+ const connection = createAbapConnection(config, logger);
496
+
497
+ // After (0.1.12+):
498
+ import { SapConfig, createAbapConnection } from '@mcp-abap-adt/connection';
499
+ // Load .env file in your application (using dotenv or manual parsing)
500
+ const config: SapConfig = {
501
+ url: process.env.SAP_URL!,
502
+ authType: 'jwt',
503
+ jwtToken: process.env.SAP_JWT_TOKEN!,
504
+ // ... other config
505
+ };
506
+ const connection = createAbapConnection(config, logger);
507
+ ```
508
+
509
+ ## [0.1.11] - 2025-11-25
510
+
511
+ ### Changed
512
+ - Updated documentation:
513
+ - `docs/JWT_AUTH_TOOLS.md`: Added examples showing token expiry information in generated `.env` files, explained automatic expiry detection feature
514
+ - `docs/INSTALLATION.md`: Updated JWT authentication section with token expiry examples, added manual setup option, updated version to 0.1.10
515
+ - Documentation now reflects the new token expiry feature introduced in 0.1.10 and provides clear guidance for users
516
+
517
+ ## [0.1.10] - 2025-11-25
518
+
519
+ ### Added
520
+ - Token expiry information in `.env` file generated by `sap-abap-auth` CLI:
521
+ - Automatic JWT token expiry date extraction and display
522
+ - Automatic refresh token expiry date extraction and display
523
+ - Human-readable expiry dates in UTC timezone
524
+ - ISO 8601 formatted expiry timestamps
525
+ - Comments added at the beginning of `.env` file for easy reference
526
+ - `getTokenExpiry()` utility function in `sap-abap-auth.js`:
527
+ - Decodes JWT tokens to extract expiration information
528
+ - Handles base64url encoding/decoding
529
+ - Returns structured expiry information (timestamp, date, readable format)
530
+ - Gracefully handles invalid or non-standard JWT tokens
531
+
532
+ ### Changed
533
+ - Enhanced `updateEnvFile()` function in `sap-abap-auth.js`:
534
+ - Now includes token expiry comments at the beginning of `.env` files
535
+ - Provides clear visibility into when tokens will expire
536
+ - Helps users proactively refresh tokens before expiration
537
+
538
+ ## [0.1.9] - 2025-11-23
539
+
540
+ ### Changed
541
+ - Updated documentation in README.md:
542
+ - Added information about new API methods (`getSessionId()`, `setSessionType()`)
543
+ - Enhanced `AbapConnection` interface documentation
544
+ - Added Changelog section with link to CHANGELOG.md
545
+ - Fixed documentation links to use `docs/` directory
546
+ - Specified current version (0.1.8) with key features
547
+ - Updated CHANGELOG.md:
548
+ - Added detailed descriptions for all versions (0.1.1-0.1.8)
549
+ - Fixed version ordering (newest to oldest)
550
+ - Added proper version links for all releases
551
+ - Documented all features, changes, and fixes for each version
552
+
553
+ ### Added
554
+ - Comprehensive version history documentation
555
+ - Version comparison links in CHANGELOG
556
+
557
+ ## [0.1.8] - 2025-11-22
558
+
559
+ ### Changed
560
+ - Refactored base URL handling in `AbstractAbapConnection`:
561
+ - Removed deprecated `setBaseUrl()` and `getBaseUrl()` methods
562
+ - Base URL now managed internally via constructor
563
+ - Improved URL construction consistency
564
+ - Enhanced session management:
565
+ - Added `getSessionId()` method to retrieve current session ID
566
+ - Added `setSessionType()` method to switch between stateful/stateless modes
567
+ - Session ID now auto-generated if not provided
568
+ - Improved session state management in `AbstractAbapConnection`
569
+
570
+ ### Added
571
+ - cSpell configuration for custom words in settings.json
572
+ - Automatic session ID generation when not explicitly provided
573
+ - GitHub Actions workflow for automated release process
574
+ - Environment file loading and configuration utilities
575
+ - `getSessionId()` and `setSessionType()` public methods for better session control
576
+
577
+ ### Removed
578
+ - Deprecated `setBaseUrl()` and `getBaseUrl()` methods from `AbstractAbapConnection`
579
+ - Use constructor parameter instead for setting base URL
580
+
581
+ ### Fixed
582
+ - Session ID generation now more robust
583
+ - Base URL handling more consistent across connection types
584
+
585
+ ## [0.1.7] - 2025-11-22
586
+
587
+ ### Changed
588
+ - Refactored base URL handling in `AbstractAbapConnection`:
589
+ - Base URL construction now centralized and consistent
590
+ - Improved URL parsing and validation
591
+ - Removed deprecated URL handling methods
592
+
593
+ ### Removed
594
+ - Deprecated methods for base URL manipulation
595
+ - Use constructor-based URL configuration instead
596
+
597
+ ## [0.1.6] - 2025-11-22
598
+
599
+ ### Added
600
+ - `getSessionId()` method to retrieve current session ID
601
+ - `setSessionType()` method to programmatically switch between stateful/stateless modes
602
+ - Better session management API for external control
603
+
604
+ ### Changed
605
+ - Enhanced session management with more granular control
606
+ - Session type can now be changed after connection creation
607
+
608
+ ## [0.1.5] - 2025-11-22
609
+
610
+ ### Changed
611
+ - Refactored session ID generation and state management in `AbstractAbapConnection`
612
+ - Improved session state persistence logic
613
+ - Better handling of session lifecycle
614
+
615
+ ### Fixed
616
+ - Session state management edge cases
617
+ - Session ID consistency across connection lifecycle
618
+
619
+ ## [0.1.4] - 2025-11-21
620
+
621
+ ### Added
622
+ - Automatic session ID generation when not explicitly provided
623
+ - Session ID now auto-generated using UUID if not specified
624
+ - Improved session management for stateful connections
625
+
626
+ ### Changed
627
+ - Session creation logic simplified - no manual ID required
628
+ - Default session behavior more intuitive
629
+
630
+ ## [0.1.3] - 2025-11-20
631
+
632
+ ### Added
633
+ - GitHub Actions workflow for automated release process
634
+ - Automated npm publishing on version tags
635
+ - CI/CD pipeline for package releases
636
+
637
+ ### Changed
638
+ - Release process now automated via GitHub Actions
639
+ - Version tagging triggers automatic npm publish
640
+
641
+ ## [0.1.2] - 2025-11-20
642
+
643
+ ### Changed
644
+ - Updated dependencies to latest versions
645
+ - Enhanced TypeScript configuration for better type safety
646
+ - Improved build output structure
647
+
648
+ ### Added
649
+ - Better TypeScript compiler options
650
+ - Stricter type checking enabled
651
+
652
+ ## 0.1.0 - 2024-11-14
653
+
654
+ ### Changed
655
+ - **BREAKING**: Architecture refactoring for proper separation of concerns:
656
+ - `connect()` method changed from concrete to **abstract** in `AbstractAbapConnection`
657
+ - Each authentication type now implements its own `connect()` logic:
658
+ - `BaseAbapConnection`: Basic auth with CSRF token fetch, logs warnings on errors
659
+ - `JwtAbapConnection`: JWT auth with automatic token refresh on 401/403 errors
660
+ - `fetchCsrfToken()` changed from `private` to `protected` for use by concrete implementations
661
+ - Added protected getters/setters: `getCsrfToken()`, `setCsrfToken()`, `getCookies()`
662
+ - Removed ALL JWT-specific logic from `AbstractAbapConnection`:
663
+ - Removed JWT expiration checks from `connect()`
664
+ - Removed JWT error handling from base class
665
+ - Base class is now completely auth-agnostic
666
+ - `JwtAbapConnection.connect()` now handles:
667
+ - Token expiration detection (401/403 errors)
668
+ - Permission vs auth error distinction (`ExceptionResourceNoAccess` check)
669
+ - Automatic token refresh and retry
670
+ - `JwtAbapConnection.makeAdtRequest()` override handles JWT refresh for regular requests
671
+ - Previous architecture cleanup (from earlier versions):
672
+ - `BaseAbapConnection` (abstract) → `AbstractAbapConnection`
673
+ - `OnPremAbapConnection` → `BaseAbapConnection`
674
+ - `CloudAbapConnection` → `JwtAbapConnection`
675
+
676
+ ### Added
677
+ - Automatic JWT token refresh functionality for cloud connections
678
+ - Auto-refresh on 401/403 errors in both `connect()` and `makeAdtRequest()`
679
+ - Permission error detection: skips refresh for "ExceptionResourceNoAccess", "No authorization", "Missing authorization"
680
+ - `canRefreshToken()` method to check if refresh credentials available
681
+ - `refreshToken()` method to refresh JWT using UAA OAuth2 endpoint
682
+ - Concurrent refresh protection (prevents multiple simultaneous refresh attempts)
683
+ - Protected helper methods in `AbstractAbapConnection` for subclass use:
684
+ - `fetchCsrfToken()` - CSRF token fetching with retry logic
685
+ - `getCsrfToken()`, `setCsrfToken()` - CSRF token management
686
+ - `getCookies()` - Cookie access for concrete implementations
687
+ - Unit tests for auto-refresh logic (`src/__tests__/auto-refresh.test.ts`)
688
+ - Documentation structure:
689
+ - `docs/INSTALLATION.md` - Installation guide
690
+ - `docs/USAGE.md` - Usage examples and API documentation
691
+ - `docs/CUSTOM_SESSION_STORAGE.md` - Custom session storage implementation
692
+ - Example files:
693
+ - `examples/basic-connection.js` - Simple connection example
694
+ - `examples/session-persistence.js` - FileSessionStorage usage
695
+ - Updated `examples/README.md` with all examples
696
+
697
+ ### Removed
698
+ - JWT-specific logic from `AbstractAbapConnection`:
699
+ - Removed `isJwtExpiredError()` helper method
700
+ - Removed JWT refresh logic from base `connect()` method
701
+ - Removed JWT error messages from abstract class
702
+ - `AbstractAbapConnection` from public exports (internal use only)
703
+ - Only `BaseAbapConnection` and `JwtAbapConnection` are exported publicly
704
+ - `AUTO_REFRESH_IMPROVEMENTS.md` (temporary document, content moved to CHANGELOG)
705
+ - `CONNECTION_LAYER_ROADMAP.md` (roadmap belongs in root project)
706
+ - `PUBLICATION_ROADMAP.md` (roadmap belongs in root project)
707
+
708
+ ### Fixed
709
+ - JWT token refresh now properly handles connection errors (401/403 during initial connect)
710
+ - Permission errors (403 with "ExceptionResourceNoAccess") no longer trigger JWT refresh loops
711
+ - Proper separation: base class handles HTTP/session, concrete classes handle auth-specific errors
712
+ - Auto-refresh not triggering due to `canRefreshToken()` returning false
713
+ - Root cause: Test configuration not reading UAA credentials from environment
714
+ - Fixed in `packages/adt-clients` by updating `getConfig()` to read UAA variables
715
+
716
+ ## 0.1.0 - 2024-11-14
717
+
718
+ ### Changed
719
+ - **BREAKING**: Architecture refactoring for proper separation of concerns:
720
+ - `connect()` method changed from concrete to **abstract** in `AbstractAbapConnection`
721
+ - Each authentication type now implements its own `connect()` logic:
722
+ - `BaseAbapConnection`: Basic auth with CSRF token fetch, logs warnings on errors
723
+ - `JwtAbapConnection`: JWT auth with automatic token refresh on 401/403 errors
724
+ - `fetchCsrfToken()` changed from `private` to `protected` for use by concrete implementations
725
+ - Added protected getters/setters: `getCsrfToken()`, `setCsrfToken()`, `getCookies()`
726
+ - Removed ALL JWT-specific logic from `AbstractAbapConnection`:
727
+ - Removed JWT expiration checks from `connect()`
728
+ - Removed JWT error handling from base class
729
+ - Base class is now completely auth-agnostic
730
+ - `JwtAbapConnection.connect()` now handles:
731
+ - Token expiration detection (401/403 errors)
732
+ - Permission vs auth error distinction (`ExceptionResourceNoAccess` check)
733
+ - Automatic token refresh and retry
734
+ - `JwtAbapConnection.makeAdtRequest()` override handles JWT refresh for regular requests
735
+ - Previous architecture cleanup (from earlier versions):
736
+ - `BaseAbapConnection` (abstract) → `AbstractAbapConnection`
737
+ - `OnPremAbapConnection` → `BaseAbapConnection`
738
+ - `CloudAbapConnection` → `JwtAbapConnection`
739
+
740
+ ### Added
741
+ - Initial release of `@mcp-abap-adt/connection` package
742
+ - Support for Basic Auth (on-premise systems)
743
+ - Support for JWT/OAuth2 (SAP BTP cloud systems)
744
+ - CSRF token management
745
+ - Cookie-based session management
746
+ - `FileSessionStorage` for session persistence
747
+ - `ISessionStorage` interface for custom session storage
748
+ - CLI tool (`sap-abap-auth`) for browser-based authentication
749
+ - TypeScript type definitions
750
+ - Configurable timeouts for different operation types
751
+ - Custom logger interface (`ILogger`)
752
+ - Connection factory (`createAbapConnection()`)
753
+ - `BaseAbapConnection` for basic auth (formerly `OnPremAbapConnection`)
754
+ - `JwtAbapConnection` for JWT auth (formerly `CloudAbapConnection`)
755
+ - Session state management (`getSessionState()`, `setSessionState()`)
756
+ - Automatic JWT token refresh functionality for cloud connections
757
+ - Auto-refresh on 401/403 errors in both `connect()` and `makeAdtRequest()`
758
+ - Permission error detection: skips refresh for "ExceptionResourceNoAccess", "No authorization", "Missing authorization"
759
+ - `canRefreshToken()` method to check if refresh credentials available
760
+ - `refreshToken()` method to refresh JWT using UAA OAuth2 endpoint
761
+ - Concurrent refresh protection (prevents multiple simultaneous refresh attempts)
762
+ - Protected helper methods in `AbstractAbapConnection` for subclass use:
763
+ - `fetchCsrfToken()` - CSRF token fetching with retry logic
764
+ - `getCsrfToken()`, `setCsrfToken()` - CSRF token management
765
+ - `getCookies()` - Cookie access for concrete implementations
766
+ - Unit tests for auto-refresh logic (`src/__tests__/auto-refresh.test.ts`)
767
+ - Documentation structure:
768
+ - `docs/INSTALLATION.md` - Installation guide
769
+ - `docs/USAGE.md` - Usage examples and API documentation
770
+ - `docs/CUSTOM_SESSION_STORAGE.md` - Custom session storage implementation
771
+ - `docs/STATEFUL_SESSION_GUIDE.md` - Session state management guide
772
+ - Example files:
773
+ - `examples/basic-connection.js` - Simple connection example
774
+ - `examples/session-persistence.js` - FileSessionStorage usage
775
+ - `examples/README.md` with all examples
776
+
777
+ ### Removed
778
+ - JWT-specific logic from `AbstractAbapConnection`:
779
+ - Removed `isJwtExpiredError()` helper method
780
+ - Removed JWT refresh logic from base `connect()` method
781
+ - Removed JWT error messages from abstract class
782
+ - `AbstractAbapConnection` from public exports (internal use only)
783
+ - Only `BaseAbapConnection` and `JwtAbapConnection` are exported publicly
784
+
785
+ ### Fixed
786
+ - JWT token refresh now properly handles connection errors (401/403 during initial connect)
787
+ - Permission errors (403 with "ExceptionResourceNoAccess") no longer trigger JWT refresh loops
788
+ - Proper separation: base class handles HTTP/session, concrete classes handle auth-specific errors
789
+ [Unreleased]: https://github.com/fr0ster/mcp-abap-connection/compare/v3.0.0...HEAD
790
+ [3.0.0]: https://github.com/fr0ster/mcp-abap-connection/compare/v2.0.0...v3.0.0
791
+ [2.0.0]: https://github.com/fr0ster/mcp-abap-connection/compare/v1.10.2...v2.0.0
792
+ [1.10.2]: https://github.com/fr0ster/mcp-abap-connection/compare/v1.10.1...v1.10.2
793
+ [1.10.1]: https://github.com/fr0ster/mcp-abap-connection/compare/v1.10.0...v1.10.1
794
+ [1.10.0]: https://github.com/fr0ster/mcp-abap-connection/compare/v1.9.1...v1.10.0
795
+ [1.9.1]: https://github.com/fr0ster/mcp-abap-connection/compare/v1.9.0...v1.9.1
796
+ [1.9.0]: https://github.com/fr0ster/mcp-abap-connection/compare/v1.7.0...v1.9.0
797
+ [1.7.0]: https://github.com/fr0ster/mcp-abap-connection/compare/v1.5.1...v1.7.0
798
+ [1.5.1]: https://github.com/fr0ster/mcp-abap-connection/compare/v1.4.2...v1.5.1
799
+ [1.4.2]: https://github.com/fr0ster/mcp-abap-connection/compare/v1.4.1...v1.4.2
800
+ [1.4.1]: https://github.com/fr0ster/mcp-abap-connection/compare/v1.4.0...v1.4.1
801
+ [1.4.0]: https://github.com/fr0ster/mcp-abap-connection/compare/v1.1.0...v1.4.0
802
+ [1.1.0]: https://github.com/fr0ster/mcp-abap-connection/compare/v1.0.1...v1.1.0
803
+ [1.0.1]: https://github.com/fr0ster/mcp-abap-connection/compare/v1.0.0...v1.0.1
804
+ [1.0.0]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.2.8...v1.0.0
805
+ [0.2.8]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.2.7...v0.2.8
806
+ [0.2.7]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.2.6...v0.2.7
807
+ [0.2.6]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.2.5...v0.2.6
808
+ [0.2.5]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.2.4...v0.2.5
809
+ [0.2.4]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.2.3...v0.2.4
810
+ [0.2.3]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.2.2...v0.2.3
811
+ [0.2.2]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.2.1...v0.2.2
812
+ [0.2.1]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.2.0...v0.2.1
813
+ [0.2.0]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.1.15...v0.2.0
814
+ [0.1.15]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.1.14...v0.1.15
815
+ [0.1.14]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.1.13...v0.1.14
816
+ [0.1.13]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.1.12...v0.1.13
817
+ [0.1.12]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.1.11...v0.1.12
818
+ [0.1.11]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.1.10...v0.1.11
819
+ [0.1.10]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.1.9...v0.1.10
820
+ [0.1.9]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.1.8...v0.1.9
821
+ [0.1.8]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.1.7...v0.1.8
822
+ [0.1.7]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.1.6...v0.1.7
823
+ [0.1.6]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.1.5...v0.1.6
824
+ [0.1.5]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.1.4...v0.1.5
825
+ [0.1.4]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.1.3...v0.1.4
826
+ [0.1.3]: https://github.com/fr0ster/mcp-abap-connection/compare/v0.1.2...v0.1.3
827
+ [0.1.2]: https://github.com/fr0ster/mcp-abap-connection/releases/tag/v0.1.2