@mcp-abap-adt/adt-clients 34.2.0 → 35.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 +12 -3
- package/dist/batch/AdtBatchConnection.d.ts.map +1 -1
- package/dist/batch/AdtBatchConnection.js +20 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/utils/acceptNegotiation.d.ts +19 -1
- package/dist/utils/acceptNegotiation.d.ts.map +1 -1
- package/dist/utils/acceptNegotiation.js +26 -2
- package/dist/utils/requestTrace.d.ts +6 -0
- package/dist/utils/requestTrace.d.ts.map +1 -1
- package/dist/utils/requestTrace.js +30 -2
- package/docs/usage/BATCH.md +30 -4
- package/docs/usage/CLIENT_API_REFERENCE.md +4 -1
- package/docs/usage/MIGRATION-35.md +33 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -834,20 +834,28 @@ Some ADT endpoints return `406` when the `Accept` header does not match the
|
|
|
834
834
|
system's supported media types. The client retries once with a type the `406`
|
|
835
835
|
names, and remembers it for that endpoint.
|
|
836
836
|
|
|
837
|
-
**It is
|
|
837
|
+
**It is off unless you turn it on** (since 35.0.0) — per client, or for the
|
|
838
|
+
process. Without a switch a `406` or `415` is the call's answer and nothing is
|
|
839
|
+
sent again:
|
|
838
840
|
|
|
839
841
|
```typescript
|
|
840
842
|
import { AdtClient } from '@mcp-abap-adt/adt-clients';
|
|
841
843
|
|
|
842
844
|
const client = new AdtClient(connection, console, {
|
|
843
|
-
enableAcceptCorrection:
|
|
845
|
+
enableAcceptCorrection: true,
|
|
844
846
|
});
|
|
845
847
|
```
|
|
846
848
|
|
|
847
849
|
```bash
|
|
848
|
-
ADT_ACCEPT_CORRECTION=
|
|
850
|
+
ADT_ACCEPT_CORRECTION=true npm test
|
|
849
851
|
```
|
|
850
852
|
|
|
853
|
+
The variable turns it on only when it is exactly `true`. To correct requests
|
|
854
|
+
yourself instead, read a `406` with `extractSupportedAccept(error)` and keep
|
|
855
|
+
the result in the connection's cache with `rememberAccept(connection, request,
|
|
856
|
+
accept)`; `cachedAccept(connection, request)` reads it back, whatever the
|
|
857
|
+
switch says. See [batch](docs/usage/BATCH.md).
|
|
858
|
+
|
|
851
859
|
**The state is the connection's** since 23.0.0: the remembered types and the
|
|
852
860
|
switch live on the connection object. They used to be module globals, so a
|
|
853
861
|
header learned on one system was sent to every other, and one client's switch
|
|
@@ -1021,6 +1029,7 @@ See [Architecture Documentation](docs/architecture/ARCHITECTURE.md#type-system-a
|
|
|
1021
1029
|
One document per breaking release, each written for a consumer on the contract
|
|
1022
1030
|
before it:
|
|
1023
1031
|
|
|
1032
|
+
- **[34.x → 35.0.0](docs/usage/MIGRATION-35.md)** — accept negotiation is off by default: a `406`/`415` is the call's answer unless you switch it on.
|
|
1024
1033
|
- **[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.
|
|
1025
1034
|
- **[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.
|
|
1026
1035
|
- **[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.
|
|
@@ -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;AAU9D,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;CAmH3C"}
|
|
@@ -4,6 +4,7 @@ exports.AdtBatchConnection = void 0;
|
|
|
4
4
|
const objects_1 = require("../endpoints/objects");
|
|
5
5
|
const acceptNegotiation_1 = require("../utils/acceptNegotiation");
|
|
6
6
|
const adtResponse_1 = require("../utils/adtResponse");
|
|
7
|
+
const requestTrace_1 = require("../utils/requestTrace");
|
|
7
8
|
const wire_1 = require("./wire");
|
|
8
9
|
/** Records member requests; execute also drains requests queued during settlement. */
|
|
9
10
|
class AdtBatchConnection {
|
|
@@ -149,6 +150,25 @@ class AdtBatchConnection {
|
|
|
149
150
|
const unsentError = (0, adtResponse_1.isUnansweredCredentialRefusal)(error)
|
|
150
151
|
? error
|
|
151
152
|
: new Error('ADT batch request not sent because an earlier batch envelope failed', { cause: error });
|
|
153
|
+
// The envelope failed as a whole: every part it carried rejects with
|
|
154
|
+
// this one object. The request that failed is the envelope's own POST,
|
|
155
|
+
// not any part — and no part's trace may write its own over it.
|
|
156
|
+
// Marked first: the mark cannot fail. The request is written only where
|
|
157
|
+
// the failure takes it — a frozen one does not, and the parts settle
|
|
158
|
+
// with it as it came either way.
|
|
159
|
+
if (active.length && !(0, adtResponse_1.isUnansweredCredentialRefusal)(error)) {
|
|
160
|
+
(0, requestTrace_1.markEnvelopeFailure)(error);
|
|
161
|
+
if (error !== null && typeof error === 'object')
|
|
162
|
+
Reflect.defineProperty(error, 'request', {
|
|
163
|
+
value: { method: 'POST', url: objects_1.BATCH[this.options.endpoint] },
|
|
164
|
+
writable: true,
|
|
165
|
+
enumerable: true,
|
|
166
|
+
configurable: true,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
// The "not sent" failure is one object shared by every unsent part, too.
|
|
170
|
+
if (unsentError !== error)
|
|
171
|
+
(0, requestTrace_1.markEnvelopeFailure)(unsentError);
|
|
152
172
|
this.settlementFailure = { error: unsentError };
|
|
153
173
|
for (const part of active)
|
|
154
174
|
part.reject(error);
|
package/dist/index.d.ts
CHANGED
|
@@ -26,5 +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, getBaseRequest, } from './utils/acceptNegotiation';
|
|
29
|
+
export { cachedAccept, exemptFromAcceptNegotiation, extractSupportedAccept, getBaseRequest, rememberAccept, } from './utils/acceptNegotiation';
|
|
30
30
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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;AAC3B,OAAO,EACL,2BAA2B,EAC3B,cAAc,GACf,MAAM,2BAA2B,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,EACL,YAAY,EACZ,2BAA2B,EAC3B,sBAAsB,EACtB,cAAc,EACd,cAAc,GACf,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.getBaseRequest = exports.exemptFromAcceptNegotiation = exports.CT_INCLUDE = exports.AdtInclude = exports.AdtBatchConnection = void 0;
|
|
37
|
+
exports.rememberAccept = exports.getBaseRequest = exports.extractSupportedAccept = exports.exemptFromAcceptNegotiation = exports.cachedAccept = 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");
|
|
@@ -47,5 +47,8 @@ __exportStar(require("./index.readings"), exports);
|
|
|
47
47
|
__exportStar(require("./index.runtime"), exports);
|
|
48
48
|
__exportStar(require("./index.ws"), exports);
|
|
49
49
|
var acceptNegotiation_1 = require("./utils/acceptNegotiation");
|
|
50
|
+
Object.defineProperty(exports, "cachedAccept", { enumerable: true, get: function () { return acceptNegotiation_1.cachedAccept; } });
|
|
50
51
|
Object.defineProperty(exports, "exemptFromAcceptNegotiation", { enumerable: true, get: function () { return acceptNegotiation_1.exemptFromAcceptNegotiation; } });
|
|
52
|
+
Object.defineProperty(exports, "extractSupportedAccept", { enumerable: true, get: function () { return acceptNegotiation_1.extractSupportedAccept; } });
|
|
51
53
|
Object.defineProperty(exports, "getBaseRequest", { enumerable: true, get: function () { return acceptNegotiation_1.getBaseRequest; } });
|
|
54
|
+
Object.defineProperty(exports, "rememberAccept", { enumerable: true, get: function () { return acceptNegotiation_1.rememberAccept; } });
|
|
@@ -17,10 +17,28 @@ export interface IAcceptNegotiationOptions {
|
|
|
17
17
|
export declare function clearAcceptCache(connection: IAbapConnection): void;
|
|
18
18
|
/** Switch correction on or off for this connection alone. */
|
|
19
19
|
export declare function setAcceptCorrectionEnabled(connection: IAbapConnection, enabled?: boolean): void;
|
|
20
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* This connection's switch, else the `ADT_ACCEPT_CORRECTION` default. Off
|
|
22
|
+
* unless explicitly on: the environment variable turns it on only when it is
|
|
23
|
+
* exactly `true`; unset, or any other value, leaves it off.
|
|
24
|
+
*/
|
|
21
25
|
export declare function getAcceptCorrectionEnabled(connection: IAbapConnection): boolean;
|
|
22
26
|
export declare function extractSupportedAccept(error: unknown): string[];
|
|
23
27
|
export declare function extractSupportedContentType(error: unknown): string[];
|
|
28
|
+
/**
|
|
29
|
+
* The Accept stored for `request`'s method and URL on this connection: what a
|
|
30
|
+
* `406` taught negotiation or `rememberAccept` stored, or `undefined` when
|
|
31
|
+
* there is none. A plain read of the per-connection cache, whatever the
|
|
32
|
+
* correction switch says, so a consumer that corrects requests itself can read
|
|
33
|
+
* it while negotiation is off.
|
|
34
|
+
*/
|
|
35
|
+
export declare function cachedAccept(connection: IAbapConnection, request: IAbapRequestOptions): string | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Store a corrected Accept for `request`'s method and URL on this connection,
|
|
38
|
+
* as the negotiation's own `406` branch does: a later request through the
|
|
39
|
+
* connection's negotiation sends it. A plain write of the per-connection cache.
|
|
40
|
+
*/
|
|
41
|
+
export declare function rememberAccept(connection: IAbapConnection, request: IAbapRequestOptions, accept: string): void;
|
|
24
42
|
/**
|
|
25
43
|
* The connection's request as it was before an `AdtClient` with correction on
|
|
26
44
|
* wrapped it: accept negotiation corrects and resends nothing. The
|
|
@@ -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;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
|
|
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;;;;GAIG;AACH,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;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,eAAe,EAC3B,OAAO,EAAE,mBAAmB,GAC3B,MAAM,GAAG,SAAS,CAEpB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,eAAe,EAC3B,OAAO,EAAE,mBAAmB,EAC5B,MAAM,EAAE,MAAM,GACb,IAAI,CAEN;AAED;;;;;;;;;GASG;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"}
|
|
@@ -6,6 +6,8 @@ exports.setAcceptCorrectionEnabled = setAcceptCorrectionEnabled;
|
|
|
6
6
|
exports.getAcceptCorrectionEnabled = getAcceptCorrectionEnabled;
|
|
7
7
|
exports.extractSupportedAccept = extractSupportedAccept;
|
|
8
8
|
exports.extractSupportedContentType = extractSupportedContentType;
|
|
9
|
+
exports.cachedAccept = cachedAccept;
|
|
10
|
+
exports.rememberAccept = rememberAccept;
|
|
9
11
|
exports.getBaseRequest = getBaseRequest;
|
|
10
12
|
exports.wrapConnectionAcceptNegotiation = wrapConnectionAcceptNegotiation;
|
|
11
13
|
exports.makeAdtRequestWithAcceptNegotiation = makeAdtRequestWithAcceptNegotiation;
|
|
@@ -59,12 +61,16 @@ function clearAcceptCache(connection) {
|
|
|
59
61
|
function setAcceptCorrectionEnabled(connection, enabled) {
|
|
60
62
|
stateOf(connection).enabled = enabled;
|
|
61
63
|
}
|
|
62
|
-
/**
|
|
64
|
+
/**
|
|
65
|
+
* This connection's switch, else the `ADT_ACCEPT_CORRECTION` default. Off
|
|
66
|
+
* unless explicitly on: the environment variable turns it on only when it is
|
|
67
|
+
* exactly `true`; unset, or any other value, leaves it off.
|
|
68
|
+
*/
|
|
63
69
|
function getAcceptCorrectionEnabled(connection) {
|
|
64
70
|
const enabled = stateOf(connection).enabled;
|
|
65
71
|
if (enabled !== undefined)
|
|
66
72
|
return enabled;
|
|
67
|
-
return process.env.ADT_ACCEPT_CORRECTION
|
|
73
|
+
return process.env.ADT_ACCEPT_CORRECTION === 'true';
|
|
68
74
|
}
|
|
69
75
|
function extractSupportedAccept(error) {
|
|
70
76
|
const types = new Set();
|
|
@@ -134,6 +140,24 @@ function extractSupportedContentType(error) {
|
|
|
134
140
|
function buildCacheKey(request) {
|
|
135
141
|
return `${request.method.toUpperCase()} ${request.url}`;
|
|
136
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* The Accept stored for `request`'s method and URL on this connection: what a
|
|
145
|
+
* `406` taught negotiation or `rememberAccept` stored, or `undefined` when
|
|
146
|
+
* there is none. A plain read of the per-connection cache, whatever the
|
|
147
|
+
* correction switch says, so a consumer that corrects requests itself can read
|
|
148
|
+
* it while negotiation is off.
|
|
149
|
+
*/
|
|
150
|
+
function cachedAccept(connection, request) {
|
|
151
|
+
return stateOf(connection).accept.get(buildCacheKey(request));
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Store a corrected Accept for `request`'s method and URL on this connection,
|
|
155
|
+
* as the negotiation's own `406` branch does: a later request through the
|
|
156
|
+
* connection's negotiation sends it. A plain write of the per-connection cache.
|
|
157
|
+
*/
|
|
158
|
+
function rememberAccept(connection, request, accept) {
|
|
159
|
+
stateOf(connection).accept.set(buildCacheKey(request), accept);
|
|
160
|
+
}
|
|
137
161
|
/**
|
|
138
162
|
* The connection's request as it was before an `AdtClient` with correction on
|
|
139
163
|
* wrapped it: accept negotiation corrects and resends nothing. The
|
|
@@ -44,6 +44,12 @@ export interface IAdtRequestTrace {
|
|
|
44
44
|
* the field only when it means something.
|
|
45
45
|
*/
|
|
46
46
|
export declare function requestOf(answer?: IAdtWireResponse): IAdtRequestTrace | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Mark `error` as a batch envelope's failure, so the trace leaves it as it
|
|
49
|
+
* came. Module-internal (not in the package's index): the batch connection is
|
|
50
|
+
* its one caller.
|
|
51
|
+
*/
|
|
52
|
+
export declare function markEnvelopeFailure(error: unknown): void;
|
|
47
53
|
/**
|
|
48
54
|
* Put the request back on the answer.
|
|
49
55
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requestTrace.d.ts","sourceRoot":"","sources":["../../src/utils/requestTrace.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EACV,eAAe,EAEf,gBAAgB,EACjB,MAAM,yCAAyC,CAAC;AAGjD,+EAA+E;AAC/E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,MAAM,CAAC,EAAE,gBAAgB,GACxB,gBAAgB,GAAG,SAAS,CAI9B;
|
|
1
|
+
{"version":3,"file":"requestTrace.d.ts","sourceRoot":"","sources":["../../src/utils/requestTrace.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EACV,eAAe,EAEf,gBAAgB,EACjB,MAAM,yCAAyC,CAAC;AAGjD,+EAA+E;AAC/E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,MAAM,CAAC,EAAE,gBAAgB,GACxB,gBAAgB,GAAG,SAAS,CAI9B;AAgBD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAExD;AAWD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,eAAe,GAAG,eAAe,CAsD7E"}
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
*/
|
|
33
33
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
34
34
|
exports.requestOf = requestOf;
|
|
35
|
+
exports.markEnvelopeFailure = markEnvelopeFailure;
|
|
35
36
|
exports.withRequestTrace = withRequestTrace;
|
|
36
37
|
const adtResponse_1 = require("./adtResponse");
|
|
37
38
|
/**
|
|
@@ -48,6 +49,31 @@ function requestOf(answer) {
|
|
|
48
49
|
return undefined;
|
|
49
50
|
return { method: carried.method, url: carried.url };
|
|
50
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* The mark of a batch envelope's failure: one object, rejected to every part
|
|
54
|
+
* the envelope carried. Each part's request passes through the trace, and a
|
|
55
|
+
* part writing its own request onto that shared object would name itself on
|
|
56
|
+
* every other part's failure — the last part's winning, a request never sent
|
|
57
|
+
* on its own. The object carries the envelope's own request instead, set by
|
|
58
|
+
* the batch connection that sent it.
|
|
59
|
+
*
|
|
60
|
+
* Kept in a `WeakSet` rather than under a symbol on the error: a transport may
|
|
61
|
+
* reject with a frozen error, which takes no property, and the mark must hold
|
|
62
|
+
* on it all the same — the parts settle with that failure as it came.
|
|
63
|
+
*/
|
|
64
|
+
const envelopeFailures = new WeakSet();
|
|
65
|
+
/**
|
|
66
|
+
* Mark `error` as a batch envelope's failure, so the trace leaves it as it
|
|
67
|
+
* came. Module-internal (not in the package's index): the batch connection is
|
|
68
|
+
* its one caller.
|
|
69
|
+
*/
|
|
70
|
+
function markEnvelopeFailure(error) {
|
|
71
|
+
if (error !== null && typeof error === 'object')
|
|
72
|
+
envelopeFailures.add(error);
|
|
73
|
+
}
|
|
74
|
+
function isEnvelopeFailure(error) {
|
|
75
|
+
return (error !== null && typeof error === 'object' && envelopeFailures.has(error));
|
|
76
|
+
}
|
|
51
77
|
/** Connections already carrying the trace. */
|
|
52
78
|
const traced = new WeakSet();
|
|
53
79
|
/**
|
|
@@ -101,8 +127,10 @@ function withRequestTrace(connection) {
|
|
|
101
127
|
//
|
|
102
128
|
// A credential refusal SAP was never asked about is not annotated: it is
|
|
103
129
|
// the connection's own object, rethrown to the caller as it came, and
|
|
104
|
-
// this wrapper does not write onto it.
|
|
105
|
-
|
|
130
|
+
// this wrapper does not write onto it. Nor is a batch envelope's
|
|
131
|
+
// failure: every part of the envelope rejects with that one object, and
|
|
132
|
+
// it already names the request that failed — the envelope's own.
|
|
133
|
+
if ((0, adtResponse_1.isUnansweredCredentialRefusal)(error) || isEnvelopeFailure(error))
|
|
106
134
|
throw error;
|
|
107
135
|
error.request = asked;
|
|
108
136
|
throw error;
|
package/docs/usage/BATCH.md
CHANGED
|
@@ -73,7 +73,8 @@ 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.
|
|
76
|
+
Accept negotiation never corrects or resends an envelope or its parts. (Since
|
|
77
|
+
35.0.0 it corrects nothing anywhere unless switched on.) A batch
|
|
77
78
|
connection is exempt from it: an `AdtClient` built over one does not wrap it,
|
|
78
79
|
whatever `enableAcceptCorrection` it is given, and a member that negotiates by
|
|
79
80
|
itself sends through it once. On a connection an `AdtClient` wrapped with
|
|
@@ -86,7 +87,27 @@ and is negotiated like any other; mark it with `exemptFromAcceptNegotiation(wrap
|
|
|
86
87
|
(exported by the package) and it is exempt too. When the batch connection wraps
|
|
87
88
|
a forwarder of yours over a connection an `AdtClient` wrapped, forward through
|
|
88
89
|
`getBaseRequest(thatConnection)` (exported): the envelope then bypasses that
|
|
89
|
-
connection's accept negotiation and is sent once.
|
|
90
|
+
connection's accept negotiation and is sent once. To correct a part that SAP
|
|
91
|
+
answered with `406` yourself, read the acceptable formats from that answer with
|
|
92
|
+
`extractSupportedAccept(error)` (exported): it takes the error the `406` came
|
|
93
|
+
as — any value; one without a response yields an empty list — and returns the
|
|
94
|
+
supported media types as a `string[]`. It reads them from the response headers
|
|
95
|
+
`accept`, `x-sap-adt-supported-accept`, `x-sap-adt-accept`, `supported-accept`
|
|
96
|
+
and `accept-supported` (comma-separated), and from every `type/subtype`
|
|
97
|
+
(with an optional `;parameter`) found in the response body, without
|
|
98
|
+
duplicates. It is the reading accept negotiation applies to a `406` itself.
|
|
99
|
+
|
|
100
|
+
The corrected Accept is remembered where negotiation remembers its own: the
|
|
101
|
+
connection's accept cache, keyed by method and URL. `cachedAccept(connection,
|
|
102
|
+
request)` (exported) returns the Accept stored for that request's method and
|
|
103
|
+
URL on that connection — what a `406` taught negotiation or `rememberAccept`
|
|
104
|
+
stored — or `undefined` when there is none. It is a plain read of the cache and
|
|
105
|
+
ignores the correction switch, so a consumer that corrects requests itself can
|
|
106
|
+
use it while negotiation is off. `rememberAccept(connection, request, accept)` (exported) stores
|
|
107
|
+
`accept` for the request's method and URL on the connection and returns nothing;
|
|
108
|
+
a later request through an `AdtClient` with correction on over the same
|
|
109
|
+
connection sends it (with correction off, only the consumer's own code reads it). Both read and write that cache only, so a correction
|
|
110
|
+
learned on either path serves both. A batch is yours, and so is
|
|
90
111
|
what SAP answered to each of its parts. The envelope request itself still goes
|
|
91
112
|
through the connection's own handling — credential renewal, CSRF recovery and
|
|
92
113
|
session — as every request does: that is about the connection to the endpoint,
|
|
@@ -118,9 +139,14 @@ Recorded request promises receive inner responses, in order: 2xx resolves; other
|
|
|
118
139
|
statuses reject with an Error carrying `response: { status, statusText, headers,
|
|
119
140
|
data }`, matching direct HTTP failure handling. Members keep their usual
|
|
120
141
|
`IAdtResponse` and strategy behavior. Envelope/parse failures stop execution immediately and reject `execute()` and
|
|
121
|
-
parts in the failed envelope.
|
|
142
|
+
parts in the failed envelope. Every part of that envelope rejects with the same
|
|
143
|
+
object and message, and its `request` is the envelope's own
|
|
144
|
+
(`{ method: 'POST', url: '/sap/bc/adt/communication/batch' }`, or the debugger's
|
|
145
|
+
batch URL), not any part's; a failure that takes no property, a frozen one,
|
|
146
|
+
reaches every part as it came, without it. Unsent runs and queued follow-ups reject with a
|
|
122
147
|
library error saying the request was not sent because an earlier envelope failed;
|
|
123
|
-
that error carries the cause, without a SAP response
|
|
148
|
+
that error carries the cause, without a SAP response and without a `request` of
|
|
149
|
+
its own. Missing parts reject with a part-count error. A count
|
|
124
150
|
mismatch also rejects `execute()`. Attach rejection handlers before execution when
|
|
125
151
|
using raw connection promises. Each execute sends follow-up envelopes for requests recorded during settlement
|
|
126
152
|
by member continuations; accept negotiation records none. It yields one event-loop turn
|
|
@@ -1042,7 +1042,10 @@ judgement moved to the caller, who knows which types they are activating.
|
|
|
1042
1042
|
|
|
1043
1043
|
### Accept Negotiation
|
|
1044
1044
|
|
|
1045
|
-
The client can optionally auto-correct `Accept` headers after a 406 response
|
|
1045
|
+
The client can optionally auto-correct `Accept` headers after a 406 response
|
|
1046
|
+
(and `Content-Type` after a 415). It is **off** unless switched on, per client
|
|
1047
|
+
as below or with `ADT_ACCEPT_CORRECTION=true`; with no switch a `406`/`415` is
|
|
1048
|
+
the call's answer and nothing is sent again (default flipped in 35.0.0):
|
|
1046
1049
|
|
|
1047
1050
|
```typescript
|
|
1048
1051
|
const client = new AdtClient(connection, console, {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Migrating to 35.0.0
|
|
2
|
+
|
|
3
|
+
35.0.0 changes no type and no dependency range. It changes one default.
|
|
4
|
+
|
|
5
|
+
## Accept negotiation is off unless switched on
|
|
6
|
+
|
|
7
|
+
Until 34.x, a request SAP answered `406` (its `Accept` not served) or `415`
|
|
8
|
+
(its `Content-Type` not accepted) was corrected from the types SAP named and
|
|
9
|
+
sent once more, unless you turned that off. Now nothing is corrected or sent
|
|
10
|
+
again unless you turn it on: the `406`/`415` is the call's answer, like any
|
|
11
|
+
other status.
|
|
12
|
+
|
|
13
|
+
- `getAcceptCorrectionEnabled(connection)` is `false` without an explicit
|
|
14
|
+
switch.
|
|
15
|
+
- `ADT_ACCEPT_CORRECTION=true` turns it on. Only the exact value `true` does;
|
|
16
|
+
unset, `false` or anything else leaves it off.
|
|
17
|
+
- The `enableAcceptCorrection` option and `setAcceptCorrectionEnabled` are
|
|
18
|
+
unchanged.
|
|
19
|
+
|
|
20
|
+
What to do if you relied on the default:
|
|
21
|
+
|
|
22
|
+
1. Switch it on: `new AdtClient(connection, logger, { enableAcceptCorrection:
|
|
23
|
+
true })` (the same option on `AdtRuntimeClient`), or set
|
|
24
|
+
`ADT_ACCEPT_CORRECTION=true`; or
|
|
25
|
+
2. Correct the request yourself. `extractSupportedAccept(error)` returns the
|
|
26
|
+
media types a `406` names; `rememberAccept(connection, request, accept)`
|
|
27
|
+
stores the one you choose in the connection's accept cache;
|
|
28
|
+
`cachedAccept(connection, request)` reads it back. All three are exported
|
|
29
|
+
from the package root; the last two read and write the cache negotiation
|
|
30
|
+
itself uses, so a correction made either way serves both.
|
|
31
|
+
|
|
32
|
+
`cachedAccept` is a plain read of the cache and no longer depends on the switch.
|
|
33
|
+
A batch connection stays exempt from negotiation.
|