@mcp-abap-adt/adt-clients 33.0.0 → 34.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/README.md +8 -3
- package/dist/batch/AdtBatchConnection.d.ts.map +1 -1
- package/dist/batch/AdtBatchConnection.js +10 -2
- package/dist/utils/acceptNegotiation.d.ts +11 -0
- package/dist/utils/acceptNegotiation.d.ts.map +1 -1
- package/dist/utils/acceptNegotiation.js +32 -1
- package/docs/usage/BATCH.md +16 -3
- package/docs/usage/MIGRATION-34.md +32 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1021,6 +1021,7 @@ See [Architecture Documentation](docs/architecture/ARCHITECTURE.md#type-system-a
|
|
|
1021
1021
|
One document per breaking release, each written for a consumer on the contract
|
|
1022
1022
|
before it:
|
|
1023
1023
|
|
|
1024
|
+
- **[33.x → 34.0.0](docs/usage/MIGRATION-34.md)** — a batch corrects and resends nothing: a part's `406`/`415` is that call's answer.
|
|
1024
1025
|
- **[32.x → 33.0.0](docs/usage/MIGRATION-33.md)** — a credential the provider refused before SAP was asked rejects with the connection's refusal as it came; a `401` SAP refused it with comes back carrying that response.
|
|
1025
1026
|
- **[31.x → 32.0.0](docs/usage/MIGRATION-32.md)** — interfaces-adt 18, three enhancement subtypes, subtype-specific create fields, two new result slots for enhancement hosts, and `metadataUpdated` for enhancement document writes.
|
|
1026
1027
|
- **[30.x → 31.0.0](docs/usage/MIGRATION-31.md)** — `interfaces-adt` 16 and
|
|
@@ -1156,9 +1157,13 @@ activate all objects with one plain `activateObjectsGroup` call. At a debugger
|
|
|
1156
1157
|
stop, record step + stack + variables on the attached stateful connection.
|
|
1157
1158
|
See [domain and debugger examples](docs/usage/BATCH.md).
|
|
1158
1159
|
|
|
1159
|
-
`execute()` also sends follow-up envelopes for requests
|
|
1160
|
-
|
|
1161
|
-
|
|
1160
|
+
`execute()` also sends follow-up envelopes for requests member continuations
|
|
1161
|
+
record during settlement (up to 100 envelopes, then all remaining requests
|
|
1162
|
+
reject). Nothing in a batch is corrected or sent again: a batch connection is
|
|
1163
|
+
exempt from accept negotiation, so a part's `401`, `406` or `415` is that call's
|
|
1164
|
+
answer, and a `406`/`415` to the envelope reaches `execute()` as it came. The
|
|
1165
|
+
connection's own handling of the envelope request — credential renewal, CSRF
|
|
1166
|
+
recovery, session — stays. Explicit session switches apply to the next recording;
|
|
1162
1167
|
LOCK/UNLOCK run in stateful envelopes; other ordinary members run stateless.
|
|
1163
1168
|
Consecutive LOCKs, consecutive UNLOCKs, and consecutive stateless requests each
|
|
1164
1169
|
form separate envelopes sent in queue order.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdtBatchConnection.d.ts","sourceRoot":"","sources":["../../src/batch/AdtBatchConnection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,yCAAyC,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"AdtBatchConnection.d.ts","sourceRoot":"","sources":["../../src/batch/AdtBatchConnection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,yCAAyC,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAS9D,KAAK,OAAO,GAAG,UAAU,GAAG,WAAW,CAAC;AAQxC,sFAAsF;AACtF,qBAAa,kBAAmB,YAAW,eAAe;IAOtD,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAP1B,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAU;IACzC,OAAO,CAAC,iBAAiB,CAAC,CAAqB;IAC/C,OAAO,CAAC,SAAS,CAAS;gBAEP,UAAU,EAAE,eAAe,EAC3B,OAAO,EAAE;QACxB,QAAQ,EAAE,eAAe,GAAG,UAAU,CAAC;QACvC,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB;IAWH,OAAO,CAAC,cAAc;IAWtB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAGxB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAG7B,YAAY,IAAI,MAAM,GAAG,IAAI;IAG7B,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAGnC,cAAc,IAAI,OAAO;IAGzB,cAAc,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,EACrC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAuBlC,OAAO,CAAC,WAAW;IAkBnB,6EAA6E;IACvE,OAAO,IAAI,OAAO,CAAC,gBAAgB,CAAC;CAiG3C"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.AdtBatchConnection = void 0;
|
|
4
4
|
const objects_1 = require("../endpoints/objects");
|
|
5
|
+
const acceptNegotiation_1 = require("../utils/acceptNegotiation");
|
|
5
6
|
const adtResponse_1 = require("../utils/adtResponse");
|
|
6
7
|
const wire_1 = require("./wire");
|
|
7
8
|
/** Records member requests; execute also drains requests queued during settlement. */
|
|
@@ -21,6 +22,9 @@ class AdtBatchConnection {
|
|
|
21
22
|
this.defaultSession =
|
|
22
23
|
options.endpoint === 'debugger' ? 'stateful' : 'stateless';
|
|
23
24
|
this.session = this.defaultSession;
|
|
25
|
+
// What SAP answers to a recorded request is the caller's: no member's
|
|
26
|
+
// accept negotiation corrects or resends through this connection.
|
|
27
|
+
(0, acceptNegotiation_1.exemptFromAcceptNegotiation)(this);
|
|
24
28
|
}
|
|
25
29
|
wrappedSession() {
|
|
26
30
|
const connection = this.connection;
|
|
@@ -103,7 +107,11 @@ class AdtBatchConnection {
|
|
|
103
107
|
endpoint: this.options.endpoint,
|
|
104
108
|
parts: active.length,
|
|
105
109
|
});
|
|
106
|
-
|
|
110
|
+
// Not through accept negotiation: when an `AdtClient` wrapped the
|
|
111
|
+
// connection, it would answer a 406/415 to the envelope by sending it
|
|
112
|
+
// again. A batch is the caller's, and so is what SAP answered to it.
|
|
113
|
+
// The connection's own handling (credential, CSRF, session) stays.
|
|
114
|
+
response = await (0, acceptNegotiation_1.getBaseRequest)(this.connection)({
|
|
107
115
|
url: objects_1.BATCH[this.options.endpoint],
|
|
108
116
|
method: 'POST',
|
|
109
117
|
timeout: 0,
|
|
@@ -126,7 +134,7 @@ class AdtBatchConnection {
|
|
|
126
134
|
if (parts.length !== active.length)
|
|
127
135
|
throw new Error(`ADT batch response part count mismatch: expected ${active.length}, received ${parts.length}`);
|
|
128
136
|
active = [];
|
|
129
|
-
// Let
|
|
137
|
+
// Let member continuations record their follow-up calls.
|
|
130
138
|
await new Promise((resolve) => setImmediate(resolve));
|
|
131
139
|
pending.push(...this.queue.splice(0));
|
|
132
140
|
if (!pending.length)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { IAbapConnection, IAbapRequestOptions, IAdtWireResponse } from '@mcp-abap-adt/interfaces-adt-connection';
|
|
2
2
|
import type { ILogger } from '@mcp-abap-adt/interfaces-utils';
|
|
3
|
+
/** Mark a connection so accept negotiation never corrects or resends through it. */
|
|
4
|
+
export declare function exemptFromAcceptNegotiation(connection: IAbapConnection): void;
|
|
3
5
|
export interface IAcceptNegotiationOptions {
|
|
4
6
|
enableAcceptCorrection?: boolean;
|
|
5
7
|
logger?: ILogger;
|
|
@@ -12,6 +14,15 @@ export declare function setAcceptCorrectionEnabled(connection: IAbapConnection,
|
|
|
12
14
|
export declare function getAcceptCorrectionEnabled(connection: IAbapConnection): boolean;
|
|
13
15
|
export declare function extractSupportedAccept(error: unknown): string[];
|
|
14
16
|
export declare function extractSupportedContentType(error: unknown): string[];
|
|
17
|
+
/**
|
|
18
|
+
* The connection's request as it was before an `AdtClient` with correction on
|
|
19
|
+
* wrapped it: accept negotiation corrects and resends nothing. The
|
|
20
|
+
* connection's own handling (credential, CSRF, session) is untouched.
|
|
21
|
+
*
|
|
22
|
+
* Exported for the batch connection: what SAP answers to an envelope is the
|
|
23
|
+
* caller's to read.
|
|
24
|
+
*/
|
|
25
|
+
export declare function getBaseRequest(connection: IAbapConnection): IAbapConnection['makeAdtRequest'];
|
|
15
26
|
export declare function wrapConnectionAcceptNegotiation(connection: IAbapConnection, logger?: ILogger): void;
|
|
16
27
|
export declare function makeAdtRequestWithAcceptNegotiation<T = unknown, D = unknown>(connection: IAbapConnection, request: IAbapRequestOptions, options?: IAcceptNegotiationOptions): Promise<IAdtWireResponse<T, D>>;
|
|
17
28
|
//# sourceMappingURL=acceptNegotiation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"acceptNegotiation.d.ts","sourceRoot":"","sources":["../../src/utils/acceptNegotiation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,yCAAyC,CAAC;AAEjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"acceptNegotiation.d.ts","sourceRoot":"","sources":["../../src/utils/acceptNegotiation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,yCAAyC,CAAC;AAEjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAkD9D,oFAAoF;AACpF,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,eAAe,GAAG,IAAI,CAM7E;AAaD,MAAM,WAAW,yBAAyB;IACxC,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,2CAA2C;AAC3C,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,eAAe,GAAG,IAAI,CAIlE;AAED,6DAA6D;AAC7D,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,eAAe,EAC3B,OAAO,CAAC,EAAE,OAAO,GAChB,IAAI,CAEN;AAED,wEAAwE;AACxE,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,eAAe,GAC1B,OAAO,CAIT;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CAoC/D;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CAsCpE;AAMD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,eAAe,GAC1B,eAAe,CAAC,gBAAgB,CAAC,CAInC;AAED,wBAAgB,+BAA+B,CAC7C,UAAU,EAAE,eAAe,EAC3B,MAAM,CAAC,EAAE,OAAO,GACf,IAAI,CAkBN;AAED,wBAAsB,mCAAmC,CACvD,CAAC,GAAG,OAAO,EACX,CAAC,GAAG,OAAO,EAEX,UAAU,EAAE,eAAe,EAC3B,OAAO,EAAE,mBAAmB,EAC5B,OAAO,CAAC,EAAE,yBAAyB,GAClC,OAAO,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAkFjC"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.exemptFromAcceptNegotiation = exemptFromAcceptNegotiation;
|
|
3
4
|
exports.clearAcceptCache = clearAcceptCache;
|
|
4
5
|
exports.setAcceptCorrectionEnabled = setAcceptCorrectionEnabled;
|
|
5
6
|
exports.getAcceptCorrectionEnabled = getAcceptCorrectionEnabled;
|
|
6
7
|
exports.extractSupportedAccept = extractSupportedAccept;
|
|
7
8
|
exports.extractSupportedContentType = extractSupportedContentType;
|
|
9
|
+
exports.getBaseRequest = getBaseRequest;
|
|
8
10
|
exports.wrapConnectionAcceptNegotiation = wrapConnectionAcceptNegotiation;
|
|
9
11
|
exports.makeAdtRequestWithAcceptNegotiation = makeAdtRequestWithAcceptNegotiation;
|
|
10
12
|
const STATE = Symbol.for('@mcp-abap-adt/adt-clients/acceptNegotiation');
|
|
@@ -21,6 +23,24 @@ function stateOf(connection) {
|
|
|
21
23
|
}
|
|
22
24
|
return state;
|
|
23
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* The mark of a connection accept negotiation never touches: a recording batch
|
|
28
|
+
* connection. What SAP answers to a recorded request — a `406`/`415` included —
|
|
29
|
+
* is the batch caller's to read, so nothing is corrected, cached or sent again,
|
|
30
|
+
* whatever switch an `AdtClient` built over it was given.
|
|
31
|
+
*/
|
|
32
|
+
const NO_NEGOTIATION = Symbol.for('@mcp-abap-adt/adt-clients/acceptNegotiation/none');
|
|
33
|
+
/** Mark a connection so accept negotiation never corrects or resends through it. */
|
|
34
|
+
function exemptFromAcceptNegotiation(connection) {
|
|
35
|
+
Object.defineProperty(connection, NO_NEGOTIATION, {
|
|
36
|
+
value: true,
|
|
37
|
+
enumerable: false,
|
|
38
|
+
configurable: false,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function isExempt(connection) {
|
|
42
|
+
return (connection[NO_NEGOTIATION] === true);
|
|
43
|
+
}
|
|
24
44
|
const baseRequestMap = new WeakMap();
|
|
25
45
|
/** Forget what this connection learned. */
|
|
26
46
|
function clearAcceptCache(connection) {
|
|
@@ -107,11 +127,19 @@ function extractSupportedContentType(error) {
|
|
|
107
127
|
function buildCacheKey(request) {
|
|
108
128
|
return `${request.method.toUpperCase()} ${request.url}`;
|
|
109
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* The connection's request as it was before an `AdtClient` with correction on
|
|
132
|
+
* wrapped it: accept negotiation corrects and resends nothing. The
|
|
133
|
+
* connection's own handling (credential, CSRF, session) is untouched.
|
|
134
|
+
*
|
|
135
|
+
* Exported for the batch connection: what SAP answers to an envelope is the
|
|
136
|
+
* caller's to read.
|
|
137
|
+
*/
|
|
110
138
|
function getBaseRequest(connection) {
|
|
111
139
|
return (baseRequestMap.get(connection) ?? connection.makeAdtRequest.bind(connection));
|
|
112
140
|
}
|
|
113
141
|
function wrapConnectionAcceptNegotiation(connection, logger) {
|
|
114
|
-
if (baseRequestMap.has(connection)) {
|
|
142
|
+
if (baseRequestMap.has(connection) || isExempt(connection)) {
|
|
115
143
|
return;
|
|
116
144
|
}
|
|
117
145
|
const baseRequest = connection.makeAdtRequest.bind(connection);
|
|
@@ -121,6 +149,9 @@ function wrapConnectionAcceptNegotiation(connection, logger) {
|
|
|
121
149
|
};
|
|
122
150
|
}
|
|
123
151
|
async function makeAdtRequestWithAcceptNegotiation(connection, request, options) {
|
|
152
|
+
if (isExempt(connection)) {
|
|
153
|
+
return getBaseRequest(connection)(request);
|
|
154
|
+
}
|
|
124
155
|
const enableCorrection = options?.enableAcceptCorrection ?? getAcceptCorrectionEnabled(connection);
|
|
125
156
|
const { accept: acceptCache, contentType: contentTypeCache } = stateOf(connection);
|
|
126
157
|
const logger = options?.logger;
|
package/docs/usage/BATCH.md
CHANGED
|
@@ -73,6 +73,19 @@ Use the real handles and inspect activation messages, including `type="E"`.
|
|
|
73
73
|
The transport provides no transaction or rollback; callers own recovery and
|
|
74
74
|
cleanup after partial failures.
|
|
75
75
|
|
|
76
|
+
Accept negotiation never corrects or resends an envelope or its parts. A batch
|
|
77
|
+
connection is exempt from it: an `AdtClient` built over one does not wrap it,
|
|
78
|
+
whatever `enableAcceptCorrection` it is given, and a member that negotiates by
|
|
79
|
+
itself sends through it once. On a connection an `AdtClient` wrapped with
|
|
80
|
+
correction on, a `406` or `415` answered to the envelope reaches `execute()` and
|
|
81
|
+
every part of that envelope as it came. A part's own `401`, `406` or `415` is
|
|
82
|
+
that part's answer like any other status; nothing reads it, corrects it or
|
|
83
|
+
sends it again. A batch is yours, and so is
|
|
84
|
+
what SAP answered to each of its parts. The envelope request itself still goes
|
|
85
|
+
through the connection's own handling — credential renewal, CSRF recovery and
|
|
86
|
+
session — as every request does: that is about the connection to the endpoint,
|
|
87
|
+
not about what the parts answered.
|
|
88
|
+
|
|
76
89
|
At an attached debugger stop, use the attached connection and its stateful session:
|
|
77
90
|
|
|
78
91
|
```typescript
|
|
@@ -103,8 +116,8 @@ parts in the failed envelope. Unsent runs and queued follow-ups reject with a
|
|
|
103
116
|
library error saying the request was not sent because an earlier envelope failed;
|
|
104
117
|
that error carries the cause, without a SAP response. Missing parts reject with a part-count error. A count
|
|
105
118
|
mismatch also rejects `execute()`. Attach rejection handlers before execution when
|
|
106
|
-
using raw connection promises. Each execute sends follow-up envelopes for requests recorded during settlement
|
|
107
|
-
|
|
119
|
+
using raw connection promises. Each execute sends follow-up envelopes for requests recorded during settlement
|
|
120
|
+
by member continuations; accept negotiation records none. It yields one event-loop turn
|
|
108
121
|
after settling each envelope to let member continuations record requests. It
|
|
109
122
|
returns the last outer response once that queue is empty. A limit of 100 envelopes
|
|
110
123
|
rejects execution and all remaining requests rather than looping forever.
|
|
@@ -121,7 +134,7 @@ For ordinary client members, LOCK and UNLOCK run stateful; creates, writes, read
|
|
|
121
134
|
and deletes run stateless. Group creates before locks, and writes before unlocks,
|
|
122
135
|
to avoid one envelope per alternating request. One execute can send several
|
|
123
136
|
envelopes and provides no transaction across them. Inner HTTP failures remain
|
|
124
|
-
per-part failures and do not stop later runs
|
|
137
|
+
per-part failures and do not stop later runs.
|
|
125
138
|
|
|
126
139
|
Stateful parts carry `X-sap-adt-sessiontype: stateful`. The wrapped session mode
|
|
127
140
|
is restored afterward. Connections exposing `getSessionMode()` or
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Migrating to 34.0.0
|
|
2
|
+
|
|
3
|
+
34.0.0 changes no type and no dependency range. It changes what a batch does
|
|
4
|
+
with a `406` or `415`.
|
|
5
|
+
|
|
6
|
+
## A batch corrects and resends nothing
|
|
7
|
+
|
|
8
|
+
Until 33.x, a member recorded through `AdtBatchConnection` kept accept
|
|
9
|
+
negotiation: a part SAP answered `406` (its `Accept` not served) or `415` (its
|
|
10
|
+
`Content-Type` not accepted) was corrected from the supported types SAP named
|
|
11
|
+
and recorded again, and `execute()` sent it in a follow-up envelope. The call
|
|
12
|
+
resolved with the corrected request's answer, and SAP's `406`/`415` was gone.
|
|
13
|
+
|
|
14
|
+
Now a batch connection is exempt from accept negotiation:
|
|
15
|
+
|
|
16
|
+
- a part's `406` or `415` is that call's answer, a failure carrying SAP's
|
|
17
|
+
response, like any other status;
|
|
18
|
+
- an `AdtClient` built over a batch connection does not wrap it, whatever
|
|
19
|
+
`enableAcceptCorrection` it is given, and a member that negotiates by itself
|
|
20
|
+
sends through it once;
|
|
21
|
+
- a `406`/`415` answered to the envelope itself, on a connection an `AdtClient`
|
|
22
|
+
wrapped with correction on, reaches `execute()` and the envelope's parts as it
|
|
23
|
+
came; the envelope is not sent again.
|
|
24
|
+
|
|
25
|
+
A batch is yours: read each answer and decide what to send again, in a batch of
|
|
26
|
+
your own. The supported types are in the failure's `response` (headers and
|
|
27
|
+
body), where accept negotiation used to read them.
|
|
28
|
+
|
|
29
|
+
The connection's own handling of the envelope request — credential renewal,
|
|
30
|
+
CSRF recovery, session — is unchanged.
|
|
31
|
+
|
|
32
|
+
Outside a batch nothing changes: accept negotiation works as before.
|