0
# Store Implementations
1
2
Pluggable storage system for cookie persistence supporting both synchronous and asynchronous operations with complete CRUD functionality and efficient indexing.
3
4
## Capabilities
5
6
### Store Base Class
7
8
Abstract base class defining the interface for cookie storage implementations.
9
10
```typescript { .api }
11
/**
12
* Base class for cookie storage implementations
13
* Provides the interface for pluggable storage backends
14
*/
15
class Store {
16
// Properties
17
synchronous: boolean; // Whether store supports synchronous operations
18
19
// Methods that should be implemented by subclasses (throw errors in base class)
20
findCookie(
21
domain: string | null,
22
path: string | null,
23
key: string | null
24
): Promise<Cookie | undefined>;
25
findCookie(
26
domain: string | null,
27
path: string | null,
28
key: string | null,
29
callback: Callback<Cookie | undefined>
30
): void;
31
32
findCookies(
33
domain: string | null,
34
path: string | null,
35
allowSpecialUseDomain?: boolean
36
): Promise<Cookie[]>;
37
findCookies(
38
domain: string | null,
39
path: string | null,
40
allowSpecialUseDomain?: boolean,
41
callback?: Callback<Cookie[]>
42
): void;
43
44
putCookie(cookie: Cookie): Promise<void>;
45
putCookie(cookie: Cookie, callback: ErrorCallback): void;
46
47
updateCookie(oldCookie: Cookie, newCookie: Cookie): Promise<void>;
48
updateCookie(oldCookie: Cookie, newCookie: Cookie, callback: ErrorCallback): void;
49
50
removeCookie(domain: string | null, path: string | null, key: string | null): Promise<void>;
51
removeCookie(domain: string | null, path: string | null, key: string | null, callback: ErrorCallback): void;
52
53
removeCookies(domain: string, path: string | null): Promise<void>;
54
removeCookies(domain: string, path: string | null, callback: ErrorCallback): void;
55
56
removeAllCookies(): Promise<void>;
57
removeAllCookies(callback: ErrorCallback): void;
58
59
getAllCookies(): Promise<Cookie[]>;
60
getAllCookies(callback: Callback<Cookie[]>): void;
61
}
62
```
63
64
### Store Method Descriptions
65
66
Core CRUD operations that all store implementations must provide.
67
68
```typescript { .api }
69
/**
70
* Retrieves a specific cookie by domain, path, and key
71
* @param domain - Cookie domain (null matches any domain)
72
* @param path - Cookie path (null matches any path)
73
* @param key - Cookie key/name (null matches any key)
74
* @returns Promise resolving to found cookie or undefined
75
*/
76
findCookie(
77
domain: string | null,
78
path: string | null,
79
key: string | null
80
): Promise<Cookie | undefined>;
81
82
/**
83
* Finds all cookies matching given domain and path
84
* @param domain - Domain to match cookies against
85
* @param path - Path to match cookies against (null matches all paths)
86
* @param allowSpecialUseDomain - Whether to allow special use domains
87
* @returns Promise resolving to array of matching cookies
88
*/
89
findCookies(
90
domain: string | null,
91
path: string | null,
92
allowSpecialUseDomain?: boolean
93
): Promise<Cookie[]>;
94
95
/**
96
* Stores a new cookie, replacing any existing cookie with same domain/path/key
97
* @param cookie - Cookie to store
98
* @returns Promise that resolves when storage is complete
99
*/
100
putCookie(cookie: Cookie): Promise<void>;
101
102
/**
103
* Updates an existing cookie with new values
104
* @param oldCookie - Existing cookie to replace
105
* @param newCookie - New cookie data
106
* @returns Promise that resolves when update is complete
107
*/
108
updateCookie(oldCookie: Cookie, newCookie: Cookie): Promise<void>;
109
110
/**
111
* Removes a specific cookie by domain, path, and key
112
* @param domain - Cookie domain (null matches any domain)
113
* @param path - Cookie path (null matches any path)
114
* @param key - Cookie key/name (null matches any key)
115
* @returns Promise that resolves when removal is complete
116
*/
117
removeCookie(domain: string | null, path: string | null, key: string | null): Promise<void>;
118
119
/**
120
* Removes cookies matching domain and path
121
* @param domain - Domain to match
122
* @param path - Path to match (null removes all paths in domain)
123
* @returns Promise that resolves when removal is complete
124
*/
125
removeCookies(domain: string, path: string | null): Promise<void>;
126
127
/**
128
* Removes all cookies from the store
129
* @returns Promise that resolves when cleanup is complete
130
*/
131
removeAllCookies(): Promise<void>;
132
133
/**
134
* Retrieves all cookies from the store
135
* @returns Promise resolving to array of all stored cookies
136
*/
137
getAllCookies(): Promise<Cookie[]>;
138
```
139
140
### MemoryCookieStore
141
142
Default in-memory store implementation with efficient indexing and synchronous operation support.
143
144
```typescript { .api }
145
/**
146
* Default in-memory cookie store implementation
147
* Provides efficient storage using nested domain/path/key indexing
148
*/
149
class MemoryCookieStore extends Store {
150
// Properties
151
synchronous: boolean; // Always true - supports synchronous operations
152
153
// Constructor
154
constructor();
155
156
// Implements all Store methods with in-memory storage
157
findCookie(domain: string | null, path: string | null, key: string | null): Promise<Cookie | undefined>;
158
findCookies(domain: string, path: string, allowSpecialUseDomain?: boolean): Promise<Cookie[]>;
159
putCookie(cookie: Cookie): Promise<void>;
160
updateCookie(oldCookie: Cookie, newCookie: Cookie): Promise<void>;
161
removeCookie(domain: string, path: string, key: string): Promise<void>;
162
removeCookies(domain: string, path: string): Promise<void>;
163
removeAllCookies(): Promise<void>;
164
getAllCookies(): Promise<Cookie[]>;
165
}
166
```
167
168
**Usage Examples:**
169
170
```typescript
171
import { MemoryCookieStore, CookieJar, Cookie } from "tough-cookie";
172
173
// Create memory store
174
const store = new MemoryCookieStore();
175
176
// Use with CookieJar
177
const jar = new CookieJar(store);
178
179
// Store is synchronous
180
console.log(store.synchronous); // true
181
182
// Can be used directly
183
const cookie = new Cookie({
184
key: 'session',
185
value: 'abc123',
186
domain: 'example.com',
187
path: '/'
188
});
189
190
await store.putCookie(cookie);
191
const found = await store.findCookie('example.com', '/', 'session');
192
console.log(found?.value); // 'abc123'
193
```
194
195
### Store Internal Structure
196
197
The memory store uses an efficient nested indexing structure for fast lookups.
198
199
```typescript { .api }
200
/**
201
* Internal structure for MemoryCookieStore indexing
202
* Provides O(1) average case lookups by domain/path/key
203
*/
204
type MemoryCookieStoreIndex = {
205
[domain: string]: {
206
[path: string]: {
207
[key: string]: Cookie
208
}
209
}
210
}
211
```
212
213
## Custom Store Implementation
214
215
### Creating Custom Stores
216
217
To create a custom store, extend the Store base class and implement all abstract methods.
218
219
**Example: Simple File-based Store**
220
221
```typescript
222
import { Store, Cookie, Callback, ErrorCallback } from "tough-cookie";
223
import * as fs from 'fs/promises';
224
import * as path from 'path';
225
226
class FileCookieStore extends Store {
227
private storePath: string;
228
229
constructor(filePath: string) {
230
super();
231
this.synchronous = false; // Async file operations
232
this.storePath = filePath;
233
}
234
235
async findCookie(
236
domain: string | null,
237
path: string | null,
238
key: string | null
239
): Promise<Cookie | undefined> {
240
const cookies = await this.getAllCookies();
241
return cookies.find(cookie =>
242
(domain === null || cookie.domain === domain) &&
243
(path === null || cookie.path === path) &&
244
(key === null || cookie.key === key)
245
);
246
}
247
248
async findCookies(
249
domain: string,
250
path: string,
251
allowSpecialUseDomain?: boolean
252
): Promise<Cookie[]> {
253
const cookies = await this.getAllCookies();
254
return cookies.filter(cookie =>
255
cookie.domain === domain &&
256
(cookie.path?.startsWith(path) || false)
257
);
258
}
259
260
async putCookie(cookie: Cookie): Promise<void> {
261
const cookies = await this.getAllCookies();
262
263
// Remove existing cookie with same domain/path/key
264
const filtered = cookies.filter(c =>
265
!(c.domain === cookie.domain &&
266
c.path === cookie.path &&
267
c.key === cookie.key)
268
);
269
270
filtered.push(cookie);
271
await this.saveAllCookies(filtered);
272
}
273
274
async updateCookie(oldCookie: Cookie, newCookie: Cookie): Promise<void> {
275
const cookies = await this.getAllCookies();
276
const index = cookies.findIndex(c =>
277
c.domain === oldCookie.domain &&
278
c.path === oldCookie.path &&
279
c.key === oldCookie.key
280
);
281
282
if (index !== -1) {
283
cookies[index] = newCookie;
284
await this.saveAllCookies(cookies);
285
}
286
}
287
288
async removeCookie(domain: string, path: string, key: string): Promise<void> {
289
const cookies = await this.getAllCookies();
290
const filtered = cookies.filter(c =>
291
!(c.domain === domain && c.path === path && c.key === key)
292
);
293
await this.saveAllCookies(filtered);
294
}
295
296
async removeCookies(domain: string, path: string): Promise<void> {
297
const cookies = await this.getAllCookies();
298
const filtered = cookies.filter(c =>
299
!(c.domain === domain && c.path === path)
300
);
301
await this.saveAllCookies(filtered);
302
}
303
304
async removeAllCookies(): Promise<void> {
305
await this.saveAllCookies([]);
306
}
307
308
async getAllCookies(): Promise<Cookie[]> {
309
try {
310
const data = await fs.readFile(this.storePath, 'utf8');
311
const parsed = JSON.parse(data);
312
return parsed.map((cookieData: any) => Cookie.fromJSON(cookieData)).filter(Boolean);
313
} catch (error) {
314
if ((error as any).code === 'ENOENT') {
315
return []; // File doesn't exist yet
316
}
317
throw error;
318
}
319
}
320
321
private async saveAllCookies(cookies: Cookie[]): Promise<void> {
322
const serialized = cookies.map(cookie => cookie.toJSON());
323
await fs.mkdir(path.dirname(this.storePath), { recursive: true });
324
await fs.writeFile(this.storePath, JSON.stringify(serialized, null, 2));
325
}
326
}
327
328
// Usage
329
const fileStore = new FileCookieStore('./cookies.json');
330
const jar = new CookieJar(fileStore);
331
```
332
333
### Store Callback Pattern
334
335
All store methods support both Promise and callback patterns for compatibility.
336
337
```typescript
338
import { MemoryCookieStore, Cookie } from "tough-cookie";
339
340
const store = new MemoryCookieStore();
341
const cookie = new Cookie({ key: 'test', value: 'value' });
342
343
// Promise-based usage
344
await store.putCookie(cookie);
345
const found = await store.findCookie('example.com', '/', 'test');
346
347
// Callback-based usage
348
store.putCookie(cookie, (error) => {
349
if (error) {
350
console.error('Failed to store cookie:', error);
351
return;
352
}
353
354
store.findCookie('example.com', '/', 'test', (error, result) => {
355
if (error) {
356
console.error('Failed to find cookie:', error);
357
return;
358
}
359
console.log('Found cookie:', result);
360
});
361
});
362
```
363
364
### Store Performance Considerations
365
366
**MemoryCookieStore Performance:**
367
- O(1) average case lookup by exact domain/path/key
368
- O(n) worst case for domain/path matching operations
369
- Efficient for applications with moderate cookie counts
370
- Memory usage grows linearly with number of stored cookies
371
372
**Custom Store Guidelines:**
373
- Implement efficient indexing for your storage backend
374
- Consider async operations for I/O bound stores (files, databases)
375
- Handle concurrent access appropriately
376
- Implement proper error handling for storage failures
377
- Consider cleanup of expired cookies in background operations
378
379
## Types
380
381
```typescript { .api }
382
interface Callback<T> {
383
(error: Error, result?: never): void;
384
(error: null, result: T): void;
385
}
386
387
interface ErrorCallback {
388
(error: Error | null): void;
389
}
390
```