openai-cache 1.0.25 → 1.0.28
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/dist/openai_cache.d.ts.map +1 -1
- package/dist/openai_cache.js +43 -32
- package/dist/openai_cache.js.map +1 -1
- package/package.json +2 -6
- package/dist/openai_cache copy.d.ts +0 -54
- package/dist/openai_cache copy.js +0 -157
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai_cache.d.ts","sourceRoot":"","sources":["../src/openai_cache.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAUtC,KAAK,OAAO,GAAG,OAAO,UAAU,CAAC,KAAK,CAAC;AACvC,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AACzC,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAExC,KAAK,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;AAelD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,OAAO,OAAO,WAAW;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IACnC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAU;IAC/C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,0BAA0B,CAAkB;IACpD,gBAAuB,gBAAgB,yBAAyB;IAEhE;;;;;;;OAOG;gBACS,KAAK,CAAC,EAAE,SAAS,EAAE,EAC9B,mBAA2B,EAC3B,YAAgB,GAChB,GAAE;QACF,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,YAAY,CAAC,EAAE,MAAM,CAAA;KAChB;IAMN;;OAEG;IACU,UAAU;IAIvB;;;;;;;;OAQG;IACI,UAAU,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,SAAS,KAAK,OAAO,CAAC,aAAa,CAAC;IAIpF;;;;;;OAMG;YACW,MAAM;
|
|
1
|
+
{"version":3,"file":"openai_cache.d.ts","sourceRoot":"","sources":["../src/openai_cache.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAUtC,KAAK,OAAO,GAAG,OAAO,UAAU,CAAC,KAAK,CAAC;AACvC,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AACzC,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAExC,KAAK,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;AAelD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,OAAO,OAAO,WAAW;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IACnC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAU;IAC/C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,0BAA0B,CAAkB;IACpD,gBAAuB,gBAAgB,yBAAyB;IAEhE;;;;;;;OAOG;gBACS,KAAK,CAAC,EAAE,SAAS,EAAE,EAC9B,mBAA2B,EAC3B,YAAgB,GAChB,GAAE;QACF,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,YAAY,CAAC,EAAE,MAAM,CAAA;KAChB;IAMN;;OAEG;IACU,UAAU;IAIvB;;;;;;;;OAQG;IACI,UAAU,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,SAAS,KAAK,OAAO,CAAC,aAAa,CAAC;IAIpF;;;;;;OAMG;YACW,MAAM;IAgJpB;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,4BAA4B;IAwC3C;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAehC,OAAO,CAAC,MAAM,CAAC,oBAAoB;IASnC,OAAO,CAAC,MAAM,CAAC,qBAAqB;CAmBpC"}
|
package/dist/openai_cache.js
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
1
|
// node imports
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
import Crypto from "node:crypto";
|
|
3
|
+
import { Buffer } from "node:buffer";
|
|
4
|
+
import { Cacheable } from "cacheable";
|
|
5
|
+
import Chalk from "chalk";
|
|
11
6
|
///////////////////////////////////////////////////////////////////////////////
|
|
12
7
|
///////////////////////////////////////////////////////////////////////////////
|
|
13
8
|
// OpenAICache
|
|
@@ -34,7 +29,7 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
34
29
|
* });
|
|
35
30
|
* ```
|
|
36
31
|
*/
|
|
37
|
-
class OpenAICache {
|
|
32
|
+
export default class OpenAICache {
|
|
38
33
|
_cache;
|
|
39
34
|
_markResponseEnabled;
|
|
40
35
|
_verboseLevel;
|
|
@@ -49,7 +44,7 @@ class OpenAICache {
|
|
|
49
44
|
* the original response body so it is optional. so the response is { X_FROM_OPENAI_CACHE: true, ...originalResponseBody }
|
|
50
45
|
*/
|
|
51
46
|
constructor(cache, { markResponseEnabled = false, verboseLevel = 0, } = {}) {
|
|
52
|
-
this._cache = cache ?? new
|
|
47
|
+
this._cache = cache ?? new Cacheable();
|
|
53
48
|
this._markResponseEnabled = markResponseEnabled;
|
|
54
49
|
this._verboseLevel = verboseLevel;
|
|
55
50
|
}
|
|
@@ -83,44 +78,58 @@ class OpenAICache {
|
|
|
83
78
|
const url = typeof input === "string" ? input : input instanceof Request ? input.url : input.toString();
|
|
84
79
|
// Normalize HTTP method
|
|
85
80
|
const method = (init?.method || "GET").toUpperCase();
|
|
86
|
-
// debugger
|
|
87
81
|
// Generate body hash payload
|
|
88
82
|
const bodyForHash = OpenAICache._serializeBodyForHash(init?.body);
|
|
89
83
|
// If body type unsupported, skip caching
|
|
90
84
|
if (bodyForHash === null) {
|
|
91
85
|
if (this._verboseLevel > 1) {
|
|
92
|
-
console.warn(
|
|
86
|
+
console.warn(Chalk.yellow(`Skipping cache for ${method} ${url} due to unsupported body type`));
|
|
93
87
|
}
|
|
94
88
|
return fetch(input, init);
|
|
95
89
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
90
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
91
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
92
|
+
//
|
|
93
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
94
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
101
95
|
// Log a warning if cache is disabled via environment variable, but only once to avoid spamming the console
|
|
102
96
|
if (process.env.OPENAI_CACHE === "disabled" && this.disabledCacheWarningLogged === false) {
|
|
103
97
|
if (this._verboseLevel > 0) {
|
|
104
|
-
console.warn(
|
|
98
|
+
console.warn(Chalk.red("OpenAI cache is disabled via OPENAI_CACHE=disabled. All requests will be live and no caching will occur."));
|
|
105
99
|
}
|
|
106
100
|
this.disabledCacheWarningLogged = true;
|
|
107
101
|
}
|
|
102
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
103
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
104
|
+
//
|
|
105
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
106
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
107
|
+
// Build cache key and file path
|
|
108
|
+
const cacheKey = Crypto.createHash("sha256")
|
|
109
|
+
.update(`${method}:${url}:${bodyForHash}`)
|
|
110
|
+
.digest("hex");
|
|
111
|
+
// console.log("cacheKey", cacheKey, bodyForHash);
|
|
108
112
|
const cachedValue = await this._cache.get(cacheKey);
|
|
109
113
|
if (cachedValue !== undefined && process.env.OPENAI_CACHE !== "disabled") {
|
|
110
114
|
const bodyEncoding = cachedValue.bodyEncoding ?? "utf8";
|
|
111
|
-
const cachedBodyBuffer =
|
|
115
|
+
const cachedBodyBuffer = Buffer.from(cachedValue.body, bodyEncoding);
|
|
112
116
|
// For streaming SSE responses, return directly without JSON modification
|
|
113
117
|
if (OpenAICache._isStreamingResponse(cachedValue.headers)) {
|
|
114
118
|
if (this._verboseLevel > 1) {
|
|
115
|
-
console.log(
|
|
119
|
+
console.log(Chalk.green(`Cache hit for streamed ${method} ${url}`));
|
|
116
120
|
}
|
|
117
|
-
|
|
121
|
+
const newResponse = new Response(cachedBodyBuffer, {
|
|
118
122
|
status: cachedValue.status,
|
|
119
123
|
headers: cachedValue.headers,
|
|
120
124
|
});
|
|
125
|
+
if (this._markResponseEnabled) {
|
|
126
|
+
newResponse.headers.set(OpenAICache.MarkResponseName, "true");
|
|
127
|
+
console.log(Chalk.blue(`Marking cached response with header`), Array.from(newResponse.headers.entries()));
|
|
128
|
+
}
|
|
129
|
+
return newResponse;
|
|
121
130
|
}
|
|
122
131
|
if (this._verboseLevel > 1) {
|
|
123
|
-
console.log(
|
|
132
|
+
console.log(Chalk.green(`Cache hit for non-streamed ${method} ${url}`));
|
|
124
133
|
}
|
|
125
134
|
// Return cached response
|
|
126
135
|
let newResponse = new Response(cachedBodyBuffer, {
|
|
@@ -130,13 +139,16 @@ class OpenAICache {
|
|
|
130
139
|
// honor this._markResponseEnabled option to indicate cache hit
|
|
131
140
|
const contentTypeIsJson = newResponse.headers.get("content-type")?.includes("application/json") ? true : false;
|
|
132
141
|
if (this._markResponseEnabled && contentTypeIsJson) {
|
|
142
|
+
newResponse.headers.set(OpenAICache.MarkResponseName, "true");
|
|
143
|
+
console.log(Chalk.blue(`Marking cached response with header`), Array.from(newResponse.headers.entries()));
|
|
144
|
+
// TODO remove the 'MARKER in body json'
|
|
133
145
|
try {
|
|
134
146
|
// decode JSON from cachedBodyBuffer
|
|
135
147
|
const bodyJson = JSON.parse(cachedBodyBuffer.toString());
|
|
136
148
|
// Set the magic property to indicate this response is from cache
|
|
137
149
|
bodyJson.X_FROM_OPENAI_CACHE = true;
|
|
138
150
|
// Rebuild response with modified body
|
|
139
|
-
const modifiedBodyBuffer =
|
|
151
|
+
const modifiedBodyBuffer = Buffer.from(JSON.stringify(bodyJson));
|
|
140
152
|
newResponse = new Response(modifiedBodyBuffer, { status: cachedValue.status, headers: cachedValue.headers, });
|
|
141
153
|
}
|
|
142
154
|
catch (error) {
|
|
@@ -152,7 +164,7 @@ class OpenAICache {
|
|
|
152
164
|
// For streaming SSE responses, pipe through to enable progressive streaming + background caching
|
|
153
165
|
if (OpenAICache._isStreamingResponse(response.headers)) {
|
|
154
166
|
if (this._verboseLevel > 1) {
|
|
155
|
-
console.log(
|
|
167
|
+
console.log(Chalk.yellow(`Cache miss for streamed ${method} ${url} - caching in background as it streams in`));
|
|
156
168
|
}
|
|
157
169
|
if (!response.ok || !response.body) {
|
|
158
170
|
return response;
|
|
@@ -160,11 +172,11 @@ class OpenAICache {
|
|
|
160
172
|
return OpenAICache._createCachingStreamResponse(response, this._cache, cacheKey);
|
|
161
173
|
}
|
|
162
174
|
if (this._verboseLevel > 1) {
|
|
163
|
-
console.log(
|
|
175
|
+
console.log(Chalk.yellow(`Cache miss for non-streamed ${method} ${url} - caching in background`));
|
|
164
176
|
}
|
|
165
177
|
const clonedResponse = response.clone();
|
|
166
178
|
// Materialize response body for caching
|
|
167
|
-
const responseBuffer =
|
|
179
|
+
const responseBuffer = Buffer.from(await clonedResponse.arrayBuffer());
|
|
168
180
|
// Collect headers and normalize them
|
|
169
181
|
const headers = Array.from(clonedResponse.headers.entries());
|
|
170
182
|
const normalizedHeaders = OpenAICache._normalizeHeaders(headers, responseBuffer.length);
|
|
@@ -198,7 +210,7 @@ class OpenAICache {
|
|
|
198
210
|
const { done, value } = await reader.read();
|
|
199
211
|
if (done) {
|
|
200
212
|
controller.close();
|
|
201
|
-
const fullBody =
|
|
213
|
+
const fullBody = Buffer.concat(chunks);
|
|
202
214
|
const normalizedHeaders = OpenAICache._normalizeHeaders(responseHeaders, fullBody.length);
|
|
203
215
|
cache.set(cacheKey, {
|
|
204
216
|
status: responseStatus,
|
|
@@ -253,17 +265,16 @@ class OpenAICache {
|
|
|
253
265
|
if (typeof body === "string")
|
|
254
266
|
return body;
|
|
255
267
|
// Handle Buffer body
|
|
256
|
-
if (
|
|
268
|
+
if (Buffer.isBuffer(body))
|
|
257
269
|
return body.toString("base64");
|
|
258
270
|
// Handle ArrayBuffer body
|
|
259
271
|
if (body instanceof ArrayBuffer)
|
|
260
|
-
return
|
|
272
|
+
return Buffer.from(body).toString("base64");
|
|
261
273
|
// Handle typed arrays (Uint8Array, Int8Array, etc.)
|
|
262
274
|
if (ArrayBuffer.isView(body))
|
|
263
|
-
return
|
|
275
|
+
return Buffer.from(body.buffer, body.byteOffset, body.byteLength).toString("base64");
|
|
264
276
|
// Return null for unsupported body types to skip caching
|
|
265
277
|
return null;
|
|
266
278
|
}
|
|
267
279
|
}
|
|
268
|
-
exports.default = OpenAICache;
|
|
269
280
|
//# sourceMappingURL=openai_cache.js.map
|
package/dist/openai_cache.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai_cache.js","sourceRoot":"","sources":["../src/openai_cache.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"openai_cache.js","sourceRoot":"","sources":["../src/openai_cache.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openai-cache",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.28",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/openai_cache.js",
|
|
6
6
|
"types": "dist/openai_cache.d.ts",
|
|
@@ -27,11 +27,7 @@
|
|
|
27
27
|
"prepublishOnly": "npm run test && npm run build",
|
|
28
28
|
"test": "tsx --test ./test/*_test.ts",
|
|
29
29
|
"test:watch": "tsx --test --watch ./test/*_test.ts",
|
|
30
|
-
"publish:all": "npm run build && npm
|
|
31
|
-
"version:patch": "npm version patch",
|
|
32
|
-
"version:minor": "npm version minor",
|
|
33
|
-
"version:major": "npm version major",
|
|
34
|
-
"version:prerelease": "npm version prerelease --preid=rc"
|
|
30
|
+
"publish:all": "npm run build && npm version patch && npm publish --access public"
|
|
35
31
|
},
|
|
36
32
|
"keywords": [
|
|
37
33
|
"openai",
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { Cacheable } from "cacheable";
|
|
2
|
-
type FetchFn = typeof globalThis.fetch;
|
|
3
|
-
type FetchInput = Parameters<FetchFn>[0];
|
|
4
|
-
type FetchInit = Parameters<FetchFn>[1];
|
|
5
|
-
type FetchResponse = Awaited<ReturnType<FetchFn>>;
|
|
6
|
-
/**
|
|
7
|
-
* OpenAICachingCacheable is a wrapper around the Fetch API that adds caching capabilities for OpenAI requests.
|
|
8
|
-
* It uses a Cacheable instance to store and retrieve cached responses based on a hash of the request details.
|
|
9
|
-
*/
|
|
10
|
-
export default class OpenAICache {
|
|
11
|
-
private readonly _cache;
|
|
12
|
-
private readonly _markResponseEnabled;
|
|
13
|
-
static readonly MarkResponseName = "X_FROM_OPENAI_CACHE";
|
|
14
|
-
/**
|
|
15
|
-
* Creates a new instance of OpenAICache.
|
|
16
|
-
*
|
|
17
|
-
* @param cache cacheable instance
|
|
18
|
-
* @param options.markResponseEnabled whether to mark cached responses with an additional property in the JSON body (default: true).
|
|
19
|
-
* This can be useful for downstream logic that needs to differentiate between live and cached responses, but it does modify
|
|
20
|
-
* the original response body so it is optional. so the response is { X_FROM_OPENAI_CACHE: true, ...originalResponseBody }
|
|
21
|
-
*/
|
|
22
|
-
constructor(cache?: Cacheable, { markResponseEnabled }?: {
|
|
23
|
-
markResponseEnabled?: boolean;
|
|
24
|
-
});
|
|
25
|
-
/**
|
|
26
|
-
* Cleans the OpenAI cache by deleting all cached values.
|
|
27
|
-
*/
|
|
28
|
-
cleanCache(): Promise<void>;
|
|
29
|
-
/**
|
|
30
|
-
* return a fetch function that can be passed to OpenAI client for caching support
|
|
31
|
-
*
|
|
32
|
-
* ```js
|
|
33
|
-
* const openai = new OpenAI({
|
|
34
|
-
* fetch: openaiCache.getFetchFn()
|
|
35
|
-
* });
|
|
36
|
-
* ```
|
|
37
|
-
*/
|
|
38
|
-
getFetchFn(): (input: FetchInput, init?: FetchInit) => Promise<FetchResponse>;
|
|
39
|
-
/**
|
|
40
|
-
* This is the fetch() implementation that adds caching for OpenAI requests.
|
|
41
|
-
*
|
|
42
|
-
* @param input The resource that you wish to fetch.
|
|
43
|
-
* @param init An options object containing any custom settings that you want to apply to the request.
|
|
44
|
-
* @returns A Promise that resolves to the Response to that request.
|
|
45
|
-
*/
|
|
46
|
-
private _fetch;
|
|
47
|
-
/**
|
|
48
|
-
* Remove transfer/content encodings that no longer apply once the body is materialized
|
|
49
|
-
* and optionally set a correct content-length for the cached payload.
|
|
50
|
-
*/
|
|
51
|
-
private static _normalizeHeaders;
|
|
52
|
-
private static _serializeBodyForHash;
|
|
53
|
-
}
|
|
54
|
-
export {};
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
// node imports
|
|
7
|
-
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
8
|
-
const node_buffer_1 = require("node:buffer");
|
|
9
|
-
const cacheable_1 = require("cacheable");
|
|
10
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
11
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
12
|
-
// OpenAICache
|
|
13
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
14
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
15
|
-
/**
|
|
16
|
-
* OpenAICachingCacheable is a wrapper around the Fetch API that adds caching capabilities for OpenAI requests.
|
|
17
|
-
* It uses a Cacheable instance to store and retrieve cached responses based on a hash of the request details.
|
|
18
|
-
*/
|
|
19
|
-
class OpenAICache {
|
|
20
|
-
/**
|
|
21
|
-
* Creates a new instance of OpenAICache.
|
|
22
|
-
*
|
|
23
|
-
* @param cache cacheable instance
|
|
24
|
-
* @param options.markResponseEnabled whether to mark cached responses with an additional property in the JSON body (default: true).
|
|
25
|
-
* This can be useful for downstream logic that needs to differentiate between live and cached responses, but it does modify
|
|
26
|
-
* the original response body so it is optional. so the response is { X_FROM_OPENAI_CACHE: true, ...originalResponseBody }
|
|
27
|
-
*/
|
|
28
|
-
constructor(cache, { markResponseEnabled = false } = {}) {
|
|
29
|
-
this._cache = cache !== null && cache !== void 0 ? cache : new cacheable_1.Cacheable();
|
|
30
|
-
this._markResponseEnabled = markResponseEnabled;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Cleans the OpenAI cache by deleting all cached values.
|
|
34
|
-
*/
|
|
35
|
-
async cleanCache() {
|
|
36
|
-
await this._cache.clear();
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* return a fetch function that can be passed to OpenAI client for caching support
|
|
40
|
-
*
|
|
41
|
-
* ```js
|
|
42
|
-
* const openai = new OpenAI({
|
|
43
|
-
* fetch: openaiCache.getFetchFn()
|
|
44
|
-
* });
|
|
45
|
-
* ```
|
|
46
|
-
*/
|
|
47
|
-
getFetchFn() {
|
|
48
|
-
return this._fetch.bind(this);
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* This is the fetch() implementation that adds caching for OpenAI requests.
|
|
52
|
-
*
|
|
53
|
-
* @param input The resource that you wish to fetch.
|
|
54
|
-
* @param init An options object containing any custom settings that you want to apply to the request.
|
|
55
|
-
* @returns A Promise that resolves to the Response to that request.
|
|
56
|
-
*/
|
|
57
|
-
async _fetch(input, init) {
|
|
58
|
-
var _a, _b;
|
|
59
|
-
// Extract the URL from the input (string or Request)
|
|
60
|
-
const url = typeof input === "string" ? input : input instanceof Request ? input.url : input.toString();
|
|
61
|
-
// Normalize HTTP method
|
|
62
|
-
const method = ((init === null || init === void 0 ? void 0 : init.method) || "GET").toUpperCase();
|
|
63
|
-
// Generate body hash payload
|
|
64
|
-
const bodyForHash = OpenAICache._serializeBodyForHash(init === null || init === void 0 ? void 0 : init.body);
|
|
65
|
-
// If body type unsupported, skip caching
|
|
66
|
-
if (bodyForHash === null)
|
|
67
|
-
return fetch(input, init);
|
|
68
|
-
// Build cache key and file path
|
|
69
|
-
const cacheKey = node_crypto_1.default.createHash("sha256")
|
|
70
|
-
.update(`${method}:${url}:${bodyForHash}`)
|
|
71
|
-
.digest("hex");
|
|
72
|
-
const cached = (await this._cache.get(cacheKey));
|
|
73
|
-
if (cached !== undefined && process.env.OPENAI_CACHE !== "disabled") {
|
|
74
|
-
const bodyEncoding = (_a = cached.bodyEncoding) !== null && _a !== void 0 ? _a : "utf8";
|
|
75
|
-
const cachedBodyBuffer = node_buffer_1.Buffer.from(cached.body, bodyEncoding);
|
|
76
|
-
// Return cached response
|
|
77
|
-
let newResponse = new Response(cachedBodyBuffer, {
|
|
78
|
-
status: cached.status,
|
|
79
|
-
headers: cached.headers,
|
|
80
|
-
});
|
|
81
|
-
// honor this._markResponseEnabled option to indicate cache hit
|
|
82
|
-
const contentTypeIsJson = ((_b = newResponse.headers.get("content-type")) === null || _b === void 0 ? void 0 : _b.includes("application/json")) ? true : false;
|
|
83
|
-
if (this._markResponseEnabled && contentTypeIsJson) {
|
|
84
|
-
try {
|
|
85
|
-
// decode JSON from cachedBodyBuffer
|
|
86
|
-
const bodyJson = JSON.parse(cachedBodyBuffer.toString());
|
|
87
|
-
// Set the magic property to indicate this response is from cache
|
|
88
|
-
bodyJson.X_FROM_OPENAI_CACHE = true;
|
|
89
|
-
// Rebuild response with modified body
|
|
90
|
-
const modifiedBodyBuffer = node_buffer_1.Buffer.from(JSON.stringify(bodyJson));
|
|
91
|
-
newResponse = new Response(modifiedBodyBuffer, { status: cached.status, headers: cached.headers, });
|
|
92
|
-
}
|
|
93
|
-
catch (error) {
|
|
94
|
-
// If parsing fails, return the original cached response without modification
|
|
95
|
-
console.warn("Failed to parse cached response body as JSON for header modification:", error);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
// Return cached response (body already buffered)
|
|
99
|
-
return newResponse;
|
|
100
|
-
}
|
|
101
|
-
// Perform network fetch
|
|
102
|
-
const response = await fetch(input, init);
|
|
103
|
-
const clonedResponse = response.clone();
|
|
104
|
-
// Materialize response body for caching
|
|
105
|
-
const responseBuffer = node_buffer_1.Buffer.from(await clonedResponse.arrayBuffer());
|
|
106
|
-
// Collect headers and normalize them
|
|
107
|
-
const headers = Array.from(clonedResponse.headers.entries());
|
|
108
|
-
const normalizedHeaders = OpenAICache._normalizeHeaders(headers, responseBuffer.length);
|
|
109
|
-
if (response.ok) {
|
|
110
|
-
await this._cache.set(cacheKey, {
|
|
111
|
-
status: clonedResponse.status,
|
|
112
|
-
headers: normalizedHeaders,
|
|
113
|
-
body: responseBuffer.toString("base64"),
|
|
114
|
-
bodyEncoding: "base64",
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
// Return live response (body already buffered)
|
|
118
|
-
return new Response(responseBuffer, { status: response.status, headers: normalizedHeaders });
|
|
119
|
-
}
|
|
120
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
121
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
122
|
-
// Private functions
|
|
123
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
124
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
125
|
-
/**
|
|
126
|
-
* Remove transfer/content encodings that no longer apply once the body is materialized
|
|
127
|
-
* and optionally set a correct content-length for the cached payload.
|
|
128
|
-
*/
|
|
129
|
-
static _normalizeHeaders(headers, bodyLength) {
|
|
130
|
-
const drop = new Set([
|
|
131
|
-
"content-encoding", // body is already decoded by fetch()
|
|
132
|
-
"transfer-encoding",
|
|
133
|
-
"content-length", // will be recalculated
|
|
134
|
-
]);
|
|
135
|
-
const filtered = headers.filter(([name]) => drop.has(name.toLowerCase()) === false);
|
|
136
|
-
if (bodyLength !== undefined) {
|
|
137
|
-
filtered.push(["content-length", String(bodyLength)]);
|
|
138
|
-
}
|
|
139
|
-
return filtered;
|
|
140
|
-
}
|
|
141
|
-
// Serialize body into a deterministic string for hashing
|
|
142
|
-
static _serializeBodyForHash(body) {
|
|
143
|
-
if (body === undefined || body === null)
|
|
144
|
-
return "";
|
|
145
|
-
if (typeof body === "string")
|
|
146
|
-
return body;
|
|
147
|
-
if (node_buffer_1.Buffer.isBuffer(body))
|
|
148
|
-
return body.toString("base64");
|
|
149
|
-
if (body instanceof ArrayBuffer)
|
|
150
|
-
return node_buffer_1.Buffer.from(body).toString("base64");
|
|
151
|
-
if (ArrayBuffer.isView(body))
|
|
152
|
-
return node_buffer_1.Buffer.from(body.buffer, body.byteOffset, body.byteLength).toString("base64");
|
|
153
|
-
return null; // unsupported body type
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
OpenAICache.MarkResponseName = "X_FROM_OPENAI_CACHE";
|
|
157
|
-
exports.default = OpenAICache;
|