@effect-native/fetch-hooks 0.0.2 → 0.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/LICENSE
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
4
|
-
Copyright (c) 2025 effect-native contributors (modifications and packages-native/)
|
|
3
|
+
Copyright (c) 2025 effect-native contributors
|
|
5
4
|
|
|
6
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
6
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -1,6 +1,38 @@
|
|
|
1
|
-
import type { CacheKey, CacheStorage, KV, KVStream, TimedChunk } from "./types.js";
|
|
1
|
+
import type { CachedRequest, CacheKey, CacheStorage, KV, KVStream, TimedChunk } from "./types.js";
|
|
2
2
|
/** Create a KV store backed by JSON files */
|
|
3
3
|
export declare function createJsonFileKV<T>(baseDir: string, filename: string): KV<CacheKey, T>;
|
|
4
|
+
/**
|
|
5
|
+
* Creates a KV store for HTTP requests that extracts inline base64 data URLs
|
|
6
|
+
* to sidecar files on disk and restores them when reading from the cache.
|
|
7
|
+
*
|
|
8
|
+
* @param baseDir - Base directory where cache entries are stored.
|
|
9
|
+
* @param filename - File name used to persist the cached request JSON.
|
|
10
|
+
* @returns A KV implementation keyed by CacheKey storing CachedRequest values.
|
|
11
|
+
* @since 1.0.0
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* const kv = createRequestFileKV(".cache", "request.json")
|
|
15
|
+
* await kv.set(["some-cache-key"], cachedRequest)
|
|
16
|
+
* const value = await kv.get(["some-cache-key"])
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function createRequestFileKV(baseDir: string, filename: string): KV<CacheKey, CachedRequest>;
|
|
20
|
+
/**
|
|
21
|
+
* Creates a KV store for text files that extracts inline base64 data URLs into
|
|
22
|
+
* sidecar asset files on disk and restores them when reading.
|
|
23
|
+
*
|
|
24
|
+
* @param baseDir - Base directory where cache entries are stored.
|
|
25
|
+
* @param filename - File name used for the cached text content within each cache key directory.
|
|
26
|
+
* @returns A KV store keyed by CacheKey that reads and writes text content from the filesystem.
|
|
27
|
+
* @since 1.0.0
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* const kv = createTextFileKV("/tmp/fetch-hooks-cache", "response.txt")
|
|
31
|
+
* await kv.set(["my-cache-key"], "inline data: data:image/png;base64,...")
|
|
32
|
+
* const value = await kv.get(["my-cache-key"])
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare function createTextFileKV(baseDir: string, filename: string): KV<CacheKey, string>;
|
|
4
36
|
/** Create a KV store backed by binary files */
|
|
5
37
|
export declare function createBinaryFileKV(baseDir: string, filename: string): KV<CacheKey, Uint8Array>;
|
|
6
38
|
/** Create a streaming KV store for SSE chunks backed by JSONL files */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filesystem-storage.d.ts","sourceRoot":"","sources":["../src/filesystem-storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"filesystem-storage.d.ts","sourceRoot":"","sources":["../src/filesystem-storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAsB,QAAQ,EAAE,YAAY,EAAE,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAsBrH,6CAA6C;AAC7C,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,CAsBtF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,CA2BlG;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,CA0BxF;AAED,+CAA+C;AAC/C,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,EAAE,CAAC,QAAQ,EAAE,UAAU,CAAC,CAsB9F;AAED,uEAAuE;AACvE,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,CAyCzG;AAED,8DAA8D;AAC9D,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,CAQrE"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
+
import { extractDataUrls, restoreDataUrls } from "./binary-extractor.js";
|
|
3
4
|
import { jsonlToTimedChunks, timedChunksToJsonl } from "./sse-handler.js";
|
|
4
5
|
function ensureCacheDir(baseDir, cacheKey) {
|
|
5
6
|
const cacheDir = join(baseDir, cacheKey);
|
|
@@ -38,6 +39,85 @@ export function createJsonFileKV(baseDir, filename) {
|
|
|
38
39
|
}
|
|
39
40
|
};
|
|
40
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Creates a KV store for HTTP requests that extracts inline base64 data URLs
|
|
44
|
+
* to sidecar files on disk and restores them when reading from the cache.
|
|
45
|
+
*
|
|
46
|
+
* @param baseDir - Base directory where cache entries are stored.
|
|
47
|
+
* @param filename - File name used to persist the cached request JSON.
|
|
48
|
+
* @returns A KV implementation keyed by CacheKey storing CachedRequest values.
|
|
49
|
+
* @since 1.0.0
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* const kv = createRequestFileKV(".cache", "request.json")
|
|
53
|
+
* await kv.set(["some-cache-key"], cachedRequest)
|
|
54
|
+
* const value = await kv.get(["some-cache-key"])
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export function createRequestFileKV(baseDir, filename) {
|
|
58
|
+
const assetsExt = ".assets";
|
|
59
|
+
return {
|
|
60
|
+
async get([key]) {
|
|
61
|
+
const filePath = join(baseDir, key, filename);
|
|
62
|
+
if (!existsSync(filePath)) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
const assetsDir = join(baseDir, key, filename + assetsExt);
|
|
66
|
+
const content = restoreDataUrls(readFileSync(filePath, "utf-8"), assetsDir);
|
|
67
|
+
return JSON.parse(content);
|
|
68
|
+
},
|
|
69
|
+
async set([key], value) {
|
|
70
|
+
const cacheDir = ensureCacheDir(baseDir, key);
|
|
71
|
+
const filePath = join(cacheDir, filename);
|
|
72
|
+
const assetsDir = join(cacheDir, filename + assetsExt);
|
|
73
|
+
const { content } = extractDataUrls(JSON.stringify(value, null, 2), assetsDir);
|
|
74
|
+
writeFileSync(filePath, content, "utf-8");
|
|
75
|
+
},
|
|
76
|
+
async has([key]) {
|
|
77
|
+
const filePath = join(baseDir, key, filename);
|
|
78
|
+
return existsSync(filePath);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Creates a KV store for text files that extracts inline base64 data URLs into
|
|
84
|
+
* sidecar asset files on disk and restores them when reading.
|
|
85
|
+
*
|
|
86
|
+
* @param baseDir - Base directory where cache entries are stored.
|
|
87
|
+
* @param filename - File name used for the cached text content within each cache key directory.
|
|
88
|
+
* @returns A KV store keyed by CacheKey that reads and writes text content from the filesystem.
|
|
89
|
+
* @since 1.0.0
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* const kv = createTextFileKV("/tmp/fetch-hooks-cache", "response.txt")
|
|
93
|
+
* await kv.set(["my-cache-key"], "inline data: data:image/png;base64,...")
|
|
94
|
+
* const value = await kv.get(["my-cache-key"])
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
export function createTextFileKV(baseDir, filename) {
|
|
98
|
+
const assetsExt = ".assets";
|
|
99
|
+
return {
|
|
100
|
+
async get([key]) {
|
|
101
|
+
const filePath = join(baseDir, key, filename);
|
|
102
|
+
if (!existsSync(filePath)) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
const assetsDir = join(baseDir, key, filename + assetsExt);
|
|
106
|
+
return restoreDataUrls(readFileSync(filePath, "utf-8"), assetsDir);
|
|
107
|
+
},
|
|
108
|
+
async set([key], value) {
|
|
109
|
+
const cacheDir = ensureCacheDir(baseDir, key);
|
|
110
|
+
const filePath = join(cacheDir, filename);
|
|
111
|
+
const assetsDir = join(cacheDir, filename + assetsExt);
|
|
112
|
+
const { content } = extractDataUrls(value, assetsDir);
|
|
113
|
+
writeFileSync(filePath, content, "utf-8");
|
|
114
|
+
},
|
|
115
|
+
async has([key]) {
|
|
116
|
+
const filePath = join(baseDir, key, filename);
|
|
117
|
+
return existsSync(filePath);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
}
|
|
41
121
|
/** Create a KV store backed by binary files */
|
|
42
122
|
export function createBinaryFileKV(baseDir, filename) {
|
|
43
123
|
return {
|
|
@@ -102,9 +182,9 @@ export function createJsonlFileKVStream(baseDir, filename) {
|
|
|
102
182
|
/** Create a complete CacheStorage backed by the filesystem */
|
|
103
183
|
export function createFilesystemStorage(baseDir) {
|
|
104
184
|
return {
|
|
105
|
-
requests:
|
|
185
|
+
requests: createRequestFileKV(baseDir, "request.json"),
|
|
106
186
|
responseMeta: createJsonFileKV(baseDir, "response.meta.json"),
|
|
107
|
-
responseBody:
|
|
187
|
+
responseBody: createTextFileKV(baseDir, "response.json"),
|
|
108
188
|
binaryBody: createBinaryFileKV(baseDir, "response.bin"),
|
|
109
189
|
sseChunks: createJsonlFileKVStream(baseDir, "response.jsonl")
|
|
110
190
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filesystem-storage.js","sourceRoot":"","sources":["../src/filesystem-storage.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"filesystem-storage.js","sourceRoot":"","sources":["../src/filesystem-storage.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect-native/fetch-hooks",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Fetch caching utilities for deterministic API replay",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"node": ">=18"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@types/node": "^22.
|
|
39
|
+
"@types/node": "^22.19.3"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"bun": ">=1.0.0"
|
|
@@ -2,6 +2,7 @@ import type { CachedRequest, CachedResponseMeta, CacheKey, CacheStorage, KV, KVS
|
|
|
2
2
|
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"
|
|
4
4
|
import { join } from "node:path"
|
|
5
|
+
import { extractDataUrls, restoreDataUrls } from "./binary-extractor.js"
|
|
5
6
|
import { jsonlToTimedChunks, timedChunksToJsonl } from "./sse-handler.js"
|
|
6
7
|
|
|
7
8
|
function ensureCacheDir(baseDir: string, cacheKey: string): string {
|
|
@@ -44,6 +45,93 @@ export function createJsonFileKV<T>(baseDir: string, filename: string): KV<Cache
|
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Creates a KV store for HTTP requests that extracts inline base64 data URLs
|
|
50
|
+
* to sidecar files on disk and restores them when reading from the cache.
|
|
51
|
+
*
|
|
52
|
+
* @param baseDir - Base directory where cache entries are stored.
|
|
53
|
+
* @param filename - File name used to persist the cached request JSON.
|
|
54
|
+
* @returns A KV implementation keyed by CacheKey storing CachedRequest values.
|
|
55
|
+
* @since 1.0.0
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* const kv = createRequestFileKV(".cache", "request.json")
|
|
59
|
+
* await kv.set(["some-cache-key"], cachedRequest)
|
|
60
|
+
* const value = await kv.get(["some-cache-key"])
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export function createRequestFileKV(baseDir: string, filename: string): KV<CacheKey, CachedRequest> {
|
|
64
|
+
const assetsExt = ".assets"
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
async get([key]: CacheKey): Promise<CachedRequest | null> {
|
|
68
|
+
const filePath = join(baseDir, key, filename)
|
|
69
|
+
if (!existsSync(filePath)) {
|
|
70
|
+
return null
|
|
71
|
+
}
|
|
72
|
+
const assetsDir = join(baseDir, key, filename + assetsExt)
|
|
73
|
+
const content = restoreDataUrls(readFileSync(filePath, "utf-8"), assetsDir)
|
|
74
|
+
return JSON.parse(content) as CachedRequest
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
async set([key]: CacheKey, value: CachedRequest): Promise<void> {
|
|
78
|
+
const cacheDir = ensureCacheDir(baseDir, key)
|
|
79
|
+
const filePath = join(cacheDir, filename)
|
|
80
|
+
const assetsDir = join(cacheDir, filename + assetsExt)
|
|
81
|
+
const { content } = extractDataUrls(JSON.stringify(value, null, 2), assetsDir)
|
|
82
|
+
writeFileSync(filePath, content, "utf-8")
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
async has([key]: CacheKey): Promise<boolean> {
|
|
86
|
+
const filePath = join(baseDir, key, filename)
|
|
87
|
+
return existsSync(filePath)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Creates a KV store for text files that extracts inline base64 data URLs into
|
|
94
|
+
* sidecar asset files on disk and restores them when reading.
|
|
95
|
+
*
|
|
96
|
+
* @param baseDir - Base directory where cache entries are stored.
|
|
97
|
+
* @param filename - File name used for the cached text content within each cache key directory.
|
|
98
|
+
* @returns A KV store keyed by CacheKey that reads and writes text content from the filesystem.
|
|
99
|
+
* @since 1.0.0
|
|
100
|
+
* @example
|
|
101
|
+
* ```ts
|
|
102
|
+
* const kv = createTextFileKV("/tmp/fetch-hooks-cache", "response.txt")
|
|
103
|
+
* await kv.set(["my-cache-key"], "inline data: data:image/png;base64,...")
|
|
104
|
+
* const value = await kv.get(["my-cache-key"])
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
export function createTextFileKV(baseDir: string, filename: string): KV<CacheKey, string> {
|
|
108
|
+
const assetsExt = ".assets"
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
async get([key]: CacheKey): Promise<string | null> {
|
|
112
|
+
const filePath = join(baseDir, key, filename)
|
|
113
|
+
if (!existsSync(filePath)) {
|
|
114
|
+
return null
|
|
115
|
+
}
|
|
116
|
+
const assetsDir = join(baseDir, key, filename + assetsExt)
|
|
117
|
+
return restoreDataUrls(readFileSync(filePath, "utf-8"), assetsDir)
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
async set([key]: CacheKey, value: string): Promise<void> {
|
|
121
|
+
const cacheDir = ensureCacheDir(baseDir, key)
|
|
122
|
+
const filePath = join(cacheDir, filename)
|
|
123
|
+
const assetsDir = join(cacheDir, filename + assetsExt)
|
|
124
|
+
const { content } = extractDataUrls(value, assetsDir)
|
|
125
|
+
writeFileSync(filePath, content, "utf-8")
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
async has([key]: CacheKey): Promise<boolean> {
|
|
129
|
+
const filePath = join(baseDir, key, filename)
|
|
130
|
+
return existsSync(filePath)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
47
135
|
/** Create a KV store backed by binary files */
|
|
48
136
|
export function createBinaryFileKV(baseDir: string, filename: string): KV<CacheKey, Uint8Array> {
|
|
49
137
|
return {
|
|
@@ -116,9 +204,9 @@ export function createJsonlFileKVStream(baseDir: string, filename: string): KVSt
|
|
|
116
204
|
/** Create a complete CacheStorage backed by the filesystem */
|
|
117
205
|
export function createFilesystemStorage(baseDir: string): CacheStorage {
|
|
118
206
|
return {
|
|
119
|
-
requests:
|
|
207
|
+
requests: createRequestFileKV(baseDir, "request.json"),
|
|
120
208
|
responseMeta: createJsonFileKV<CachedResponseMeta>(baseDir, "response.meta.json"),
|
|
121
|
-
responseBody:
|
|
209
|
+
responseBody: createTextFileKV(baseDir, "response.json"),
|
|
122
210
|
binaryBody: createBinaryFileKV(baseDir, "response.bin"),
|
|
123
211
|
sseChunks: createJsonlFileKVStream(baseDir, "response.jsonl")
|
|
124
212
|
}
|