@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 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 recorded during settlement,
1160
- including automatic 406/415 negotiation retries (up to 100 envelopes, then all
1161
- remaining requests reject). Explicit session switches apply to the next recording;
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;AAK9D,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;IAQH,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;CA6F3C"}
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
- response = await this.connection.makeAdtRequest({
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 negotiation and member continuations record their follow-up calls.
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;AA6C9D,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;AAcD,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,CA+EjC"}
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;
@@ -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
- including the automatic 406/415 corrected retry. It yields one event-loop turn
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, allowing negotiation retries.
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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-abap-adt/adt-clients",
3
- "version": "33.0.0",
3
+ "version": "34.0.0",
4
4
  "description": "ADT clients for SAP ABAP systems - AdtClient and AdtRuntimeClient",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",