Skip to content

Commit a67dc99

Browse files
committed
fixup
1 parent e46c54c commit a67dc99

File tree

1 file changed

+40
-89
lines changed

1 file changed

+40
-89
lines changed

lib/cache/memory-cache-store.js

+40-89
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,11 @@
33
const { Writable } = require('node:stream')
44

55
/**
6+
* @typedef {import('../../types/cache-interceptor.d.ts').default.CacheKey} CacheKey
67
* @typedef {import('../../types/cache-interceptor.d.ts').default.CacheStore} CacheStore
8+
* @typedef {import('../../types/cache-interceptor.d.ts').default.CachedResponse} CachedResponse
9+
* @typedef {import('../../types/cache-interceptor.d.ts').default.GetResult} GetResult
710
* @implements {CacheStore}
8-
*
9-
* @typedef {{
10-
* locked: boolean
11-
* opts: import('../../types/cache-interceptor.d.ts').default.CachedResponse
12-
* body?: Buffer[]
13-
* }} MemoryStoreValue
1411
*/
1512
class MemoryCacheStore {
1613
#maxCount = Infinity
@@ -20,7 +17,7 @@ class MemoryCacheStore {
2017
#entryCount = 0
2118

2219
/**
23-
* @type {Map<string, Map<string, MemoryStoreValue[]>>}
20+
* @type {Map<string, Map<string, GetResult[]>>}
2421
*/
2522
#data = new Map()
2623

@@ -66,22 +63,7 @@ class MemoryCacheStore {
6663
* @returns {import('../../types/cache-interceptor.d.ts').default.GetResult | undefined}
6764
*/
6865
get (key) {
69-
if (typeof key !== 'object') {
70-
throw new TypeError(`expected key to be object, got ${typeof key}`)
71-
}
72-
73-
const values = this.#getValuesForRequest(key, false)
74-
if (!values) {
75-
return undefined
76-
}
77-
78-
const value = this.#findValue(key, values)
79-
80-
if (!value || value.locked) {
81-
return undefined
82-
}
83-
84-
return { ...value.opts, body: value.body }
66+
return this.#findValue(key, this.#getValuesForRequest(key))
8567
}
8668

8769
/**
@@ -97,87 +79,53 @@ class MemoryCacheStore {
9779
throw new TypeError(`expected value to be object, got ${typeof opts}`)
9880
}
9981

82+
if (this.isFull) {
83+
this.#prune()
84+
}
85+
10086
if (this.isFull) {
10187
return undefined
10288
}
10389

104-
const values = this.#getValuesForRequest(key, true)
90+
const values = this.#getValuesForRequest(key)
10591

10692
let value = this.#findValue(key, values)
107-
if (!value) {
108-
// The value doesn't already exist, meaning we haven't cached this
109-
// response before. Let's assign it a value and insert it into our data
110-
// property.
111-
112-
if (this.isFull) {
113-
// Or not, we don't have space to add another response
114-
return undefined
115-
}
11693

117-
if (this.#entryCount++ > this.#maxEntries) {
118-
this.#prune()
119-
}
120-
121-
value = { locked: true, opts }
94+
if (!value) {
95+
value = { ...opts, body: null }
12296
values.push(value)
123-
} else {
124-
// Check if there's already another request writing to the value or
125-
// a request reading from it
126-
if (value.locked) {
127-
return undefined
128-
}
129-
130-
// Empty it so we can overwrite it
131-
value.body = []
13297
}
13398

13499
let currentSize = 0
135-
/**
136-
* @type {Buffer[] | null}
137-
*/
138-
let body = []
100+
101+
const body = []
139102
const maxEntrySize = this.#maxEntrySize
140103

141-
const writable = new Writable({
104+
return new Writable({
142105
write (chunk, encoding, callback) {
143-
if (key.method === 'HEAD') {
144-
throw new Error('HEAD request shouldn\'t have a body')
145-
}
146-
147-
if (!body) {
148-
return callback()
149-
}
150-
151106
if (typeof chunk === 'string') {
152107
chunk = Buffer.from(chunk, encoding)
153108
}
154109

155110
currentSize += chunk.byteLength
156111

157112
if (currentSize >= maxEntrySize) {
158-
body = null
159-
this.end()
160-
return callback()
113+
this.destroy()
114+
} else {
115+
body.push(chunk)
161116
}
162117

163-
body.push(chunk)
164118
callback()
165119
},
166120
final (callback) {
167-
value.locked = false
168-
if (body !== null) {
169-
value.body = body
170-
}
171-
121+
Object.assign(value, opts, { body })
172122
callback()
173123
}
174124
})
175-
176-
return writable
177125
}
178126

179127
/**
180-
* @param {import('../../types/cache-interceptor.d.ts').default.CacheKey} key
128+
* @param {CacheKey} key
181129
*/
182130
delete (key) {
183131
this.#data.delete(`${key.origin}:${key.path}`)
@@ -186,25 +134,24 @@ class MemoryCacheStore {
186134
/**
187135
* Gets all of the requests of the same origin, path, and method. Does not
188136
* take the `vary` property into account.
189-
* @param {import('../../types/cache-interceptor.d.ts').default.CacheKey} key
190-
* @param {boolean} [makeIfDoesntExist=false]
191-
* @returns {MemoryStoreValue[] | undefined}
137+
* @param {CacheKey} key
138+
* @returns {GetResult[]}
192139
*/
193-
#getValuesForRequest (key, makeIfDoesntExist) {
140+
#getValuesForRequest (key) {
141+
if (typeof key !== 'object') {
142+
throw new TypeError(`expected key to be object, got ${typeof key}`)
143+
}
144+
194145
// https://www.rfc-editor.org/rfc/rfc9111.html#section-2-3
195146
const topLevelKey = `${key.origin}:${key.path}`
196147
let cachedPaths = this.#data.get(topLevelKey)
197148
if (!cachedPaths) {
198-
if (!makeIfDoesntExist) {
199-
return undefined
200-
}
201-
202149
cachedPaths = new Map()
203150
this.#data.set(topLevelKey, cachedPaths)
204151
}
205152

206153
let value = cachedPaths.get(key.method)
207-
if (!value && makeIfDoesntExist) {
154+
if (!value) {
208155
value = []
209156
cachedPaths.set(key.method, value)
210157
}
@@ -214,25 +161,29 @@ class MemoryCacheStore {
214161

215162
/**
216163
* Given a list of values of a certain request, this decides the best value
217-
* to respond with.
218-
* @param {import('../../types/cache-interceptor.d.ts').default.CacheKey} req
219-
* @param {MemoryStoreValue[]} values
220-
* @returns {(MemoryStoreValue) | undefined}
164+
* to respond with.
165+
* @param {CacheKey} key
166+
* @param {GetResult[] | undefined } values
167+
* @returns {(GetResult) | undefined}
221168
*/
222-
#findValue (req, values) {
169+
#findValue (key, values) {
170+
if (typeof key !== 'object') {
171+
throw new TypeError(`expected key to be object, got ${typeof key}`)
172+
}
173+
223174
const now = Date.now()
224-
return values.find(({ opts: { deleteAt, vary }, body }) => (
175+
return values?.find(({ deleteAt, vary, body }) => (
225176
body != null &&
226177
deleteAt > now &&
227-
(!vary || Object.keys(vary).every(key => vary[key] === req.headers?.[key]))
178+
(!vary || Object.keys(vary).every(headerName => vary[headerName] === key.headers?.[headerName]))
228179
))
229180
}
230181

231182
#prune () {
232183
const now = Date.now()
233184
for (const [key, cachedPaths] of this.#data) {
234185
for (const [method, prev] of cachedPaths) {
235-
const next = prev.filter(({ opts, body }) => body == null || opts.deleteAt > now)
186+
const next = prev.filter(({ deleteAt }) => deleteAt > now)
236187
if (next.length === 0) {
237188
cachedPaths.delete(method)
238189
if (cachedPaths.size === 0) {

0 commit comments

Comments
 (0)