@jerome-benoit/sap-ai-provider-v2 5.0.2 → 5.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 +44 -24
- package/dist/chunk-4ILJD6PI.js +333 -0
- package/dist/chunk-4ILJD6PI.js.map +1 -0
- package/dist/chunk-BHA5MIN6.js +224 -0
- package/dist/chunk-BHA5MIN6.js.map +1 -0
- package/dist/{chunk-LEME2MFD.js → chunk-DLGBK3C3.js} +91 -7
- package/dist/chunk-DLGBK3C3.js.map +1 -0
- package/dist/{chunk-NLMWIVG7.js → chunk-EUBI5ENK.js} +54 -27
- package/dist/chunk-EUBI5ENK.js.map +1 -0
- package/dist/{chunk-YP3AADWD.js → chunk-FKHOJ3ZC.js} +24 -3
- package/dist/chunk-FKHOJ3ZC.js.map +1 -0
- package/dist/{chunk-77JSAAPE.js → chunk-QFMHNGLB.js} +56 -218
- package/dist/chunk-QFMHNGLB.js.map +1 -0
- package/dist/{chunk-U6WJSLR7.js → chunk-QQQYMQPU.js} +19 -10
- package/dist/chunk-QQQYMQPU.js.map +1 -0
- package/dist/{chunk-QZOZ3PZT.js → chunk-ZOBD7PXJ.js} +118 -22
- package/dist/chunk-ZOBD7PXJ.js.map +1 -0
- package/dist/{foundation-models-embedding-model-strategy-A3WDDAYK.js → foundation-models-embedding-model-strategy-3WAKJXBY.js} +5 -4
- package/dist/{foundation-models-embedding-model-strategy-A3WDDAYK.js.map → foundation-models-embedding-model-strategy-3WAKJXBY.js.map} +1 -1
- package/dist/{foundation-models-language-model-strategy-6U6KK6KH.js → foundation-models-language-model-strategy-PJ26VXEA.js} +22 -9
- package/dist/foundation-models-language-model-strategy-PJ26VXEA.js.map +1 -0
- package/dist/index.cjs +1903 -384
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +798 -185
- package/dist/index.d.ts +798 -185
- package/dist/index.js +148 -24
- package/dist/index.js.map +1 -1
- package/dist/{orchestration-embedding-model-strategy-JO3QH5MR.js → orchestration-embedding-model-strategy-AZ76XLMD.js} +6 -5
- package/dist/{orchestration-embedding-model-strategy-JO3QH5MR.js.map → orchestration-embedding-model-strategy-AZ76XLMD.js.map} +1 -1
- package/dist/{orchestration-language-model-strategy-MBVA7BYX.js → orchestration-language-model-strategy-CT6RHCYO.js} +57 -19
- package/dist/orchestration-language-model-strategy-CT6RHCYO.js.map +1 -0
- package/dist/responses-language-model-strategy-UYTV6TPM.js +738 -0
- package/dist/responses-language-model-strategy-UYTV6TPM.js.map +1 -0
- package/dist/sap-ai-error-UPKYWPSS.js +16 -0
- package/dist/sap-ai-error-UPKYWPSS.js.map +1 -0
- package/package.json +79 -39
- package/dist/chunk-77JSAAPE.js.map +0 -1
- package/dist/chunk-LEME2MFD.js.map +0 -1
- package/dist/chunk-NLMWIVG7.js.map +0 -1
- package/dist/chunk-QZOZ3PZT.js.map +0 -1
- package/dist/chunk-U6WJSLR7.js.map +0 -1
- package/dist/chunk-YP3AADWD.js.map +0 -1
- package/dist/foundation-models-language-model-strategy-6U6KK6KH.js.map +0 -1
- package/dist/orchestration-language-model-strategy-MBVA7BYX.js.map +0 -1
package/README.md
CHANGED
|
@@ -62,21 +62,23 @@ SAP's enterprise-grade AI models through the familiar Vercel AI SDK interface.
|
|
|
62
62
|
|
|
63
63
|
- 🔐 **Simplified Authentication** - Uses SAP AI SDK's built-in credential
|
|
64
64
|
handling
|
|
65
|
-
- 🎯 **Tool Calling Support** -
|
|
66
|
-
-
|
|
67
|
-
|
|
65
|
+
- 🎯 **Tool Calling Support** - Function calling across supported APIs;
|
|
66
|
+
[native-tool support depends on the API and facade](./API_REFERENCE.md#tool-definition-format)
|
|
67
|
+
- 🧠 **Native Reasoning** - Orchestration and Responses preserve model reasoning
|
|
68
|
+
and native history, including signed and opaque blocks
|
|
68
69
|
- 🖼️ **Multi-modal Input** - Support for text and image inputs
|
|
69
70
|
- 📡 **Streaming Support** - Real-time text generation with structured V3 blocks
|
|
70
71
|
- 🔒 **Data Masking** - Built-in SAP DPI integration for privacy
|
|
71
72
|
- 🛡️ **Content Filtering** - Azure Content Safety and Llama Guard support
|
|
72
|
-
- 🔧 **TypeScript Support** -
|
|
73
|
+
- 🔧 **TypeScript Support** - Typed SDK contracts, IntelliSense, and portable
|
|
74
|
+
declaration inference
|
|
73
75
|
- 🎨 **Multiple Models** - Support for OpenAI, Claude, Gemini, Nova, and more
|
|
74
76
|
- 🔄 **AI SDK 5–7 Compatibility** - Versioned V2, V3, and V4 entrypoints
|
|
75
77
|
preserve the matching Vercel AI SDK provider specification
|
|
76
78
|
- 📊 **Text Embeddings** - Generate vector embeddings for RAG and semantic
|
|
77
79
|
search
|
|
78
|
-
- 🔀 **
|
|
79
|
-
|
|
80
|
+
- 🔀 **API Selection** - Choose Orchestration, Foundation Models Chat Completions,
|
|
81
|
+
or OpenAI Responses per provider, model, or call
|
|
80
82
|
- 📦 **Stored Configuration Support** - Reference orchestration configurations
|
|
81
83
|
or prompt templates from SAP AI Core
|
|
82
84
|
|
|
@@ -185,10 +187,11 @@ import { createSAPAIProvider } from "@jerome-benoit/sap-ai-provider/v2";
|
|
|
185
187
|
// import { createSAPAIProvider } from "@jerome-benoit/sap-ai-provider-v2";
|
|
186
188
|
```
|
|
187
189
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
use
|
|
191
|
-
|
|
190
|
+
For AI SDK 6, prefer the main package's root or `/v3` entrypoint.
|
|
191
|
+
V2 models use the SDK's compatibility layer and emit compatibility warnings.
|
|
192
|
+
If V2 compatibility is required, use a current 6.x patch. See
|
|
193
|
+
[V2 embedding troubleshooting](./TROUBLESHOOTING.md#problem-v2-embeddings-fail-with-ai-sdk-600)
|
|
194
|
+
if embedding requests fail.
|
|
192
195
|
|
|
193
196
|
See [Architecture - Versioned Packages](./ARCHITECTURE.md#versioned-package-architecture-v4--v3--v2)
|
|
194
197
|
for the V4/V3/V2 packaging model.
|
|
@@ -211,12 +214,14 @@ const provider = createSAPAIProvider({
|
|
|
211
214
|
|
|
212
215
|
### API Selection
|
|
213
216
|
|
|
214
|
-
|
|
217
|
+
Choose the API supported by your SAP AI Core deployment:
|
|
215
218
|
|
|
216
219
|
- **Orchestration API** (default): Full-featured API with data masking, content
|
|
217
220
|
filtering, document grounding, and translation
|
|
218
221
|
- **Foundation Models API**: Direct model access with additional parameters like
|
|
219
222
|
`logprobs`, `seed`, `logit_bias`, and `dataSources` (Azure On Your Data)
|
|
223
|
+
- **Responses API**: Direct OpenAI Responses access for models that require it
|
|
224
|
+
for tool calling, including GPT-6.1-Sol
|
|
220
225
|
|
|
221
226
|
**Complete example:**
|
|
222
227
|
[examples/example-foundation-models.ts](./examples/example-foundation-models.ts)\
|
|
@@ -254,6 +259,23 @@ const result = await generateText({
|
|
|
254
259
|
> (masking, filtering, grounding, translation). Attempting to use these features
|
|
255
260
|
> with Foundation Models API will throw an `UnsupportedFeatureError`.
|
|
256
261
|
|
|
262
|
+
For OpenAI Responses, select `api: "responses"` explicitly:
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
const provider = createSAPAIProvider({ api: "responses" });
|
|
266
|
+
const model = provider("gpt-6.1-sol", {
|
|
267
|
+
responses: { reasoningEffort: "low" },
|
|
268
|
+
});
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
The default remains Orchestration; model names do not change API selection.
|
|
272
|
+
Responses uses your existing SAP credentials and deployment configuration.
|
|
273
|
+
It bypasses Orchestration modules, and embeddings need an explicit
|
|
274
|
+
`api: "foundation-models"` or `api: "orchestration"` override.
|
|
275
|
+
Responses rejects assistant file history rather than silently omitting it.
|
|
276
|
+
See the [Responses API reference](./API_REFERENCE.md#responses-api) for options,
|
|
277
|
+
reasoning history, and a [runnable example](./examples/example-responses.ts).
|
|
278
|
+
|
|
257
279
|
### Option 2: Default Instance (Quick Start)
|
|
258
280
|
|
|
259
281
|
```typescript
|
|
@@ -332,9 +354,9 @@ console.log(result.text);
|
|
|
332
354
|
**Complete example:**
|
|
333
355
|
[examples/example-simple-chat-completion.ts](./examples/example-simple-chat-completion.ts)
|
|
334
356
|
|
|
335
|
-
> **Note:**
|
|
336
|
-
>
|
|
337
|
-
>
|
|
357
|
+
> **Note:** Keep returned reasoning parts and their provider metadata intact to
|
|
358
|
+
> preserve native Orchestration history. `includeReasoning` only controls forwarding
|
|
359
|
+
> manually supplied reasoning as text; it does not enable model reasoning.
|
|
338
360
|
|
|
339
361
|
```typescript
|
|
340
362
|
const result = await generateText({
|
|
@@ -405,8 +427,7 @@ import { generateText } from "ai";
|
|
|
405
427
|
const provider = createSAPAIProvider();
|
|
406
428
|
|
|
407
429
|
const model = provider("gpt-4.1", {
|
|
408
|
-
//
|
|
409
|
-
// Best practice is to keep this disabled.
|
|
430
|
+
// Only forward manually supplied reasoning as text when explicitly needed.
|
|
410
431
|
includeReasoning: false,
|
|
411
432
|
modelParams: {
|
|
412
433
|
temperature: 0.3,
|
|
@@ -459,13 +480,9 @@ For complete embedding API documentation, see
|
|
|
459
480
|
|
|
460
481
|
## Supported Models
|
|
461
482
|
|
|
462
|
-
This provider supports
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
> **Note:** Model availability depends on your SAP AI Core tenant configuration,
|
|
467
|
-
> region, and subscription. Use `provider("model-name")` with any model ID
|
|
468
|
-
> available in your environment.
|
|
483
|
+
This provider supports language models and text embeddings through the supported
|
|
484
|
+
SAP AI Core APIs. Model availability and features depend on your tenant and the
|
|
485
|
+
selected API. Native RPT tabular prediction APIs are not exposed.
|
|
469
486
|
|
|
470
487
|
For details on discovering available models, see
|
|
471
488
|
**[API Reference: Supported Models](./API_REFERENCE.md#supported-models)**.
|
|
@@ -686,8 +703,10 @@ authentication, model parameters, data masking, content filtering, and more.
|
|
|
686
703
|
`AI-Object-Store-Secret-Name` (feedback service). See
|
|
687
704
|
[API Reference](./API_REFERENCE.md#sapaiprovidersettings) for portability caveats.
|
|
688
705
|
- `modelParams`: Temperature, maxTokens, topP, and other generation parameters
|
|
706
|
+
- `dropUnsupportedParams`: Orchestration-only control for unsupported parameters
|
|
707
|
+
on the primary local model; see the [API reference](./API_REFERENCE.md#orchestrationmodelsettings).
|
|
689
708
|
- `masking`: SAP Data Privacy Integration (DPI) configuration
|
|
690
|
-
- `filtering`: Content safety filters (Azure Content Safety, Llama Guard)
|
|
709
|
+
- `filtering`: Content safety filters (Azure Content Safety, Llama Guard, IBM Granite Guardian)
|
|
691
710
|
|
|
692
711
|
For complete configuration reference including all available options, types, and
|
|
693
712
|
examples, see
|
|
@@ -771,6 +790,7 @@ See [Installation](#installation) for other AI SDK versions.
|
|
|
771
790
|
| `example-translation.ts` | Input/output translation | Multi-language support, SAP translation |
|
|
772
791
|
| `example-embeddings.ts` | Text embeddings | Vector generation, semantic similarity |
|
|
773
792
|
| `example-foundation-models.ts` | Foundation Models API | Direct model access, logprobs, seed |
|
|
793
|
+
| `example-responses.ts` | OpenAI Responses API | Streaming, tools, reasoning history |
|
|
774
794
|
|
|
775
795
|
**Running Examples:**
|
|
776
796
|
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import {createRequire as __createRequire} from 'module';var require=__createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
throwIfAborted,
|
|
4
|
+
waitWithAbort
|
|
5
|
+
} from "./chunk-DLGBK3C3.js";
|
|
6
|
+
|
|
7
|
+
// src/sap-http-stream.ts
|
|
8
|
+
import { AISDKError } from "@ai-sdk/provider";
|
|
9
|
+
import { isErrorWithCause } from "@sap-cloud-sdk/util";
|
|
10
|
+
var ERROR_BODY_TRUNCATION = "...[truncated]";
|
|
11
|
+
var MAX_ERROR_BODY_BYTES = 2e3 - ERROR_BODY_TRUNCATION.length;
|
|
12
|
+
var ERROR_BODY_READ_FAILURE = /* @__PURE__ */ Symbol("sap-ai.httpErrorBodyReadFailure");
|
|
13
|
+
var disposedStreams = /* @__PURE__ */ new WeakSet();
|
|
14
|
+
var leasedStreams = /* @__PURE__ */ new WeakSet();
|
|
15
|
+
var streamLeases = /* @__PURE__ */ new WeakMap();
|
|
16
|
+
function destroyHttpResponse(response, retainedRequest) {
|
|
17
|
+
const body = response.data;
|
|
18
|
+
const request = response.request;
|
|
19
|
+
try {
|
|
20
|
+
if (isDestroyableRequest(body)) body.destroy();
|
|
21
|
+
} finally {
|
|
22
|
+
if (request !== retainedRequest && isDestroyableRequest(request)) request.destroy();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function disposeSapStream(response) {
|
|
26
|
+
if (disposedStreams.has(response)) return;
|
|
27
|
+
disposedStreams.add(response);
|
|
28
|
+
try {
|
|
29
|
+
response.stream.controller.abort();
|
|
30
|
+
} finally {
|
|
31
|
+
if (leasedStreams.has(response)) releaseSapStream(response);
|
|
32
|
+
else destroyHttpResponse(response.rawResponse);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async function executeSapStream(execute, signal, requestConfig) {
|
|
36
|
+
const responses = [];
|
|
37
|
+
const cleanups = /* @__PURE__ */ new Set();
|
|
38
|
+
let closed = false;
|
|
39
|
+
let transferred = false;
|
|
40
|
+
let failedRequest;
|
|
41
|
+
let failedError;
|
|
42
|
+
const release = () => {
|
|
43
|
+
closed = true;
|
|
44
|
+
signal?.removeEventListener("abort", release);
|
|
45
|
+
for (const response of responses) {
|
|
46
|
+
if (response.fromTransport && isConsumedHttpBody(response.data)) continue;
|
|
47
|
+
const consumedRequest = responses.some(
|
|
48
|
+
(other) => other.fromTransport && other.request === response.request && isConsumedHttpBody(other.data)
|
|
49
|
+
);
|
|
50
|
+
try {
|
|
51
|
+
const dispose = response.disposeTimeout;
|
|
52
|
+
const retainedRequest = consumedRequest ? response.request : void 0;
|
|
53
|
+
if (dispose && cleanups.has(dispose)) dispose(retainedRequest);
|
|
54
|
+
else destroyHttpResponse(response, retainedRequest);
|
|
55
|
+
} catch {
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
responses.length = 0;
|
|
59
|
+
cleanups.clear();
|
|
60
|
+
};
|
|
61
|
+
const ownResponse = (response, request, fromTransport, failed) => {
|
|
62
|
+
const data = response.data;
|
|
63
|
+
const nativeRequest = response.request;
|
|
64
|
+
const owned = responses.find((other) => other.data === data && other.request === nativeRequest);
|
|
65
|
+
if (owned) {
|
|
66
|
+
if (failed && !owned.disposeTimeout) {
|
|
67
|
+
owned.disposeTimeout = preserveResponseBodyTimeout(response, request, cleanups);
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
responses.push({
|
|
71
|
+
data,
|
|
72
|
+
disposeTimeout: failed ? preserveResponseBodyTimeout(response, request, cleanups) : void 0,
|
|
73
|
+
fromTransport,
|
|
74
|
+
request: nativeRequest
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
if (closed || signal?.aborted) release();
|
|
78
|
+
};
|
|
79
|
+
const observeResponse = ({ fn }) => async (request) => {
|
|
80
|
+
try {
|
|
81
|
+
const response = await fn(request);
|
|
82
|
+
ownResponse(response, request, true, false);
|
|
83
|
+
return response;
|
|
84
|
+
} catch (error) {
|
|
85
|
+
const failed = findFailedHttpRequest(error);
|
|
86
|
+
if (failed) ownResponse(failed.response, request, true, true);
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
const captureFinalFailure = ({ fn }) => async (request) => {
|
|
91
|
+
try {
|
|
92
|
+
const response = await fn(request);
|
|
93
|
+
ownResponse(response, request, false, false);
|
|
94
|
+
return response;
|
|
95
|
+
} catch (error) {
|
|
96
|
+
const failed = findFailedHttpRequest(error);
|
|
97
|
+
if (!failed) throw error;
|
|
98
|
+
failedRequest = failed;
|
|
99
|
+
failedError = error;
|
|
100
|
+
ownResponse(failed.response, request, false, true);
|
|
101
|
+
return failed.response;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
try {
|
|
105
|
+
const response = await waitWithAbort(
|
|
106
|
+
execute({
|
|
107
|
+
...requestConfig,
|
|
108
|
+
middleware: [captureFinalFailure, ...requestConfig?.middleware ?? [], observeResponse]
|
|
109
|
+
}),
|
|
110
|
+
signal,
|
|
111
|
+
disposeSapStream
|
|
112
|
+
);
|
|
113
|
+
if (signal?.aborted) {
|
|
114
|
+
try {
|
|
115
|
+
disposeSapStream(response);
|
|
116
|
+
} finally {
|
|
117
|
+
throwIfAborted(signal);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (failedRequest) {
|
|
121
|
+
try {
|
|
122
|
+
await readHttpErrorBody(
|
|
123
|
+
failedRequest.response,
|
|
124
|
+
createErrorByteStream(failedRequest.response),
|
|
125
|
+
signal
|
|
126
|
+
);
|
|
127
|
+
} catch {
|
|
128
|
+
throwIfAborted(signal);
|
|
129
|
+
}
|
|
130
|
+
throw failedError;
|
|
131
|
+
}
|
|
132
|
+
if (responses.length > 0) {
|
|
133
|
+
streamLeases.set(response, release);
|
|
134
|
+
leasedStreams.add(response);
|
|
135
|
+
signal?.addEventListener("abort", release, { once: true });
|
|
136
|
+
if (signal?.aborted) {
|
|
137
|
+
releaseSapStream(response);
|
|
138
|
+
throwIfAborted(signal);
|
|
139
|
+
}
|
|
140
|
+
transferred = true;
|
|
141
|
+
}
|
|
142
|
+
return response;
|
|
143
|
+
} finally {
|
|
144
|
+
if (!transferred) release();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function findFailedHttpRequest(error) {
|
|
148
|
+
const seen = /* @__PURE__ */ new Set();
|
|
149
|
+
let current = error;
|
|
150
|
+
for (let depth = 0; depth < 32; depth++) {
|
|
151
|
+
if (typeof current !== "object" || current === null || seen.has(current)) return void 0;
|
|
152
|
+
if (AISDKError.isInstance(current)) return void 0;
|
|
153
|
+
seen.add(current);
|
|
154
|
+
if (isFailedHttpRequest(current)) return current;
|
|
155
|
+
current = "cause" in current ? current.cause : current instanceof Error && isErrorWithCause(current) ? current.rootCause : void 0;
|
|
156
|
+
}
|
|
157
|
+
return void 0;
|
|
158
|
+
}
|
|
159
|
+
function isDestroyableRequest(request) {
|
|
160
|
+
return typeof request === "object" && request !== null && "destroy" in request && typeof request.destroy === "function";
|
|
161
|
+
}
|
|
162
|
+
function preserveResponseBodyTimeout(response, requestConfig, cleanups) {
|
|
163
|
+
const body = response.data;
|
|
164
|
+
const request = response.request;
|
|
165
|
+
if (!isHttpResponseEvents(body) || !isHttpResponseEvents(request)) return;
|
|
166
|
+
const responseConfig = "config" in response ? response.config : void 0;
|
|
167
|
+
const timeoutConfig = typeof responseConfig === "object" && responseConfig !== null && !Array.isArray(responseConfig) ? responseConfig : requestConfig;
|
|
168
|
+
let ownsRequest = true;
|
|
169
|
+
const release = () => {
|
|
170
|
+
request.removeListener("timeout", onTimeout);
|
|
171
|
+
body.removeListener("end", release);
|
|
172
|
+
body.removeListener("error", onFailure);
|
|
173
|
+
body.removeListener("close", onFailure);
|
|
174
|
+
cleanups.delete(dispose);
|
|
175
|
+
};
|
|
176
|
+
const onFailure = () => {
|
|
177
|
+
try {
|
|
178
|
+
if (ownsRequest) request.destroy();
|
|
179
|
+
} finally {
|
|
180
|
+
release();
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
const dispose = (retainedRequest) => {
|
|
184
|
+
ownsRequest = request !== retainedRequest;
|
|
185
|
+
request.removeListener("timeout", onTimeout);
|
|
186
|
+
try {
|
|
187
|
+
body.destroy();
|
|
188
|
+
} finally {
|
|
189
|
+
if (ownsRequest) request.destroy();
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
const onTimeout = () => {
|
|
193
|
+
const nativeResponse = "res" in request ? request.res : void 0;
|
|
194
|
+
if (typeof nativeResponse === "object" && nativeResponse !== null && "complete" in nativeResponse && nativeResponse.complete === true) {
|
|
195
|
+
release();
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const timeout = timeoutConfig.timeout;
|
|
199
|
+
const timeoutErrorMessage = timeoutConfig.timeoutErrorMessage;
|
|
200
|
+
const transitional = timeoutConfig.transitional;
|
|
201
|
+
const clarifyTimeoutError = typeof transitional === "object" && transitional !== null && "clarifyTimeoutError" in transitional && transitional.clarifyTimeoutError === true;
|
|
202
|
+
const message = typeof timeoutErrorMessage === "string" && timeoutErrorMessage ? timeoutErrorMessage : (typeof timeout === "number" || typeof timeout === "string") && timeout ? `timeout of ${String(timeout)}ms exceeded` : "timeout exceeded";
|
|
203
|
+
body.destroy(
|
|
204
|
+
Object.assign(new Error(message), {
|
|
205
|
+
code: clarifyTimeoutError ? "ETIMEDOUT" : "ECONNABORTED"
|
|
206
|
+
})
|
|
207
|
+
);
|
|
208
|
+
request.destroy();
|
|
209
|
+
};
|
|
210
|
+
request.once("timeout", onTimeout);
|
|
211
|
+
body.once("end", release);
|
|
212
|
+
body.once("error", onFailure);
|
|
213
|
+
body.once("close", onFailure);
|
|
214
|
+
cleanups.add(dispose);
|
|
215
|
+
return dispose;
|
|
216
|
+
}
|
|
217
|
+
async function readHttpErrorBody(response, stream, signal) {
|
|
218
|
+
const decoder = new TextDecoder();
|
|
219
|
+
const reader = stream.getReader();
|
|
220
|
+
let retainedBytes = 0;
|
|
221
|
+
let text = "";
|
|
222
|
+
let truncated = false;
|
|
223
|
+
let readFailure;
|
|
224
|
+
try {
|
|
225
|
+
for (; ; ) {
|
|
226
|
+
const chunk = await waitWithAbort(reader.read(), signal);
|
|
227
|
+
if (chunk.done) {
|
|
228
|
+
text += decoder.decode();
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
const remaining = MAX_ERROR_BODY_BYTES - retainedBytes;
|
|
232
|
+
text += decoder.decode(chunk.value.subarray(0, remaining), { stream: true });
|
|
233
|
+
retainedBytes += Math.min(chunk.value.byteLength, remaining);
|
|
234
|
+
if (chunk.value.byteLength > remaining) {
|
|
235
|
+
truncated = true;
|
|
236
|
+
await reader.cancel("HTTP error diagnostic limit exceeded");
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
} catch (error) {
|
|
241
|
+
readFailure = error;
|
|
242
|
+
if (!truncated) text += decoder.decode();
|
|
243
|
+
void reader.cancel(error).catch(() => {
|
|
244
|
+
});
|
|
245
|
+
} finally {
|
|
246
|
+
if (signal?.aborted) {
|
|
247
|
+
destroyHttpResponse(response);
|
|
248
|
+
void reader.cancel(signal.reason).catch(() => {
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
reader.releaseLock();
|
|
252
|
+
}
|
|
253
|
+
response.data = truncated ? text + ERROR_BODY_TRUNCATION : text;
|
|
254
|
+
if (!truncated && readFailure === void 0) {
|
|
255
|
+
try {
|
|
256
|
+
response.data = JSON.parse(text);
|
|
257
|
+
} catch {
|
|
258
|
+
response.data = text;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
throwIfAborted(signal);
|
|
262
|
+
return readFailure;
|
|
263
|
+
}
|
|
264
|
+
function withSapStreamCleanup(response, stream) {
|
|
265
|
+
if (!streamLeases.has(response)) return stream;
|
|
266
|
+
return iterate();
|
|
267
|
+
async function* iterate() {
|
|
268
|
+
try {
|
|
269
|
+
yield* stream;
|
|
270
|
+
} finally {
|
|
271
|
+
releaseSapStream(response);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
function createErrorByteStream(response) {
|
|
276
|
+
const body = response.data;
|
|
277
|
+
if (typeof body !== "object" || body === null || !(Symbol.asyncIterator in body) || typeof body[Symbol.asyncIterator] !== "function") {
|
|
278
|
+
throw new TypeError("SAP did not return a readable HTTP error body.");
|
|
279
|
+
}
|
|
280
|
+
const iterator = body[Symbol.asyncIterator]();
|
|
281
|
+
const encoder = new TextEncoder();
|
|
282
|
+
return new ReadableStream(
|
|
283
|
+
{
|
|
284
|
+
cancel() {
|
|
285
|
+
destroyHttpResponse(response);
|
|
286
|
+
},
|
|
287
|
+
async pull(controller) {
|
|
288
|
+
try {
|
|
289
|
+
const chunk = await iterator.next();
|
|
290
|
+
if (chunk.done) controller.close();
|
|
291
|
+
else if (typeof chunk.value === "string") controller.enqueue(encoder.encode(chunk.value));
|
|
292
|
+
else if (chunk.value instanceof Uint8Array) controller.enqueue(chunk.value);
|
|
293
|
+
else throw new TypeError("SAP returned a non-byte HTTP error chunk.");
|
|
294
|
+
} catch (error) {
|
|
295
|
+
try {
|
|
296
|
+
destroyHttpResponse(response);
|
|
297
|
+
} catch {
|
|
298
|
+
} finally {
|
|
299
|
+
controller.error(error);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
{ highWaterMark: 0 }
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
function isConsumedHttpBody(body) {
|
|
308
|
+
return typeof body === "object" && body !== null && "readableEnded" in body && body.readableEnded === true;
|
|
309
|
+
}
|
|
310
|
+
function isFailedHttpRequest(error) {
|
|
311
|
+
return error instanceof Error && "isAxiosError" in error && error.isAxiosError === true && "response" in error && typeof error.response === "object" && error.response !== null;
|
|
312
|
+
}
|
|
313
|
+
function isHttpResponseEvents(value) {
|
|
314
|
+
return isDestroyableRequest(value) && "once" in value && typeof value.once === "function" && "removeListener" in value && typeof value.removeListener === "function";
|
|
315
|
+
}
|
|
316
|
+
function releaseSapStream(response) {
|
|
317
|
+
const release = streamLeases.get(response);
|
|
318
|
+
streamLeases.delete(response);
|
|
319
|
+
release?.();
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
export {
|
|
323
|
+
ERROR_BODY_READ_FAILURE,
|
|
324
|
+
destroyHttpResponse,
|
|
325
|
+
disposeSapStream,
|
|
326
|
+
executeSapStream,
|
|
327
|
+
findFailedHttpRequest,
|
|
328
|
+
isDestroyableRequest,
|
|
329
|
+
preserveResponseBodyTimeout,
|
|
330
|
+
readHttpErrorBody,
|
|
331
|
+
withSapStreamCleanup
|
|
332
|
+
};
|
|
333
|
+
//# sourceMappingURL=chunk-4ILJD6PI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/sap-http-stream.ts"],"sourcesContent":["/** Native SAP HTTP stream lifecycle and bounded failure diagnostics. */\nimport type { CustomRequestConfig } from \"@sap-ai-sdk/core\";\nimport type { HttpResponse } from \"@sap-cloud-sdk/http-client\";\n\nimport { AISDKError } from \"@ai-sdk/provider\";\nimport { isErrorWithCause } from \"@sap-cloud-sdk/util\";\n\nimport { throwIfAborted, waitWithAbort } from \"./abort-utils.js\";\nexport interface FailedHttpRequest extends Error {\n isAxiosError: true;\n response: SAPHttpResponse;\n}\nexport type SAPHttpMiddleware = NonNullable<CustomRequestConfig[\"middleware\"]>[number];\n\nexport type SAPHttpResponse = HttpResponse;\n\ninterface HttpResponseEvents {\n destroy: (error?: Error) => void;\n once: (event: string, listener: () => void) => unknown;\n removeListener: (event: string, listener: () => void) => unknown;\n}\n\ninterface HttpStreamResources {\n readonly data: unknown;\n readonly request?: unknown;\n}\ninterface NativeStreamResponse {\n readonly rawResponse: SAPHttpResponse;\n readonly stream: { readonly controller: AbortController };\n}\n\ntype ResponseBodyDisposer = (retainedRequest?: unknown) => void;\n\ninterface StreamResponseOwnership extends HttpStreamResources {\n disposeTimeout: ResponseBodyDisposer | undefined;\n readonly fromTransport: boolean;\n}\n\nconst ERROR_BODY_TRUNCATION = \"...[truncated]\";\n// Reserve the marker inside the shared HTTP diagnostic serializer's 2,000-character limit.\nconst MAX_ERROR_BODY_BYTES = 2_000 - ERROR_BODY_TRUNCATION.length;\nexport const ERROR_BODY_READ_FAILURE = Symbol(\"sap-ai.httpErrorBodyReadFailure\");\nconst disposedStreams = new WeakSet();\n// Retain provenance after release so later cancellation cannot use raw fallback cleanup.\nconst leasedStreams = new WeakSet();\nconst streamLeases = new WeakMap<object, () => void>();\n/**\n * Releases an HTTP response that arrives after its caller has cancelled.\n * @param response - A late SDK response whose stream has no consumer.\n * @param retainedRequest - A request transferred to a recovered successful stream.\n */\nexport function destroyHttpResponse(\n response: HttpStreamResources,\n retainedRequest?: unknown,\n): void {\n const body: unknown = response.data;\n const request: unknown = response.request;\n try {\n if (isDestroyableRequest(body)) body.destroy();\n } finally {\n if (request !== retainedRequest && isDestroyableRequest(request)) request.destroy();\n }\n}\n/**\n * Releases an abandoned SDK stream without starting its SSE iterator.\n * @param response - Raw stream response returned by either SAP client.\n */\nexport function disposeSapStream(response: NativeStreamResponse): void {\n if (disposedStreams.has(response)) return;\n disposedStreams.add(response);\n try {\n response.stream.controller.abort();\n } finally {\n if (leasedStreams.has(response)) releaseSapStream(response);\n else destroyHttpResponse(response.rawResponse);\n }\n}\n/**\n * Preserves only the final middleware failure before SAP's JSON-only stream parser.\n * @param execute - Starts the raw SDK stream with the supplied middleware chain.\n * @param signal - Caller cancellation forwarded separately to the SDK.\n * @param requestConfig - Existing caller transport and retry middleware.\n * @returns A live SDK stream, with successful ownership transferred to its caller.\n */\nexport async function executeSapStream<T extends NativeStreamResponse>(\n execute: (requestConfig: CustomRequestConfig) => Promise<T>,\n signal: AbortSignal | undefined,\n requestConfig: CustomRequestConfig | undefined,\n): Promise<T> {\n const responses: StreamResponseOwnership[] = [];\n const cleanups = new Set<() => void>();\n let closed = false;\n let transferred = false;\n let failedRequest: FailedHttpRequest | undefined;\n let failedError: unknown;\n\n const release = () => {\n closed = true;\n signal?.removeEventListener(\"abort\", release);\n // Each snapshot owns the resources observed before middleware can replace them.\n // A consumed native body has already returned its request's socket to the pool.\n for (const response of responses) {\n if (response.fromTransport && isConsumedHttpBody(response.data)) continue;\n const consumedRequest = responses.some(\n (other) =>\n other.fromTransport &&\n other.request === response.request &&\n isConsumedHttpBody(other.data),\n );\n try {\n const dispose = response.disposeTimeout;\n const retainedRequest = consumedRequest ? response.request : undefined;\n if (dispose && cleanups.has(dispose)) dispose(retainedRequest);\n else destroyHttpResponse(response, retainedRequest);\n } catch {\n // Cleanup must not replace the operation's primary outcome.\n }\n }\n responses.length = 0;\n cleanups.clear();\n };\n const ownResponse = (\n response: SAPHttpResponse,\n request: CustomRequestConfig,\n fromTransport: boolean,\n failed: boolean,\n ) => {\n const data: unknown = response.data;\n const nativeRequest: unknown = response.request;\n const owned = responses.find((other) => other.data === data && other.request === nativeRequest);\n if (owned) {\n if (failed && !owned.disposeTimeout) {\n owned.disposeTimeout = preserveResponseBodyTimeout(response, request, cleanups);\n }\n } else {\n responses.push({\n data,\n disposeTimeout: failed\n ? preserveResponseBodyTimeout(response, request, cleanups)\n : undefined,\n fromTransport,\n request: nativeRequest,\n });\n }\n if (closed || signal?.aborted) release();\n };\n const observeResponse: SAPHttpMiddleware =\n ({ fn }) =>\n async (request) => {\n try {\n const response = await fn(request);\n ownResponse(response, request, true, false);\n return response;\n } catch (error) {\n const failed = findFailedHttpRequest(error);\n if (failed) ownResponse(failed.response, request, true, true);\n throw error;\n }\n };\n const captureFinalFailure: SAPHttpMiddleware =\n ({ fn }) =>\n async (request) => {\n try {\n const response = await fn(request);\n ownResponse(response, request, false, false);\n return response;\n } catch (error) {\n const failed = findFailedHttpRequest(error);\n if (!failed) throw error;\n failedRequest = failed;\n failedError = error;\n // Middleware can reject a successful response or substitute its body.\n ownResponse(failed.response, request, false, true);\n return failed.response;\n }\n };\n try {\n const response = await waitWithAbort(\n execute({\n ...requestConfig,\n middleware: [captureFinalFailure, ...(requestConfig?.middleware ?? []), observeResponse],\n }),\n signal,\n disposeSapStream,\n );\n if (signal?.aborted) {\n try {\n disposeSapStream(response);\n } finally {\n throwIfAborted(signal);\n }\n }\n if (failedRequest) {\n try {\n await readHttpErrorBody(\n failedRequest.response,\n createErrorByteStream(failedRequest.response),\n signal,\n );\n } catch {\n // Diagnostic failures never replace the final native HTTP failure.\n throwIfAborted(signal);\n }\n throw failedError;\n }\n if (responses.length > 0) {\n // Do not inspect optional rawResponse metadata here. A lease keeps both\n // replacement streams and wrappers around original bodies alive until done.\n streamLeases.set(response, release);\n leasedStreams.add(response);\n signal?.addEventListener(\"abort\", release, { once: true });\n if (signal?.aborted) {\n releaseSapStream(response);\n throwIfAborted(signal);\n }\n transferred = true;\n }\n return response;\n } finally {\n if (!transferred) release();\n }\n}\n\n/**\n * Finds the final Axios failure without crossing a classified AI SDK boundary.\n * @param error - Original rejection from the configured middleware chain.\n * @returns The nested failed request, if reachable within the bounded cause chain.\n */\nexport function findFailedHttpRequest(error: unknown): FailedHttpRequest | undefined {\n const seen = new Set<object>();\n let current = error;\n for (let depth = 0; depth < 32; depth++) {\n if (typeof current !== \"object\" || current === null || seen.has(current)) return undefined;\n if (AISDKError.isInstance(current)) return undefined;\n seen.add(current);\n if (isFailedHttpRequest(current)) return current;\n // SAP's legacy rootCause getter can recurse. Prefer its native cause even\n // when undefined, and never inspect both representations of the same chain.\n current =\n \"cause\" in current\n ? current.cause\n : current instanceof Error && isErrorWithCause(current)\n ? current.rootCause\n : undefined;\n }\n return undefined;\n}\n\n/**\n * Identifies the native request used to close a preserved HTTP-error response.\n * @param request - Request attached to an Axios response.\n * @returns Whether the request supports cancellation by destruction.\n */\nexport function isDestroyableRequest(request: unknown): request is { destroy: () => void } {\n return (\n typeof request === \"object\" &&\n request !== null &&\n \"destroy\" in request &&\n typeof request.destroy === \"function\"\n );\n}\n\n/**\n * Keeps Axios's socket inactivity timeout effective after streamed headers settle.\n * @param response - Native response observed before configured middleware resumes.\n * @param requestConfig - Fallback settings when resolved Axios metadata is unavailable.\n * @param cleanups - Disposes responses abandoned by cancellation or middleware retries.\n * @returns The setup disposer; omit it from setup cleanup when the body is transferred.\n */\nexport function preserveResponseBodyTimeout(\n response: SAPHttpResponse,\n requestConfig: CustomRequestConfig,\n cleanups: Set<() => void>,\n): ResponseBodyDisposer | undefined {\n const body: unknown = response.data;\n const request: unknown = response.request;\n if (!isHttpResponseEvents(body) || !isHttpResponseEvents(request)) return;\n const responseConfig: unknown = \"config\" in response ? response.config : undefined;\n const timeoutConfig =\n typeof responseConfig === \"object\" && responseConfig !== null && !Array.isArray(responseConfig)\n ? (responseConfig as Record<string, unknown>)\n : requestConfig;\n let ownsRequest = true;\n\n const release = () => {\n request.removeListener(\"timeout\", onTimeout);\n body.removeListener(\"end\", release);\n body.removeListener(\"error\", onFailure);\n body.removeListener(\"close\", onFailure);\n cleanups.delete(dispose);\n };\n const onFailure = () => {\n try {\n if (ownsRequest) request.destroy();\n } finally {\n release();\n }\n };\n const dispose: ResponseBodyDisposer = (retainedRequest) => {\n ownsRequest = request !== retainedRequest;\n request.removeListener(\"timeout\", onTimeout);\n // Keep the error observer until close: destruction can emit an error asynchronously.\n try {\n body.destroy();\n } finally {\n if (ownsRequest) request.destroy();\n }\n };\n const onTimeout = () => {\n const nativeResponse: unknown = \"res\" in request ? request.res : undefined;\n // A fully received body can remain buffered while configured middleware waits.\n if (\n typeof nativeResponse === \"object\" &&\n nativeResponse !== null &&\n \"complete\" in nativeResponse &&\n nativeResponse.complete === true\n ) {\n release();\n return;\n }\n const timeout: unknown = timeoutConfig.timeout;\n const timeoutErrorMessage: unknown = timeoutConfig.timeoutErrorMessage;\n const transitional: unknown = timeoutConfig.transitional;\n const clarifyTimeoutError =\n typeof transitional === \"object\" &&\n transitional !== null &&\n \"clarifyTimeoutError\" in transitional &&\n transitional.clarifyTimeoutError === true;\n const message =\n typeof timeoutErrorMessage === \"string\" && timeoutErrorMessage\n ? timeoutErrorMessage\n : (typeof timeout === \"number\" || typeof timeout === \"string\") && timeout\n ? `timeout of ${String(timeout)}ms exceeded`\n : \"timeout exceeded\";\n // Aborting the controller here would misclassify inactivity as caller cancellation.\n body.destroy(\n Object.assign(new Error(message), {\n code: clarifyTimeoutError ? \"ETIMEDOUT\" : \"ECONNABORTED\",\n }),\n );\n request.destroy();\n };\n request.once(\"timeout\", onTimeout);\n body.once(\"end\", release);\n body.once(\"error\", onFailure);\n body.once(\"close\", onFailure);\n cleanups.add(dispose);\n return dispose;\n}\n\n/**\n * Retains bounded UTF-8 diagnostics, parsing JSON only after a complete body.\n * @param response - Native failed response whose data will hold the diagnostic.\n * @param stream - Byte stream owned by this failure.\n * @param signal - Caller cancellation, distinct from diagnostic truncation.\n * @returns Any secondary read failure, kept outside the native cause chain.\n */\nexport async function readHttpErrorBody(\n response: SAPHttpResponse,\n stream: ReadableStream<Uint8Array>,\n signal?: AbortSignal,\n): Promise<unknown> {\n const decoder = new TextDecoder();\n const reader = stream.getReader();\n let retainedBytes = 0;\n let text = \"\";\n let truncated = false;\n let readFailure: unknown;\n try {\n for (;;) {\n const chunk = await waitWithAbort(reader.read(), signal);\n if (chunk.done) {\n text += decoder.decode();\n break;\n }\n const remaining = MAX_ERROR_BODY_BYTES - retainedBytes;\n text += decoder.decode(chunk.value.subarray(0, remaining), { stream: true });\n retainedBytes += Math.min(chunk.value.byteLength, remaining);\n if (chunk.value.byteLength > remaining) {\n truncated = true;\n await reader.cancel(\"HTTP error diagnostic limit exceeded\");\n break;\n }\n }\n } catch (error) {\n readFailure = error;\n if (!truncated) text += decoder.decode();\n void reader.cancel(error).catch(() => {\n // The original diagnostic read failure remains primary.\n });\n } finally {\n if (signal?.aborted) {\n destroyHttpResponse(response);\n void reader.cancel(signal.reason).catch(() => {\n // Caller cancellation remains primary while teardown settles.\n });\n }\n reader.releaseLock();\n }\n response.data = truncated ? text + ERROR_BODY_TRUNCATION : text;\n if (!truncated && readFailure === undefined) {\n try {\n response.data = JSON.parse(text) as unknown;\n } catch {\n response.data = text;\n }\n }\n throwIfAborted(signal);\n return readFailure;\n}\n/**\n * Keeps observed transport resources alive until the returned SSE iterator ends.\n * @param response - SDK response holding the operation's resource lease.\n * @param stream - SDK iterator, which must not start during setup.\n * @returns The iterator with finalization cleanup, or the unchanged unowned iterator.\n */\nexport function withSapStreamCleanup<T>(\n response: NativeStreamResponse,\n stream: AsyncIterable<T>,\n): AsyncIterable<T> {\n if (!streamLeases.has(response)) return stream;\n return iterate();\n\n /**\n * Iterates SDK chunks while releasing the owned transport on every exit.\n * @returns The SDK iterator with finalization cleanup.\n * @yields {T} Each original SDK chunk.\n */\n async function* iterate(): AsyncGenerator<T> {\n try {\n yield* stream;\n } finally {\n releaseSapStream(response);\n }\n }\n}\n\n/**\n * Adapts only failed native bodies; successful SDK SSE ownership stays untouched.\n * @param response - Failed native HTTP response.\n * @returns Byte stream consumed by the shared bounded diagnostic reader.\n */\nfunction createErrorByteStream(response: SAPHttpResponse): ReadableStream<Uint8Array> {\n const body: unknown = response.data;\n if (\n typeof body !== \"object\" ||\n body === null ||\n !(Symbol.asyncIterator in body) ||\n typeof body[Symbol.asyncIterator] !== \"function\"\n ) {\n throw new TypeError(\"SAP did not return a readable HTTP error body.\");\n }\n const iterator = (body as AsyncIterable<unknown>)[Symbol.asyncIterator]();\n const encoder = new TextEncoder();\n return new ReadableStream<Uint8Array>(\n {\n cancel() {\n destroyHttpResponse(response);\n },\n async pull(controller) {\n try {\n const chunk = await iterator.next();\n if (chunk.done) controller.close();\n else if (typeof chunk.value === \"string\") controller.enqueue(encoder.encode(chunk.value));\n else if (chunk.value instanceof Uint8Array) controller.enqueue(chunk.value);\n else throw new TypeError(\"SAP returned a non-byte HTTP error chunk.\");\n } catch (error) {\n try {\n destroyHttpResponse(response);\n } catch {\n // Teardown cannot replace the native HTTP failure or its diagnostics.\n } finally {\n controller.error(error);\n }\n }\n },\n },\n { highWaterMark: 0 },\n );\n}\n/**\n * Identifies a consumed native body whose request may have released its socket.\n * @param body - Original body observed at the transport boundary.\n * @returns Whether the native readable has reached its end.\n */\nfunction isConsumedHttpBody(body: unknown): boolean {\n return (\n typeof body === \"object\" &&\n body !== null &&\n \"readableEnded\" in body &&\n body.readableEnded === true\n );\n}\n/**\n * Identifies the HTTP errors whose response streams need preservation.\n * @param error - Failure reported by the SAP HTTP middleware chain.\n * @returns Whether the failure includes a native Axios response.\n */\nfunction isFailedHttpRequest(error: unknown): error is FailedHttpRequest {\n return (\n error instanceof Error &&\n \"isAxiosError\" in error &&\n error.isAxiosError === true &&\n \"response\" in error &&\n typeof error.response === \"object\" &&\n error.response !== null\n );\n}\n/**\n * Identifies native HTTP requests and response streams without importing Node APIs.\n * @param value - Native object returned by the SAP HTTP client.\n * @returns Whether lifecycle listeners and destruction are supported.\n */\nfunction isHttpResponseEvents(value: unknown): value is HttpResponseEvents {\n return (\n isDestroyableRequest(value) &&\n \"once\" in value &&\n typeof value.once === \"function\" &&\n \"removeListener\" in value &&\n typeof value.removeListener === \"function\"\n );\n}\n/**\n * Releases the transport resources leased to a recovered SDK stream.\n * @param response - SDK response whose iteration has ended or been cancelled.\n */\nfunction releaseSapStream(response: NativeStreamResponse): void {\n const release = streamLeases.get(response);\n streamLeases.delete(response);\n release?.();\n}\n"],"mappings":"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","names":[]}
|