@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) 2023 Effectful Technologies Inc (original work)
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,EAAqC,QAAQ,EAAE,YAAY,EAAE,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAqBrH,6CAA6C;AAC7C,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,CAsBtF;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
+ {"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: createJsonFileKV(baseDir, "request.json"),
185
+ requests: createRequestFileKV(baseDir, "request.json"),
106
186
  responseMeta: createJsonFileKV(baseDir, "response.meta.json"),
107
- responseBody: createJsonFileKV(baseDir, "response.json"),
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.2",
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.15.32"
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: createJsonFileKV<CachedRequest>(baseDir, "request.json"),
207
+ requests: createRequestFileKV(baseDir, "request.json"),
120
208
  responseMeta: createJsonFileKV<CachedResponseMeta>(baseDir, "response.meta.json"),
121
- responseBody: createJsonFileKV<string>(baseDir, "response.json"),
209
+ responseBody: createTextFileKV(baseDir, "response.json"),
122
210
  binaryBody: createBinaryFileKV(baseDir, "response.bin"),
123
211
  sseChunks: createJsonlFileKVStream(baseDir, "response.jsonl")
124
212
  }