Skip to content

Commit 577fbe3

Browse files
committed
idek
1 parent 9b25308 commit 577fbe3

File tree

3 files changed

+370
-4
lines changed

3 files changed

+370
-4
lines changed

src/storage/memory.test.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,20 @@ describe("MemoryStore", () => {
259259
expect(found).toBeNull();
260260
});
261261

262+
it("should be idempotent (multiple deletes don't error)", async () => {
263+
const { record } = await keys.create({
264+
ownerId: "user_idempotent",
265+
});
266+
267+
await store.delete(record.id);
268+
await store.delete(record.id);
269+
await store.delete(record.id);
270+
271+
// Should not throw
272+
const result = await store.findById(record.id);
273+
expect(result).toBeNull();
274+
});
275+
262276
it("should do nothing for non-existent ID", async () => {
263277
await store.delete("non-existent");
264278
// Should not throw
@@ -280,9 +294,63 @@ describe("MemoryStore", () => {
280294
expect(userKeepKeys).toHaveLength(1);
281295
});
282296

297+
it("should be idempotent (multiple calls don't error)", async () => {
298+
await keys.create({
299+
ownerId: "user_idempotent_all",
300+
});
301+
302+
await store.deleteByOwner("user_idempotent_all");
303+
await store.deleteByOwner("user_idempotent_all");
304+
await store.deleteByOwner("user_idempotent_all");
305+
306+
// Should not throw
307+
const found = await store.findByOwner("user_idempotent_all");
308+
expect(found).toHaveLength(0);
309+
});
310+
283311
it("should do nothing for non-existent owner", async () => {
284312
await store.deleteByOwner("non-existent");
285313
// Should not throw
286314
});
287315
});
316+
317+
describe("Edge Cases", () => {
318+
it("should handle empty tags array", async () => {
319+
const { record } = await keys.create({
320+
ownerId: "user_empty_tags",
321+
tags: [],
322+
});
323+
324+
const found = await store.findById(record.id);
325+
expect(found?.metadata.tags).toEqual([]);
326+
});
327+
328+
it("should handle undefined vs empty tags array", async () => {
329+
const { record: r1 } = await keys.create({
330+
ownerId: "user_no_tags_1",
331+
});
332+
333+
const { record: r2 } = await keys.create({
334+
ownerId: "user_no_tags_2",
335+
tags: [],
336+
});
337+
338+
const found1 = await store.findById(r1.id);
339+
const found2 = await store.findById(r2.id);
340+
341+
// Both should handle tags gracefully
342+
expect(found1).not.toBeNull();
343+
expect(found2).not.toBeNull();
344+
});
345+
346+
it("should handle keys with no metadata fields", async () => {
347+
const { record } = await keys.create({
348+
ownerId: "user_minimal",
349+
});
350+
351+
const found = await store.findById(record.id);
352+
expect(found).not.toBeNull();
353+
expect(found?.metadata.ownerId).toBe("user_minimal");
354+
});
355+
});
288356
});

src/storage/memory.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ export class MemoryStore implements Storage {
55
private readonly keys: Map<string, ApiKeyRecord> = new Map();
66

77
async save(record: ApiKeyRecord): Promise<void> {
8-
const existing = await this.keys.get(record.id);
8+
const existing = await this.findById(record.id);
99
if (existing) {
1010
throw new Error(`API key with id ${record.id} already exists`);
1111
}
12-
this.keys.set(record.id, record);
12+
await this.keys.set(record.id, record);
1313
}
1414

1515
async findByHash(keyHash: string): Promise<ApiKeyRecord | null> {
@@ -60,9 +60,9 @@ export class MemoryStore implements Storage {
6060
}
6161

6262
async deleteByOwner(ownerId: string): Promise<void> {
63-
for (const [id, record] of this.keys.entries()) {
63+
for (const [id, record] of await this.keys.entries()) {
6464
if (record.metadata.ownerId === ownerId) {
65-
await this.keys.delete(id);
65+
this.keys.delete(id);
6666
}
6767
}
6868
}

0 commit comments

Comments
 (0)