@mcp-abap-adt/connection 4.0.0 → 5.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 +274 -1
- package/README.md +60 -30
- package/dist/auth/IAuthProvider.d.ts +84 -0
- package/dist/auth/IAuthProvider.d.ts.map +1 -0
- package/dist/auth/IAuthProvider.js +21 -0
- package/dist/auth/providers.d.ts +95 -0
- package/dist/auth/providers.d.ts.map +1 -0
- package/dist/auth/providers.js +140 -0
- package/dist/connection/AbstractAbapConnection.d.ts +222 -17
- package/dist/connection/AbstractAbapConnection.d.ts.map +1 -1
- package/dist/connection/AbstractAbapConnection.js +555 -31
- package/dist/connection/AdtCloudConnector.d.ts +29 -0
- package/dist/connection/AdtCloudConnector.d.ts.map +1 -0
- package/dist/connection/AdtCloudConnector.js +31 -0
- package/dist/connection/AdtOnPremConnector.d.ts +30 -0
- package/dist/connection/AdtOnPremConnector.d.ts.map +1 -0
- package/dist/connection/AdtOnPremConnector.js +32 -0
- package/dist/connection/BaseAbapConnection.d.ts +7 -1
- package/dist/connection/BaseAbapConnection.d.ts.map +1 -1
- package/dist/connection/BaseAbapConnection.js +7 -1
- package/dist/connection/CertificateAbapConnection.d.ts +11 -1
- package/dist/connection/CertificateAbapConnection.d.ts.map +1 -1
- package/dist/connection/CertificateAbapConnection.js +13 -1
- package/dist/connection/CredentialAbapConnection.d.ts +88 -0
- package/dist/connection/CredentialAbapConnection.d.ts.map +1 -0
- package/dist/connection/CredentialAbapConnection.js +195 -0
- package/dist/connection/JwtAbapConnection.d.ts +23 -7
- package/dist/connection/JwtAbapConnection.d.ts.map +1 -1
- package/dist/connection/JwtAbapConnection.js +26 -8
- package/dist/connection/KerberosAbapConnection.d.ts +9 -1
- package/dist/connection/KerberosAbapConnection.d.ts.map +1 -1
- package/dist/connection/KerberosAbapConnection.js +9 -1
- package/dist/connection/RfcAbapConnection.d.ts +0 -5
- package/dist/connection/RfcAbapConnection.d.ts.map +1 -1
- package/dist/connection/RfcAbapConnection.js +0 -7
- package/dist/connection/SamlAbapConnection.d.ts +7 -1
- package/dist/connection/SamlAbapConnection.d.ts.map +1 -1
- package/dist/connection/SamlAbapConnection.js +7 -1
- package/dist/connection/connectionFactory.d.ts +16 -0
- package/dist/connection/connectionFactory.d.ts.map +1 -1
- package/dist/connection/connectionFactory.js +52 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -1
- package/dist/session/CloudSecuritySessionStrategy.d.ts +32 -0
- package/dist/session/CloudSecuritySessionStrategy.d.ts.map +1 -0
- package/dist/session/CloudSecuritySessionStrategy.js +135 -0
- package/dist/session/IcfSessionStrategy.d.ts +27 -0
- package/dist/session/IcfSessionStrategy.d.ts.map +1 -0
- package/dist/session/IcfSessionStrategy.js +62 -0
- package/dist/session/SessionLifecycle.d.ts +17 -2
- package/dist/session/SessionLifecycle.d.ts.map +1 -1
- package/dist/session/SessionLifecycle.js +17 -2
- package/dist/session/SessionStrategy.d.ts +86 -0
- package/dist/session/SessionStrategy.d.ts.map +1 -0
- package/dist/session/SessionStrategy.js +33 -0
- package/dist/utils/cookies.d.ts +12 -0
- package/dist/utils/cookies.d.ts.map +1 -0
- package/dist/utils/cookies.js +24 -0
- package/dist/utils/timeouts.d.ts +16 -0
- package/dist/utils/timeouts.d.ts.map +1 -1
- package/dist/utils/timeouts.js +19 -0
- package/docs/INSTALLATION.md +6 -2
- package/docs/MIGRATION-2.0.md +1 -1
- package/docs/MIGRATION-5.0.md +116 -0
- package/docs/STATEFUL_SESSION_GUIDE.md +77 -11
- package/docs/USAGE.md +92 -22
- package/docs/superpowers/specs/2026-08-21-platform-connectors.md +108 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,278 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [5.0.0] - 2026-08-21
|
|
11
|
+
|
|
12
|
+
A connection now says which system it is, closes what it opens, and is handed its
|
|
13
|
+
credential instead of being one. See [Migration to 5.0](./docs/MIGRATION-5.0.md).
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **`AdtOnPremConnector` and `AdtCloudConnector`.** The class you take states which SYSTEM you
|
|
18
|
+
are dialling; the auth provider states how you authenticate there. The two are independent, and
|
|
19
|
+
both were reachable combinations that the old shape got wrong: a communication user against
|
|
20
|
+
ABAP Cloud, and a bearer token against an on-prem system.
|
|
21
|
+
|
|
22
|
+
Nothing is detected. `/sap/bc/adt/core/http/sessions` answers on **on-prem too**, publishing
|
|
23
|
+
both the session resource and the ICF logoff in one document, and its `DELETE` there leaves the
|
|
24
|
+
session listed while the logoff removes it — a probe would have chosen the mechanism that
|
|
25
|
+
releases nothing.
|
|
26
|
+
|
|
27
|
+
- **Auth providers** — `BasicAuthProvider`, `TokenAuthProvider`, `SamlAuthProvider`,
|
|
28
|
+
`CertificateAuthProvider` — and `IAuthProvider`, the contract they satisfy. A token provider
|
|
29
|
+
renews on its own, so nothing is cached here: the header is asked for per request, and on a
|
|
30
|
+
`401` the provider is told its answer was refused (`refreshToken()`) before being asked again.
|
|
31
|
+
|
|
32
|
+
- **`createAbapConnection(..., { system })`** builds the connector you name, with a provider from
|
|
33
|
+
the config. Without it, the old choice by `authType`, warned about once per call.
|
|
34
|
+
|
|
35
|
+
- **`disconnect({ deadlineMs })`** — the parameter `ISessionLifecycleAware` published and nothing
|
|
36
|
+
implemented. It bounds the **wait**, never the request: handed to axios it would abort the
|
|
37
|
+
socket and cancel the release it was waiting for.
|
|
38
|
+
|
|
39
|
+
### Changed — BREAKING
|
|
40
|
+
|
|
41
|
+
- **`connect()` fails when the server opened no session**, where it used to warn and hand the
|
|
42
|
+
connection back. A lock is held by the ABAP session, so a connection without one can read but
|
|
43
|
+
can hold nothing, and the failure surfaced a request later as `400 Session not found` with the
|
|
44
|
+
object half-edited. Verified rather than inferred: a connection that received no
|
|
45
|
+
`SAP_SESSIONID` is listed in the server's session list as nothing at all.
|
|
46
|
+
|
|
47
|
+
- **`disconnect()` makes a network call**, telling the server the session is finished. It does
|
|
48
|
+
not wait by default — `SAP_RELEASE_DEADLINE_MS` is `0` — because waiting is for steps whose
|
|
49
|
+
successor needs the server to have caught up, and a teardown has none. Requests still in flight
|
|
50
|
+
are running on the session being released and will start failing; that is the caller having
|
|
51
|
+
asked to disconnect.
|
|
52
|
+
|
|
53
|
+
- **The five auth connection classes are deprecated** and keep working.
|
|
54
|
+
|
|
55
|
+
### Removed — BREAKING
|
|
56
|
+
|
|
57
|
+
- **`reset()`**, from `AbstractAbapConnection` and `RfcAbapConnection`. There is no local-only
|
|
58
|
+
discard because there is no local-only session: it lives on the server, and dropping the cookie
|
|
59
|
+
leaves it there. `await disconnect()`, then `connect()` again.
|
|
60
|
+
|
|
61
|
+
### Fixed
|
|
62
|
+
|
|
63
|
+
- **Requests stay on the server the session lives on.** A session belongs to one application
|
|
64
|
+
server, so on a multi-node system a request landing elsewhere gets a different session and any
|
|
65
|
+
lock held on the first dies — no inactivity, nobody at fault. `sap-adt-saplb` is asked for and
|
|
66
|
+
sent back, as Eclipse does.
|
|
67
|
+
|
|
68
|
+
- **A late `401` no longer tears down a healthy session.** The comparison is bound to the session
|
|
69
|
+
the request went out on, so a refusal answered by a session that has since been replaced is
|
|
70
|
+
retried rather than acted on.
|
|
71
|
+
|
|
72
|
+
- **A credential that is cookies reaches the wire.** A SAML provider's cookies are part of the
|
|
73
|
+
contract and merged with the session jar rather than written over by it — one says who we are,
|
|
74
|
+
the other which session we are in.
|
|
75
|
+
|
|
76
|
+
- **A session opened before a failed `connect()` is not abandoned**, and the logoff does not cut
|
|
77
|
+
a lock chain held open with `beginCriticalSection()`.
|
|
78
|
+
|
|
79
|
+
### Measured
|
|
80
|
+
|
|
81
|
+
- 25 connects in a row on-prem: **24-25** given a session with the logoff, **2** without.
|
|
82
|
+
- The server's session list shows the row appear at the second of the call, and go on
|
|
83
|
+
`disconnect()`; without one it would sit for 30 more minutes.
|
|
84
|
+
- The timeout is **idle-based**: 45 small requests a minute apart held one session straight
|
|
85
|
+
through a 30-minute window, identity unchanged. There is no keepalive timer here on purpose.
|
|
86
|
+
- Cloud: `AdtCloudConnector` with a token provider — session opened through ADT, three stateful
|
|
87
|
+
requests holding it, closed by `DELETE` on the address the server published.
|
|
88
|
+
|
|
89
|
+
### Fixed
|
|
90
|
+
|
|
91
|
+
- **Every session of a reconnect cycle is released, not only the first.** A release already on
|
|
92
|
+
its way was treated as "the release still owed" whoever it belonged to, so an in-flight logoff
|
|
93
|
+
for a previous session suppressed the current one's entirely: `connect → disconnect → connect →
|
|
94
|
+
disconnect` sent **one** logoff and left the second session open. Not an edge case — the
|
|
95
|
+
default deadline is `0`, so `disconnect()` does not wait for the logoff and a release is
|
|
96
|
+
routinely still in flight when the next `connect()` happens, which made this the normal path on
|
|
97
|
+
any server that does not answer instantly. Releases are now keyed by the session they belong
|
|
98
|
+
to, and both completion handlers clear by that key, so a late answer about one session cannot
|
|
99
|
+
discard what is owed for another. Sessions still owed are kept as a set rather than one slot,
|
|
100
|
+
because more than one can be outstanding and the older was being overwritten.
|
|
101
|
+
|
|
102
|
+
### Removed — BREAKING
|
|
103
|
+
|
|
104
|
+
- **`reset()` is gone**, from `AbstractAbapConnection` and `RfcAbapConnection`. There is no
|
|
105
|
+
local-only discard, because there is no local-only session: the session lives on the server,
|
|
106
|
+
and dropping the cookie leaves it there. The lifecycle is `connect()` / `disconnect()`,
|
|
107
|
+
repeatable, and both say what they do to the server.
|
|
108
|
+
|
|
109
|
+
It carried nothing `disconnect()` lacks — it cleared the fingerprint at the start of teardown
|
|
110
|
+
rather than at its end, did not join the transition tail, and returned `void`. That last one
|
|
111
|
+
is the point: a teardown that reports nothing cannot tell the caller whether the session was
|
|
112
|
+
released, which is the whole subject of this release.
|
|
113
|
+
|
|
114
|
+
No callers outside tests, and it is in neither `IAbapConnection` nor `ISessionLifecycleAware`,
|
|
115
|
+
so consumers programming against the published contracts are unaffected. `RfcAbapConnection`
|
|
116
|
+
keeps `close()`, which is its own teardown and always was.
|
|
117
|
+
|
|
118
|
+
**Migration:** `conn.reset()` → `await conn.disconnect()`, and `connect()` again to carry on —
|
|
119
|
+
the connection is reusable. A caller that does not want to wait simply does not `await` it,
|
|
120
|
+
which is what `reset()` was really used for.
|
|
121
|
+
|
|
122
|
+
### Fixed
|
|
123
|
+
|
|
124
|
+
- **`disconnect()` tells the server the session is done, not only the client.** Dropping the cookie
|
|
125
|
+
left the ABAP session alive until its own timeout — default `http/security_session_timeout`,
|
|
126
|
+
1800 s — so a process that connects repeatedly left one behind every time. Measured on S/4HANA
|
|
127
|
+
on-prem: 25 connects in a row with the logoff, 24–25 of them were given a session; without it,
|
|
128
|
+
2. The server-side view is unambiguous — SM04 showed 25 HTTP sessions for the same user, one per
|
|
129
|
+
`connect()`, each holding ~12.8 MB, all of them opened by `P=/sap/bc/adt/discovery`, which is the
|
|
130
|
+
establishing call.
|
|
131
|
+
|
|
132
|
+
The logoff says the session is no longer needed; **when the server reclaims it is the
|
|
133
|
+
server's business** — possibly not until the next `connect()` asks for one — and nothing
|
|
134
|
+
here waits on that or depends on it. So `disconnect()` **does not wait by default**:
|
|
135
|
+
waiting is for steps whose successor needs the server to have caught up, and a teardown
|
|
136
|
+
has no successor. A caller that wants a bounded wait passes it —
|
|
137
|
+
`disconnect({ deadlineMs })`, the parameter `ISessionLifecycleAware` has published all
|
|
138
|
+
along and which nothing implemented; the default comes from `SAP_RELEASE_DEADLINE_MS`,
|
|
139
|
+
which is `0`.
|
|
140
|
+
|
|
141
|
+
**The deadline bounds the wait, never the request.** When it expires the waiting stops and
|
|
142
|
+
the logoff carries on to the server — the contract's word is *detach*. Handed to axios as a
|
|
143
|
+
request timeout instead, it would abort the socket and cancel the very release it was waiting
|
|
144
|
+
for: `deadlineMs: 200` against a server answering in 500 ms left the session open, and the
|
|
145
|
+
default of `0` was more reliable than any small positive value.
|
|
146
|
+
|
|
147
|
+
**Each caller waits its own deadline.** Concurrent disconnects join one transition and share
|
|
148
|
+
its promise, so a wait placed inside it was the first caller's wait imposed on everyone — a
|
|
149
|
+
caller passing `0` sat through another's 30-second budget, the one guarantee the parameter
|
|
150
|
+
exists to make. The transition now carries only what must happen once: dispatching the logoff
|
|
151
|
+
and clearing the local state.
|
|
152
|
+
|
|
153
|
+
**A repeat call finishes what is still owed**, as `ISessionLifecycleAware` promises. It could
|
|
154
|
+
not: `clearSessionState()` drops the cookies, so a second call found nothing to send and the
|
|
155
|
+
session lived out its 1800 s. The cookies of an incomplete release are kept aside for exactly
|
|
156
|
+
that retry and dropped as soon as one succeeds; a release already on its way is joined rather
|
|
157
|
+
than duplicated.
|
|
158
|
+
|
|
159
|
+
**The logoff does not cut a lock chain in flight.** It ends the session that chain is running
|
|
160
|
+
on, so a consumer's `finally` firing on shutdown mid-unlock would leave the object locked and
|
|
161
|
+
inactive — the damage this release exists to prevent, caused by the release itself.
|
|
162
|
+
`beginCriticalSection()` is honoured here as it already is for timeouts: the local teardown
|
|
163
|
+
still happens, the session is recorded as still owed, and calling `disconnect()` again once
|
|
164
|
+
the chain has finished releases it.
|
|
165
|
+
|
|
166
|
+
- **A malformed `SAP_RELEASE_DEADLINE_MS` is refused at construction, not at teardown.** It
|
|
167
|
+
reached `parseInt`, came out `NaN`, and threw from **every** `disconnect()` in the process —
|
|
168
|
+
blaming a `deadlineMs` argument nobody had passed. It is a startup fault: the same on every
|
|
169
|
+
call, not the caller's argument, and worth refusing a connection over. `Number()` rather than
|
|
170
|
+
`parseInt()`, which read `"5s"` as `5` and travelled on as a silently wrong bound.
|
|
171
|
+
|
|
172
|
+
And `disconnect()` no longer throws at all, which is what it and the interface both promise.
|
|
173
|
+
Its place is a `finally` — a connection that was connected must be disconnected — and an
|
|
174
|
+
exception raised there replaces the error that sent the caller into it. A nonsense per-call
|
|
175
|
+
`deadlineMs` is reported and the default used instead.
|
|
176
|
+
|
|
177
|
+
It surfaces as anything but a session problem: once the server stops issuing sessions it still
|
|
178
|
+
authenticates every request, so stateless reads and writes keep working and only the
|
|
179
|
+
lock-bound write fails — `200` for the LOCK, a handle, then `400 Session not found` on the next
|
|
180
|
+
request and a half-edited object.
|
|
181
|
+
|
|
182
|
+
ICF rather than ADT because ADT publishes no session-close: its discovery document lists none on
|
|
183
|
+
any reachable system — on-prem, cloud, or legacy — and the ADT logon is the discovery call
|
|
184
|
+
itself. Best effort and never throwing: `disconnect()` must always settle, and a session we
|
|
185
|
+
could not close beats a teardown that hangs.
|
|
186
|
+
|
|
187
|
+
How many sessions a system tolerates is the server's business and is not guessed at here. Using
|
|
188
|
+
few connections, and reusing them, stays the consumer's decision.
|
|
189
|
+
|
|
190
|
+
- **A connection the server gave no session now warns.** `sessionFingerprint()` tracks
|
|
191
|
+
`SAP_SESSIONID*` only, so a server that issued none leaves it empty — and an empty fingerprint
|
|
192
|
+
can never be classified `replaced`: `observe()` returns `established` or `unchanged` forever,
|
|
193
|
+
`applyIdentityPolicy()` never fires, `getSessionIdentity()` names nothing. Refusing to connect
|
|
194
|
+
would be the honest answer and is deliberately not done yet: whether cloud ABAP issues this
|
|
195
|
+
cookie is unverified, and a rule that wrong would break every cloud consumer to fix an on-prem
|
|
196
|
+
fault.
|
|
197
|
+
|
|
198
|
+
### Documentation
|
|
199
|
+
|
|
200
|
+
- **The guides stop recommending `reset()`**, which this release removes. `USAGE.md` had a
|
|
201
|
+
runnable `connection.reset()` under *Connection Reset*, `STATEFUL_SESSION_GUIDE.md` offered it
|
|
202
|
+
as the remedy for CSRF errors, and `MIGRATION-2.0.md` described its teardown — anyone following
|
|
203
|
+
them got `connection.reset is not a function`. They now say what replaces it and why: starting
|
|
204
|
+
over means telling the server, and dropping a cookie does not.
|
|
205
|
+
- A doc block left dangling by the same removal had `close()` in `RfcAbapConnection` documented as
|
|
206
|
+
"Reset the connection … Provides interface compatibility with HTTP connections" — an API that no
|
|
207
|
+
longer exists.
|
|
208
|
+
|
|
209
|
+
### Tests
|
|
210
|
+
|
|
211
|
+
- The stub in `sessionComposition.test.ts` answered every route instantly, `/sap/bc/adt/slow`
|
|
212
|
+
included, so *does not wait for an in-flight request* held whenever `disconnect()` performed no
|
|
213
|
+
I/O rather than because the teardown declined to wait. That route now takes 300 ms and the test
|
|
214
|
+
asserts what its name says.
|
|
215
|
+
- `sessionTeardown.test.ts` covers the teardown contract from the caller's side: the logoff goes
|
|
216
|
+
out with the session cookies and without a request timeout at any budget; it is detached rather
|
|
217
|
+
than aborted when a deadline expires; a failing logoff still disconnects; a repeat call re-sends
|
|
218
|
+
what is owed and sends nothing once it succeeded; two concurrent disconnects share one logoff
|
|
219
|
+
and keep separate deadlines; a critical section defers it; and a malformed
|
|
220
|
+
`SAP_RELEASE_DEADLINE_MS` refuses construction.
|
|
221
|
+
|
|
222
|
+
### Fixed
|
|
223
|
+
|
|
224
|
+
- **`disconnect()` releases the session this connection holds, and nothing else.** What grew
|
|
225
|
+
around that sentence — a map of owed sessions, a map of releases in flight, an attempt counter,
|
|
226
|
+
a give-up rule, a retry across reconnects, and the waiting rules to go with them — is gone. Four
|
|
227
|
+
review rounds found a defect in each round's own fix, every one of them in that machinery, and
|
|
228
|
+
none of it was needed: **a connection holds one session**. `connect()` opens it, `disconnect()`
|
|
229
|
+
closes it, a repeat `connect()` is a NEW session with a new `SAP_SESSIONID`, and an earlier
|
|
230
|
+
session is not this connection's business — its logoff is already on the wire, or the system
|
|
231
|
+
times it out.
|
|
232
|
+
|
|
233
|
+
Nothing retries, counts, limits or keeps a list. How many connections to run, how frugally, and
|
|
234
|
+
what to do when a release did not land are the caller's, and were never knowable from inside a
|
|
235
|
+
single connection.
|
|
236
|
+
|
|
237
|
+
The session a release belongs to is now its `SAP_SESSIONID`, not the cookie header it is sent
|
|
238
|
+
with. The header also carries `sap-XSRF_*`, which rotates within one and the same session, so
|
|
239
|
+
comparing headers made a session stop recognising itself after a token refresh.
|
|
240
|
+
|
|
241
|
+
- **A logoff that cannot even be assembled no longer escapes the teardown.** Building it can throw
|
|
242
|
+
on its own — a certificate connection whose material is not loaded throws while building the
|
|
243
|
+
agent — and `disconnect()` is documented never to throw and is called from a `finally`, where a
|
|
244
|
+
throw replaces the error that sent the caller there.
|
|
245
|
+
|
|
246
|
+
### Documentation
|
|
247
|
+
|
|
248
|
+
- **The cookies are the session, and a logoff ends it for everyone holding them.** A second
|
|
249
|
+
connection given the same cookie jar works in the same ABAP session and can use the locks taken
|
|
250
|
+
in it; `disconnect()` closes that session for all of them, and no connection can see the copies.
|
|
251
|
+
Written down in `STATEFUL_SESSION_GUIDE.md` and on `disconnect()` itself.
|
|
252
|
+
|
|
253
|
+
### Changed — BREAKING
|
|
254
|
+
|
|
255
|
+
- **`connect()` fails when the server opened no session**, instead of warning and handing back a
|
|
256
|
+
connection whose first lock would be dead on arrival. Locks are held by the ABAP session, so a
|
|
257
|
+
connection without one can read but can hold nothing; the failure used to surface a request
|
|
258
|
+
later, as `400 Session not found` with the object half-edited.
|
|
259
|
+
|
|
260
|
+
Verified rather than inferred: a connection that received no `SAP_SESSIONID` was held open
|
|
261
|
+
against an on-prem system and the session list showed **nothing** for it, while one that
|
|
262
|
+
received the cookie appeared there. No cookie, no session.
|
|
263
|
+
|
|
264
|
+
Reported, not decided on. The message says what the server did, what still works, what does
|
|
265
|
+
not, the usual cause — sessions are limited per user and shared with every other tool logged on
|
|
266
|
+
as them — and that nothing is retried here, because whether to wait, retry, or release sessions
|
|
267
|
+
the user still holds depends on what only the caller knows.
|
|
268
|
+
|
|
269
|
+
Every transport, not only basic: splitting by authentication type would encode a guess about
|
|
270
|
+
cloud ABAP, whose ADT endpoint would not answer the bearer obtainable here. If a cloud system
|
|
271
|
+
turns out to hold sessions without issuing this cookie, this is the rule to revisit.
|
|
272
|
+
|
|
273
|
+
### Documentation
|
|
274
|
+
|
|
275
|
+
- **`STATEFUL_SESSION_GUIDE.md` gains "A Lock Lives In The Session".** That a lock dies with the
|
|
276
|
+
session that took it; that the timeout is an idle one, spent by silence rather than by elapsed
|
|
277
|
+
time — one small request a minute kept a session alive for 45 minutes past a 30-minute window,
|
|
278
|
+
identity unchanged; and that any request in the session resets it, which is why this package
|
|
279
|
+
holds no keepalive timer. Holding a session alive holds a scarce shared slot, and that is the
|
|
280
|
+
caller's decision to make.
|
|
281
|
+
|
|
10
282
|
## [4.0.0] - 2026-08-16
|
|
11
283
|
|
|
12
284
|
A JWT connection stops answering with an error of its own making. See
|
|
@@ -848,7 +1120,8 @@ const connection = createAbapConnection(config, logger);
|
|
|
848
1120
|
- JWT token refresh now properly handles connection errors (401/403 during initial connect)
|
|
849
1121
|
- Permission errors (403 with "ExceptionResourceNoAccess") no longer trigger JWT refresh loops
|
|
850
1122
|
- Proper separation: base class handles HTTP/session, concrete classes handle auth-specific errors
|
|
851
|
-
[Unreleased]: https://github.com/fr0ster/mcp-abap-connection/compare/
|
|
1123
|
+
[Unreleased]: https://github.com/fr0ster/mcp-abap-connection/compare/v5.0.0...HEAD
|
|
1124
|
+
[5.0.0]: https://github.com/fr0ster/mcp-abap-connection/compare/v4.0.0...v5.0.0
|
|
852
1125
|
[4.0.0]: https://github.com/fr0ster/mcp-abap-connection/compare/v3.0.0...v4.0.0
|
|
853
1126
|
[3.0.0]: https://github.com/fr0ster/mcp-abap-connection/compare/v2.0.0...v3.0.0
|
|
854
1127
|
[2.0.0]: https://github.com/fr0ster/mcp-abap-connection/compare/v1.10.2...v2.0.0
|
package/README.md
CHANGED
|
@@ -17,8 +17,8 @@ ABAP connection layer for MCP ABAP ADT server. Provides a unified interface for
|
|
|
17
17
|
- Session headers management (cookies, CSRF tokens)
|
|
18
18
|
- Session state persistence is handled by `@mcp-abap-adt/auth-broker` package
|
|
19
19
|
- 🏗️ **Clean Architecture**:
|
|
20
|
-
-
|
|
21
|
-
-
|
|
20
|
+
- One connector per SYSTEM (`AdtOnPremConnector`, `AdtCloudConnector`), handed an auth provider
|
|
21
|
+
- Authentication is a parameter, not a subclass — nothing about the system is inferred from it
|
|
22
22
|
- Proper separation of concerns - no JWT logic in base class
|
|
23
23
|
- 🔌 **Realtime Transport Scaffold**:
|
|
24
24
|
- Generic `GenericWebSocketTransport` with pluggable WS factory
|
|
@@ -39,21 +39,31 @@ The package uses a clean separation of concerns:
|
|
|
39
39
|
- CSRF token fetching with retry
|
|
40
40
|
- Auth-agnostic - knows nothing about Basic or JWT
|
|
41
41
|
|
|
42
|
-
- **`
|
|
43
|
-
-
|
|
44
|
-
|
|
45
|
-
-
|
|
46
|
-
|
|
47
|
-
- **`
|
|
48
|
-
-
|
|
49
|
-
|
|
50
|
-
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
42
|
+
- **`AdtOnPremConnector`** (concrete, exported):
|
|
43
|
+
- An on-prem system: the session arrives with the establishing call, and the platform's
|
|
44
|
+
ICF logoff is how it is given back
|
|
45
|
+
- Takes an auth provider — basic, SAML, certificate, a bearer token, whatever you hold
|
|
46
|
+
|
|
47
|
+
- **`AdtCloudConnector`** (concrete, exported):
|
|
48
|
+
- An ABAP Cloud system: a session is a resource, opened at
|
|
49
|
+
`/sap/bc/adt/core/http/sessions` and given back by `DELETE` on the address it publishes
|
|
50
|
+
- Takes an auth provider, same as above
|
|
51
|
+
|
|
52
|
+
**Which one you take is how you say where you are dialling.** Nothing is probed:
|
|
53
|
+
the session resource answers on on-prem too, and its `DELETE` there leaves the
|
|
54
|
+
session open while the logoff removes it — so asking the server would pick the
|
|
55
|
+
mechanism that releases nothing.
|
|
56
|
+
|
|
57
|
+
- **Auth providers** (`BasicAuthProvider`, `TokenAuthProvider`, `SamlAuthProvider`,
|
|
58
|
+
`CertificateAuthProvider`):
|
|
59
|
+
- What a connection authenticates with, passed in
|
|
60
|
+
- A token provider renews on its own; the connector asks it per request and, on a
|
|
61
|
+
`401`, tells it the answer was refused before asking again
|
|
62
|
+
|
|
63
|
+
- **`BaseAbapConnection`, `JwtAbapConnection`, `SamlAbapConnection`,
|
|
64
|
+
`CertificateAbapConnection`, `KerberosAbapConnection`** (deprecated, still exported):
|
|
65
|
+
- The previous shape, where the class stated your credential and the session
|
|
66
|
+
mechanism came with it. See [Migration to 5.0](./docs/MIGRATION-5.0.md)
|
|
57
67
|
|
|
58
68
|
- **`GenericWebSocketTransport`** (concrete, exported):
|
|
59
69
|
- Transport abstraction for realtime WS message flows
|
|
@@ -158,7 +168,9 @@ const logger = {
|
|
|
158
168
|
};
|
|
159
169
|
|
|
160
170
|
// Create connection
|
|
161
|
-
const connection = createAbapConnection(config, logger
|
|
171
|
+
const connection = createAbapConnection(config, logger, undefined, undefined, {
|
|
172
|
+
system: "onprem", // which SYSTEM this is — said, never detected
|
|
173
|
+
});
|
|
162
174
|
await connection.connect(); // required before any request
|
|
163
175
|
|
|
164
176
|
// Make ADT request
|
|
@@ -189,7 +201,9 @@ const logger = {
|
|
|
189
201
|
};
|
|
190
202
|
|
|
191
203
|
// Logger is optional - if not provided, no logging output
|
|
192
|
-
const connection = createAbapConnection(config, logger
|
|
204
|
+
const connection = createAbapConnection(config, logger, undefined, undefined, {
|
|
205
|
+
system: "cloud", // which SYSTEM this is — said, never detected
|
|
206
|
+
});
|
|
193
207
|
await connection.connect();
|
|
194
208
|
|
|
195
209
|
// Note: Token refresh is handled by @mcp-abap-adt/auth-broker package
|
|
@@ -210,7 +224,9 @@ const config: SapConfig = {
|
|
|
210
224
|
sessionCookies: "MYSAPSSO2=...; SAP_SESSIONID=...",
|
|
211
225
|
};
|
|
212
226
|
|
|
213
|
-
const connection = createAbapConnection(config, logger
|
|
227
|
+
const connection = createAbapConnection(config, logger, undefined, undefined, {
|
|
228
|
+
system: "onprem", // which SYSTEM this is — said, never detected
|
|
229
|
+
});
|
|
214
230
|
await connection.connect();
|
|
215
231
|
|
|
216
232
|
const response = await connection.makeAdtRequest({
|
|
@@ -224,7 +240,11 @@ const response = await connection.makeAdtRequest({
|
|
|
224
240
|
For automatic token refresh on **401** errors, inject `ITokenRefresher`:
|
|
225
241
|
|
|
226
242
|
```typescript
|
|
227
|
-
import {
|
|
243
|
+
import {
|
|
244
|
+
AdtCloudConnector,
|
|
245
|
+
TokenAuthProvider,
|
|
246
|
+
SapConfig,
|
|
247
|
+
} from "@mcp-abap-adt/connection";
|
|
228
248
|
import type { ITokenRefresher } from "@mcp-abap-adt/interfaces";
|
|
229
249
|
|
|
230
250
|
// Token refresher provides token acquisition and refresh
|
|
@@ -234,20 +254,26 @@ const tokenRefresher: ITokenRefresher = {
|
|
|
234
254
|
refreshToken: async () => { /* refresh and return new token */ },
|
|
235
255
|
};
|
|
236
256
|
|
|
237
|
-
// JWT configuration
|
|
238
257
|
const config: SapConfig = {
|
|
239
258
|
url: "https://your-instance.abap.cloud.sap",
|
|
240
259
|
authType: "jwt",
|
|
241
|
-
jwtToken: await tokenRefresher.getToken(), // Get initial token
|
|
242
260
|
};
|
|
243
261
|
|
|
244
|
-
//
|
|
245
|
-
|
|
262
|
+
// The connector says which SYSTEM this is; the provider says how to
|
|
263
|
+
// authenticate. Neither decides the other.
|
|
264
|
+
const connection = new AdtCloudConnector(
|
|
265
|
+
config,
|
|
266
|
+
new TokenAuthProvider(tokenRefresher),
|
|
267
|
+
logger,
|
|
268
|
+
);
|
|
246
269
|
await connection.connect();
|
|
247
270
|
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
//
|
|
271
|
+
// On a 401 the connector tells the provider its token was refused, asks again,
|
|
272
|
+
// and only if the answer changed rebuilds the session and retries once. An
|
|
273
|
+
// unchanged answer means the server refused these credentials, and the 401
|
|
274
|
+
// reaches you. A refresh replaces the SAP session, so if a lock window is open
|
|
275
|
+
// the request fails with ADT_SESSION_REPLACED rather than continuing on a
|
|
276
|
+
// session your lock is not in.
|
|
251
277
|
const response = await connection.makeAdtRequest({
|
|
252
278
|
method: "GET",
|
|
253
279
|
url: "/sap/bc/adt/programs/programs/your-program",
|
|
@@ -273,7 +299,9 @@ For operations that require session state (e.g., object modifications), you can
|
|
|
273
299
|
```typescript
|
|
274
300
|
import { createAbapConnection } from "@mcp-abap-adt/connection";
|
|
275
301
|
|
|
276
|
-
const connection = createAbapConnection(config, logger
|
|
302
|
+
const connection = createAbapConnection(config, logger, undefined, undefined, {
|
|
303
|
+
system: "onprem", // which SYSTEM this is — said, never detected
|
|
304
|
+
});
|
|
277
305
|
await connection.connect();
|
|
278
306
|
|
|
279
307
|
// Enable stateful session mode (adds x-sap-adt-sessiontype: stateful header)
|
|
@@ -321,7 +349,9 @@ class MyLogger implements ILogger {
|
|
|
321
349
|
}
|
|
322
350
|
|
|
323
351
|
const logger = new MyLogger();
|
|
324
|
-
const connection = createAbapConnection(config, logger
|
|
352
|
+
const connection = createAbapConnection(config, logger, undefined, undefined, {
|
|
353
|
+
system: "onprem", // which SYSTEM this is — said, never detected
|
|
354
|
+
});
|
|
325
355
|
```
|
|
326
356
|
|
|
327
357
|
## CLI Tool
|
|
@@ -0,0 +1,84 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
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 });
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The credentials a connector can be handed.
|
|
3
|
+
*
|
|
4
|
+
* Each is the authentication half of one of the connection classes that used to
|
|
5
|
+
* carry both halves, lifted out unchanged — the header a `BasicAuthProvider`
|
|
6
|
+
* builds is byte for byte what `BaseAbapConnection` built, and the TLS options a
|
|
7
|
+
* `CertificateAuthProvider` returns are what `CertificateAbapConnection`
|
|
8
|
+
* returned. Nothing about how a credential works changed; only who owns it.
|
|
9
|
+
*/
|
|
10
|
+
import type { AgentOptions } from 'node:https';
|
|
11
|
+
import type { ICertificateMaterialLoader, ISapConfig, ITokenRefresher } from '@mcp-abap-adt/interfaces';
|
|
12
|
+
import type { IAuthProvider } from './IAuthProvider.js';
|
|
13
|
+
/** Username and password, as `Basic base64(user:pass)`. */
|
|
14
|
+
export declare class BasicAuthProvider implements IAuthProvider {
|
|
15
|
+
private readonly username;
|
|
16
|
+
private readonly password;
|
|
17
|
+
readonly kind = "basic";
|
|
18
|
+
constructor(username: string, password: string);
|
|
19
|
+
authorizationHeader(): Promise<string>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A bearer token, kept current by whoever issued it.
|
|
23
|
+
*
|
|
24
|
+
* Takes an `ITokenRefresher` — the contract `@mcp-abap-adt/auth-broker` already
|
|
25
|
+
* produces and `@mcp-abap-adt/auth-providers` already implements twelve ways.
|
|
26
|
+
* This package depends on neither: it speaks the contract, and the consumer
|
|
27
|
+
* brings the implementation, exactly as it does for `IAbapConnection`.
|
|
28
|
+
*
|
|
29
|
+
* **This carries no session recovery.** What happens to a session when the
|
|
30
|
+
* credential behind it is renewed mid-flight is the connection's business and
|
|
31
|
+
* stays there; see `JwtAbapConnection`, which still owns that machinery.
|
|
32
|
+
*/
|
|
33
|
+
export declare class TokenAuthProvider implements IAuthProvider {
|
|
34
|
+
private readonly source;
|
|
35
|
+
readonly kind = "token";
|
|
36
|
+
/**
|
|
37
|
+
* A token, or something that can produce one.
|
|
38
|
+
*
|
|
39
|
+
* A bare string is a token with no renewal behind it — honest, and fine for a
|
|
40
|
+
* short task. An `ITokenRefresher` or a function is a provider that checks
|
|
41
|
+
* expiry and renews on its own, which is where this belongs in a long-lived
|
|
42
|
+
* process.
|
|
43
|
+
*/
|
|
44
|
+
constructor(source: string | ITokenRefresher | (() => Promise<string>));
|
|
45
|
+
/**
|
|
46
|
+
* Asked every time, and nothing kept.
|
|
47
|
+
*
|
|
48
|
+
* The provider behind this already caches the token, knows when it expires,
|
|
49
|
+
* and renews before handing one back. A second cache here would serve the
|
|
50
|
+
* stale one and hide exactly the renewal the provider exists to do — which
|
|
51
|
+
* is what the first version of this class did.
|
|
52
|
+
*/
|
|
53
|
+
authorizationHeader(): Promise<string>;
|
|
54
|
+
/**
|
|
55
|
+
* The token was refused, so force a new one.
|
|
56
|
+
*
|
|
57
|
+
* `getToken()` is documented to return the cached token while it believes it
|
|
58
|
+
* is still valid — which is exactly the situation after a 401 on a token the
|
|
59
|
+
* provider has not yet noticed is dead. `refreshToken()` is the contract's
|
|
60
|
+
* answer for that, and this is the only place it is called.
|
|
61
|
+
*/
|
|
62
|
+
renew(): Promise<void>;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* A SAML session, already negotiated, presented as cookies.
|
|
66
|
+
*
|
|
67
|
+
* No `Authorization` header at all — the cookies are the credential, and they
|
|
68
|
+
* are added by the connection alongside its own.
|
|
69
|
+
*/
|
|
70
|
+
export declare class SamlAuthProvider implements IAuthProvider {
|
|
71
|
+
private readonly sessionCookies;
|
|
72
|
+
readonly kind = "saml";
|
|
73
|
+
constructor(sessionCookies: string);
|
|
74
|
+
authorizationHeader(): Promise<string>;
|
|
75
|
+
/** The cookies to present. */
|
|
76
|
+
cookies(): string;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Client certificate: the credential lives in the TLS handshake.
|
|
80
|
+
*
|
|
81
|
+
* `prepare()` is where the material is read, which is why it exists at all —
|
|
82
|
+
* building an agent before it is loaded is what used to reject a connect
|
|
83
|
+
* before a single request went out.
|
|
84
|
+
*/
|
|
85
|
+
export declare class CertificateAuthProvider implements IAuthProvider {
|
|
86
|
+
private readonly loader;
|
|
87
|
+
private readonly config;
|
|
88
|
+
readonly kind = "certificate";
|
|
89
|
+
private material;
|
|
90
|
+
constructor(loader: ICertificateMaterialLoader, config: ISapConfig);
|
|
91
|
+
prepare(): Promise<void>;
|
|
92
|
+
authorizationHeader(): Promise<string>;
|
|
93
|
+
httpsAgentOptions(): AgentOptions;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=providers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/auth/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAEV,0BAA0B,EAC1B,UAAU,EACV,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,2DAA2D;AAC3D,qBAAa,iBAAkB,YAAW,aAAa;IAInD,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAJ3B,QAAQ,CAAC,IAAI,WAAW;gBAGL,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM;IAG7B,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;CAG7C;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,iBAAkB,YAAW,aAAa;IAYnD,OAAO,CAAC,QAAQ,CAAC,MAAM;IAXzB,QAAQ,CAAC,IAAI,WAAW;IAExB;;;;;;;OAOG;gBAEgB,MAAM,EAAE,MAAM,GAAG,eAAe,GAAG,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAG7E;;;;;;;OAOG;IACG,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;IAU5C;;;;;;;OAOG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ7B;AAED;;;;;GAKG;AACH,qBAAa,gBAAiB,YAAW,aAAa;IAGxC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAF3C,QAAQ,CAAC,IAAI,UAAU;gBAEM,cAAc,EAAE,MAAM;IAE7C,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;IAI5C,8BAA8B;IAC9B,OAAO,IAAI,MAAM;CAGlB;AAED;;;;;;GAMG;AACH,qBAAa,uBAAwB,YAAW,aAAa;IAKzD,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IALzB,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,OAAO,CAAC,QAAQ,CAAqC;gBAGlC,MAAM,EAAE,0BAA0B,EAClC,MAAM,EAAE,UAAU;IAG/B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAMxB,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;IAI5C,iBAAiB,IAAI,YAAY;CASlC"}
|