@mcp-abap-adt/adt-clients 33.0.0 → 34.1.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)
package/dist/index.d.ts CHANGED
@@ -26,4 +26,5 @@ export * from './index.executors';
26
26
  export * from './index.readings';
27
27
  export * from './index.runtime';
28
28
  export * from './index.ws';
29
+ export { exemptFromAcceptNegotiation } from './utils/acceptNegotiation';
29
30
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACxD,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACxD,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC"}
package/dist/index.js CHANGED
@@ -34,7 +34,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
34
34
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
35
35
  };
36
36
  Object.defineProperty(exports, "__esModule", { value: true });
37
- exports.CT_INCLUDE = exports.AdtInclude = exports.AdtBatchConnection = void 0;
37
+ exports.exemptFromAcceptNegotiation = exports.CT_INCLUDE = exports.AdtInclude = exports.AdtBatchConnection = void 0;
38
38
  var batch_1 = require("./batch");
39
39
  Object.defineProperty(exports, "AdtBatchConnection", { enumerable: true, get: function () { return batch_1.AdtBatchConnection; } });
40
40
  var include_1 = require("./core/include");
@@ -46,3 +46,5 @@ __exportStar(require("./index.executors"), exports);
46
46
  __exportStar(require("./index.readings"), exports);
47
47
  __exportStar(require("./index.runtime"), exports);
48
48
  __exportStar(require("./index.ws"), exports);
49
+ var acceptNegotiation_1 = require("./utils/acceptNegotiation");
50
+ Object.defineProperty(exports, "exemptFromAcceptNegotiation", { enumerable: true, get: function () { return acceptNegotiation_1.exemptFromAcceptNegotiation; } });
@@ -1,5 +1,14 @@
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
+ /**
4
+ * Mark a connection so accept negotiation never corrects or resends through it.
5
+ *
6
+ * Public for a consumer that hands members its own connection over an
7
+ * `AdtBatchConnection` — a per-call wrapper, say: an `AdtBatchConnection` marks
8
+ * itself, but a different object is not it, and is negotiated like any other
9
+ * connection unless it is marked too. The mark is permanent; there is no unmark.
10
+ */
11
+ export declare function exemptFromAcceptNegotiation(connection: IAbapConnection): void;
3
12
  export interface IAcceptNegotiationOptions {
4
13
  enableAcceptCorrection?: boolean;
5
14
  logger?: ILogger;
@@ -12,6 +21,15 @@ export declare function setAcceptCorrectionEnabled(connection: IAbapConnection,
12
21
  export declare function getAcceptCorrectionEnabled(connection: IAbapConnection): boolean;
13
22
  export declare function extractSupportedAccept(error: unknown): string[];
14
23
  export declare function extractSupportedContentType(error: unknown): string[];
24
+ /**
25
+ * The connection's request as it was before an `AdtClient` with correction on
26
+ * wrapped it: accept negotiation corrects and resends nothing. The
27
+ * connection's own handling (credential, CSRF, session) is untouched.
28
+ *
29
+ * Exported for the batch connection: what SAP answers to an envelope is the
30
+ * caller's to read.
31
+ */
32
+ export declare function getBaseRequest(connection: IAbapConnection): IAbapConnection['makeAdtRequest'];
15
33
  export declare function wrapConnectionAcceptNegotiation(connection: IAbapConnection, logger?: ILogger): void;
16
34
  export declare function makeAdtRequestWithAcceptNegotiation<T = unknown, D = unknown>(connection: IAbapConnection, request: IAbapRequestOptions, options?: IAcceptNegotiationOptions): Promise<IAdtWireResponse<T, D>>;
17
35
  //# 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;;;;;;;GAOG;AACH,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,31 @@ 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
+ /**
34
+ * Mark a connection so accept negotiation never corrects or resends through it.
35
+ *
36
+ * Public for a consumer that hands members its own connection over an
37
+ * `AdtBatchConnection` — a per-call wrapper, say: an `AdtBatchConnection` marks
38
+ * itself, but a different object is not it, and is negotiated like any other
39
+ * connection unless it is marked too. The mark is permanent; there is no unmark.
40
+ */
41
+ function exemptFromAcceptNegotiation(connection) {
42
+ Object.defineProperty(connection, NO_NEGOTIATION, {
43
+ value: true,
44
+ enumerable: false,
45
+ configurable: false,
46
+ });
47
+ }
48
+ function isExempt(connection) {
49
+ return (connection[NO_NEGOTIATION] === true);
50
+ }
24
51
  const baseRequestMap = new WeakMap();
25
52
  /** Forget what this connection learned. */
26
53
  function clearAcceptCache(connection) {
@@ -107,11 +134,19 @@ function extractSupportedContentType(error) {
107
134
  function buildCacheKey(request) {
108
135
  return `${request.method.toUpperCase()} ${request.url}`;
109
136
  }
137
+ /**
138
+ * The connection's request as it was before an `AdtClient` with correction on
139
+ * wrapped it: accept negotiation corrects and resends nothing. The
140
+ * connection's own handling (credential, CSRF, session) is untouched.
141
+ *
142
+ * Exported for the batch connection: what SAP answers to an envelope is the
143
+ * caller's to read.
144
+ */
110
145
  function getBaseRequest(connection) {
111
146
  return (baseRequestMap.get(connection) ?? connection.makeAdtRequest.bind(connection));
112
147
  }
113
148
  function wrapConnectionAcceptNegotiation(connection, logger) {
114
- if (baseRequestMap.has(connection)) {
149
+ if (baseRequestMap.has(connection) || isExempt(connection)) {
115
150
  return;
116
151
  }
117
152
  const baseRequest = connection.makeAdtRequest.bind(connection);
@@ -121,6 +156,9 @@ function wrapConnectionAcceptNegotiation(connection, logger) {
121
156
  };
122
157
  }
123
158
  async function makeAdtRequestWithAcceptNegotiation(connection, request, options) {
159
+ if (isExempt(connection)) {
160
+ return getBaseRequest(connection)(request);
161
+ }
124
162
  const enableCorrection = options?.enableAcceptCorrection ?? getAcceptCorrectionEnabled(connection);
125
163
  const { accept: acceptCache, contentType: contentTypeCache } = stateOf(connection);
126
164
  const logger = options?.logger;
@@ -73,6 +73,22 @@ 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 connection of your own that members send through instead of
84
+ the batch connection — a per-call wrapper over it, say — is a different object
85
+ and is negotiated like any other; mark it with `exemptFromAcceptNegotiation(wrapper)`
86
+ (exported by the package) and it is exempt too. A batch is yours, and so is
87
+ what SAP answered to each of its parts. The envelope request itself still goes
88
+ through the connection's own handling — credential renewal, CSRF recovery and
89
+ session — as every request does: that is about the connection to the endpoint,
90
+ not about what the parts answered.
91
+
76
92
  At an attached debugger stop, use the attached connection and its stateful session:
77
93
 
78
94
  ```typescript
@@ -103,8 +119,8 @@ parts in the failed envelope. Unsent runs and queued follow-ups reject with a
103
119
  library error saying the request was not sent because an earlier envelope failed;
104
120
  that error carries the cause, without a SAP response. Missing parts reject with a part-count error. A count
105
121
  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
122
+ using raw connection promises. Each execute sends follow-up envelopes for requests recorded during settlement
123
+ by member continuations; accept negotiation records none. It yields one event-loop turn
108
124
  after settling each envelope to let member continuations record requests. It
109
125
  returns the last outer response once that queue is empty. A limit of 100 envelopes
110
126
  rejects execution and all remaining requests rather than looping forever.
@@ -121,7 +137,7 @@ For ordinary client members, LOCK and UNLOCK run stateful; creates, writes, read
121
137
  and deletes run stateless. Group creates before locks, and writes before unlocks,
122
138
  to avoid one envelope per alternating request. One execute can send several
123
139
  envelopes and provides no transaction across them. Inner HTTP failures remain
124
- per-part failures and do not stop later runs, allowing negotiation retries.
140
+ per-part failures and do not stop later runs.
125
141
 
126
142
  Stateful parts carry `X-sap-adt-sessiontype: stateful`. The wrapped session mode
127
143
  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.1.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",