@carlonicora/nestjs-neo4jsonapi 4.0.0 → 4.1.1

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.
@@ -36,6 +36,24 @@
36
36
  * fetch (the OpenRouter pin, the unsupported-parameter repair) rather than
37
37
  * replacing it, and forwards `input`/`init` untouched — it only ever inspects
38
38
  * the response.
39
+ *
40
+ * THE BODY IS READ EXACTLY ONCE, AND NEVER THROUGH `clone()`.
41
+ *
42
+ * `clone()` tees the body stream: the read that follows pulls through BOTH
43
+ * branches, so the original is no longer pristine the moment the clone is read.
44
+ * That is fine until the read FAILS. The OpenAI SDK bounds the whole fetch call
45
+ * — this middleware included — with `AI_REQUEST_TIMEOUT_MS`, and a generation
46
+ * that outruns the budget aborts the stream while we are mid-read. Returning
47
+ * "the original, untouched" then handed the caller a DISTURBED response, whose
48
+ * `.text()` threw undici's `Body is unusable: Body has already been read` and
49
+ * buried the real AbortError. Observed live 2026-08-31 on game creation, where
50
+ * an 88s turn crossed the 120s default (the payload was in `content` all along
51
+ * — this middleware had nothing to repair and still broke the call).
52
+ *
53
+ * So: one read, and a read failure PROPAGATES. The caller owns the timeout and
54
+ * must see its own error. Everything downstream of the read is handed on as a
55
+ * rebuilt Response — a repair is no longer the only path that constructs one,
56
+ * because the single read has consumed the original either way.
39
57
  */
40
58
  export declare function reasoningContentFetch(innerFetch?: typeof fetch): typeof fetch;
41
59
  //# sourceMappingURL=reasoning-content-fetch.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"reasoning-content-fetch.d.ts","sourceRoot":"","sources":["../../../../src/core/llm/services/reasoning-content-fetch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAkFH;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,GAAE,OAAO,KAAa,GAAG,OAAO,KAAK,CA0BpF"}
1
+ {"version":3,"file":"reasoning-content-fetch.d.ts","sourceRoot":"","sources":["../../../../src/core/llm/services/reasoning-content-fetch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAoGH;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,GAAE,OAAO,KAAa,GAAG,OAAO,KAAK,CA0BpF"}
@@ -110,34 +110,68 @@ const promoteReasoningToContent = (body) => {
110
110
  }
111
111
  return changed;
112
112
  };
113
+ /**
114
+ * Re-wraps `text` as the response the caller will read, carrying `source`'s
115
+ * status and headers MINUS the ones that described the wire body.
116
+ *
117
+ * `content-encoding` and `content-length` describe the compressed, chunked
118
+ * bytes undici already decoded on our behalf; the body attached here is decoded
119
+ * text of a different length. Forwarding them would hand the caller a response
120
+ * whose headers contradict its body — and the OpenAI SDK reads `content-length`
121
+ * to decide whether a body is worth parsing at all (`content-length: "0"` short
122
+ * circuits it), so a stale value is not inert.
123
+ */
124
+ const rebuild = (source, text) => {
125
+ const headers = new Headers(source.headers);
126
+ headers.delete("content-encoding");
127
+ headers.delete("content-length");
128
+ return new Response(text, { status: source.status, statusText: source.statusText, headers });
129
+ };
113
130
  /**
114
131
  * A `fetch` middleware that repairs reasoning-only responses. Wraps an inner
115
132
  * fetch (the OpenRouter pin, the unsupported-parameter repair) rather than
116
133
  * replacing it, and forwards `input`/`init` untouched — it only ever inspects
117
134
  * the response.
135
+ *
136
+ * THE BODY IS READ EXACTLY ONCE, AND NEVER THROUGH `clone()`.
137
+ *
138
+ * `clone()` tees the body stream: the read that follows pulls through BOTH
139
+ * branches, so the original is no longer pristine the moment the clone is read.
140
+ * That is fine until the read FAILS. The OpenAI SDK bounds the whole fetch call
141
+ * — this middleware included — with `AI_REQUEST_TIMEOUT_MS`, and a generation
142
+ * that outruns the budget aborts the stream while we are mid-read. Returning
143
+ * "the original, untouched" then handed the caller a DISTURBED response, whose
144
+ * `.text()` threw undici's `Body is unusable: Body has already been read` and
145
+ * buried the real AbortError. Observed live 2026-08-31 on game creation, where
146
+ * an 88s turn crossed the 120s default (the payload was in `content` all along
147
+ * — this middleware had nothing to repair and still broke the call).
148
+ *
149
+ * So: one read, and a read failure PROPAGATES. The caller owns the timeout and
150
+ * must see its own error. Everything downstream of the read is handed on as a
151
+ * rebuilt Response — a repair is no longer the only path that constructs one,
152
+ * because the single read has consumed the original either way.
118
153
  */
119
154
  function reasoningContentFetch(innerFetch = fetch) {
120
155
  return (async (input, init) => {
121
156
  const response = await innerFetch(input, init);
122
157
  if (!response.ok || !isJsonResponse(response))
123
158
  return response;
159
+ // Deliberately unguarded: an abort or a truncated stream is the caller's
160
+ // error to classify, not ours to convert into a body it cannot read.
161
+ const raw = await response.text();
124
162
  let body;
125
163
  try {
126
- body = JSON.parse(await response.clone().text());
164
+ body = JSON.parse(raw);
127
165
  }
128
166
  catch {
129
167
  // Not a JSON document after all (a gateway's HTML error page mislabelled,
130
- // a truncated body) — hand back the original, untouched.
131
- return response;
168
+ // a truncated body) — hand the bytes on exactly as they arrived.
169
+ return rebuild(response, raw);
132
170
  }
133
171
  if (!promoteReasoningToContent(body))
134
- return response;
172
+ return rebuild(response, raw);
135
173
  console.warn("[reasoningContentFetch] provider returned the payload in `reasoning` with empty `content` — promoted it");
136
- return new Response(JSON.stringify(body), {
137
- status: response.status,
138
- statusText: response.statusText,
139
- headers: response.headers,
140
- });
174
+ return rebuild(response, JSON.stringify(body));
141
175
  });
142
176
  }
143
177
  //# sourceMappingURL=reasoning-content-fetch.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"reasoning-content-fetch.js","sourceRoot":"","sources":["../../../../src/core/llm/services/reasoning-content-fetch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"reasoning-content-fetch.js","sourceRoot":"","sources":["../../../../src/core/llm/services/reasoning-content-fetch.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carlonicora/nestjs-neo4jsonapi",
3
- "version": "4.0.0",
3
+ "version": "4.1.1",
4
4
  "description": "NestJS foundation package with JSON:API, Neo4j, Redis, LangChain agents, and common utilities",
5
5
  "author": "Carlo Nicora",
6
6
  "license": "GPL-3.0-or-later",