-
Notifications
You must be signed in to change notification settings - Fork 137
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(drivers): added session storage driver
- Loading branch information
1 parent
e36cee8
commit 813c8f9
Showing
4 changed files
with
158 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
--- | ||
navigation.title: Session Storage | ||
--- | ||
|
||
# Session Storage | ||
|
||
Store data in [sessionStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage). | ||
|
||
```js | ||
import { createStorage } from "unstorage"; | ||
import sessionStorageDriver from "unstorage/drivers/session-storage"; | ||
|
||
const storage = createStorage({ | ||
driver: sessionStorageDriver({ base: "app:" }), | ||
}); | ||
``` | ||
|
||
**Options:** | ||
|
||
- `base`: Add `${base}:` to all keys to avoid collision | ||
- `sessionStorage`: Optionally provide `sessionStorage` object | ||
- `window`: Optionally provide `window` object |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { defineDriver } from "./utils"; | ||
|
||
export interface SessionStorageOptions { | ||
base?: string; | ||
window?: typeof window; | ||
sessionStorage?: typeof window.sessionStorage; | ||
} | ||
|
||
export default defineDriver((opts: SessionStorageOptions = {}) => { | ||
if (!opts.window) { | ||
opts.window = typeof window !== "undefined" ? window : undefined; | ||
} | ||
if (!opts.sessionStorage) { | ||
opts.sessionStorage = opts.window?.sessionStorage; | ||
} | ||
if (!opts.sessionStorage) { | ||
throw new Error("sessionStorage not available"); | ||
} | ||
|
||
const r = (key: string) => (opts.base ? opts.base + ":" : "") + key; | ||
|
||
let _storageListener: (ev: StorageEvent) => void; | ||
|
||
return { | ||
name: "session-storage", | ||
options: opts, | ||
hasItem(key) { | ||
return Object.prototype.hasOwnProperty.call(opts.sessionStorage, r(key)); | ||
}, | ||
getItem(key) { | ||
return opts.sessionStorage.getItem(r(key)); | ||
}, | ||
setItem(key, value) { | ||
return opts.sessionStorage.setItem(r(key), value); | ||
}, | ||
removeItem(key) { | ||
return opts.sessionStorage.removeItem(r(key)); | ||
}, | ||
getKeys() { | ||
return Object.keys(opts.sessionStorage); | ||
}, | ||
clear() { | ||
if (!opts.base) { | ||
opts.sessionStorage!.clear(); | ||
} else { | ||
for (const key of Object.keys(opts.sessionStorage)) { | ||
opts.sessionStorage?.removeItem(key); | ||
} | ||
} | ||
if (opts.window && _storageListener) { | ||
opts.window.removeEventListener("storage", _storageListener); | ||
} | ||
}, | ||
watch(callback) { | ||
if (!opts.window) { | ||
return; | ||
} | ||
_storageListener = ({ key, newValue }: StorageEvent) => { | ||
if (key) { | ||
callback(newValue ? "update" : "remove", key); | ||
} | ||
}; | ||
opts.window.addEventListener("storage", _storageListener); | ||
|
||
return () => { | ||
opts.window.removeEventListener("storage", _storageListener); | ||
_storageListener = undefined; | ||
}; | ||
}, | ||
}; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { JSDOM } from "jsdom"; | ||
import { describe, expect, it, vi } from "vitest"; | ||
import driver from "../../src/drivers/session-storage"; | ||
import { testDriver } from "./utils"; | ||
|
||
describe("drivers: session-storage", () => { | ||
const jsdom = new JSDOM("", { | ||
url: "http://localhost", | ||
}); | ||
jsdom.virtualConsole.sendTo(console); | ||
|
||
testDriver({ | ||
driver: driver({ window: jsdom.window as unknown as typeof window }), | ||
additionalTests: (ctx) => { | ||
it("check session storage", () => { | ||
expect(jsdom.window.sessionStorage.getItem("s1:a")).toBe("test_data"); | ||
}); | ||
it("watch session storage", async () => { | ||
const watcher = vi.fn(); | ||
await ctx.storage.watch(watcher); | ||
|
||
// Emulate | ||
// jsdom.window.sessionStorage.setItem('s1:random_file', 'random') | ||
const ev = jsdom.window.document.createEvent("CustomEvent"); | ||
ev.initEvent("storage", true); | ||
// @ts-ignore | ||
ev.key = "s1:random_file"; | ||
// @ts-ignore | ||
ev.newValue = "random"; | ||
jsdom.window.dispatchEvent(ev); | ||
|
||
expect(watcher).toHaveBeenCalledWith("update", "s1:random_file"); | ||
}); | ||
it("unwatch session storage", async () => { | ||
const watcher = vi.fn(); | ||
const unwatch = await ctx.storage.watch(watcher); | ||
|
||
// Emulate | ||
// jsdom.window.sessionStorage.setItem('s1:random_file', 'random') | ||
const ev = jsdom.window.document.createEvent("CustomEvent"); | ||
ev.initEvent("storage", true); | ||
// @ts-ignore | ||
ev.key = "s1:random_file"; | ||
// @ts-ignore | ||
ev.newValue = "random"; | ||
const ev2 = jsdom.window.document.createEvent("CustomEvent"); | ||
ev2.initEvent("storage", true); | ||
// @ts-ignore | ||
ev2.key = "s1:random_file2"; | ||
// @ts-ignore | ||
ev2.newValue = "random"; | ||
|
||
jsdom.window.dispatchEvent(ev); | ||
|
||
await unwatch(); | ||
|
||
jsdom.window.dispatchEvent(ev2); | ||
|
||
expect(watcher).toHaveBeenCalledWith("update", "s1:random_file"); | ||
expect(watcher).toHaveBeenCalledTimes(1); | ||
}); | ||
}, | ||
}); | ||
}); |