Skip to content

Commit 4de69f4

Browse files
authored
Merge pull request #36 from MacFJA/new-shorthand
Add new store shorthand
2 parents 584b57b + 78d4d92 commit 4de69f4

10 files changed

+279
-32
lines changed

.docs/Examples/04-Encrypted-Storage.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,7 @@ _**NOTE:** The encryption is not well adapted for cookie storage, as the data is
2323
const nickname = persist(writable("John"), storage, "myapp-nickname")
2424
</script>
2525
```
26+
27+
## Encryption key
28+
29+
https://www.allkeysgenerator.com/Random/Security-Encryption-Key-Generator.aspx
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
---
2+
name: Usage of persistent store
3+
order: 5
4+
---
5+
6+
# Usage of persistent store
7+
8+
There are a multiple way to use/create persistent stores.
9+
10+
## The long and configurable way
11+
12+
This method allow to configure the storage by first creating it.
13+
This is particular useful for LocalStorage, SessionStorage, EncryptedStorage and ChromeStorage that have configuration.
14+
15+
_**NOTE:** It's the only way to use EncryptedStorage and ChromeStorage_
16+
17+
### Function call
18+
19+
```typescript
20+
import {writable} from "svelte/store"
21+
22+
const persistedStore = persist(
23+
writable("my value"),
24+
<<storageCreateFunction()>>,
25+
"my-data-key"
26+
)
27+
```
28+
29+
With:
30+
31+
- `writable("my value")` the store you want to persist
32+
- `<<storageCreateFunction()>>` one of
33+
- `createLocalStorage`
34+
- `createSessionStorage`
35+
- `createCookieStorage`
36+
- `createIndexedDBStorage`
37+
- `createEncryptedStorage`
38+
- `createChromeStorage`
39+
- `"my-data-key"` the key that will identify the store in the storage
40+
41+
### Functions signatures
42+
43+
```typescript
44+
declare function persist<T>(store: Writable<T>, storage: StorageInterface<T>, key: string): PersistentStore<T>
45+
46+
declare function createLocalStorage<T>(listenExternalChanges?: boolean): StorageInterface<T>
47+
declare function createSessionStorage<T>(listenExternalChanges?: boolean): StorageInterface<T>
48+
declare function createCookieStorage(): StorageInterface<any>
49+
declare function createIndexedDBStorage<T>(): SelfUpdateStorageInterface<T>
50+
declare function createEncryptedStorage<T>(
51+
wrapped: StorageInterface<T>,
52+
encryptionKey: string
53+
): StorageInterface<T> | SelfUpdateStorageInterface<T>
54+
declare function createChromeStorage<T>(
55+
storageType?: CHROME_STORAGE_TYPE,
56+
listenExternalChanges?: boolean
57+
): SelfUpdateStorageInterface<T>
58+
```
59+
60+
- `createLocalStorage` and `createSessionStorage` take a boolean as theirs first parameter (`false` by default). If set to `true` the storage will listen for changes (of the stored value) in other pages
61+
- `createEncryptedStorage` have 2 parameters, the first one is the storage that you want to encrypt, the second is the encryption key to use
62+
- `createChromeStorage` have 2 optional parameters, the first one this the type of storage (local storage by default), the second (`false` by default) if set to `true` the storage will listen for changes (of the stored value) in other pages
63+
64+
## Preconfigured storage way
65+
66+
This method allow to use pre-created storage, configured with default options.
67+
This avoids creating multiple times the same storage
68+
69+
### Function call
70+
71+
```typescript
72+
import {writable} from "svelte/store"
73+
74+
const persistedStore = <<persistFunction>>(
75+
writable("my value"),
76+
"my-data-key"
77+
)
78+
```
79+
80+
With:
81+
82+
- `writable("my value")` the store you want to persist
83+
- `<<persistFunction>>` one of
84+
- `persistBrowserLocal`
85+
- `persistBrowserSession`
86+
- `persistCookie`
87+
- `"my-data-key"` the key that will identify the store in the storage
88+
89+
### Functions signatures
90+
91+
```typescript
92+
declare function persistBrowserLocal<T>(store: Writable<T>, key: string): PersistentStore<T>
93+
declare function persistBrowserSession<T>(store: Writable<T>, key: string): PersistentStore<T>
94+
declare function persistCookie<T>(store: Writable<T>, cookieName: string): PersistentStore<T>
95+
```
96+
97+
## Short way
98+
99+
This method allow to quickly create a writable store without the boilerplate of creating a Svelte store and a Storage.
100+
101+
### Function call
102+
103+
```typescript
104+
const persistedStore = <<writableFunction>>(
105+
"my-data-key",
106+
"my value"
107+
)
108+
```
109+
110+
With:
111+
112+
- `"my value"` the value store you want to persist
113+
- `<<writableFunction>>` one of
114+
- `localWritable`
115+
- `writable`
116+
- `sessionWritable`
117+
- `cookieWritable`
118+
- `"my-data-key"` the key that will identify the store in the storage
119+
120+
### Functions signatures
121+
122+
```typescript
123+
declare function localWritable<T>(key: string, initialValue?: T): PersistentStore<T>
124+
declare function writable<T>(key: string, initialValue?: T): PersistentStore<T>
125+
declare function sessionWritable<T>(key: string, initialValue?: T): PersistentStore<T>
126+
declare function cookieWritable<T>(key: string, initialValue?: T): PersistentStore<T>
127+
```
128+
129+
- `writable` is an alias to `localWritable`
130+
131+
---
132+
133+
## About long format advantages
134+
135+
The long format allow you to use High order function principle.
136+
137+
The `persist` (and also `persistCookie`, `persistBrowserSession`, `persistBrowserLocal`) function is a high order function: it takes a parameter and return an augmented version of it.
138+
139+
As High order function return an augmented version of their parameter, they can be chained.
140+
141+
Imagine we have another lib that enhance a store (like `@macfja/svelte-invalidable`) we can chain them:
142+
143+
```typescript
144+
import { invalidable } from "@macfja/svelte-invalidable"
145+
import { persistBrowserLocal } from "@macfja/svelte-persistent-store"
146+
import { writable } from "svelte/store"
147+
148+
const myStore = persistBrowserLocal(
149+
invalidable(writable(0), () => Math.random()),
150+
"last-random"
151+
)
152+
153+
// $myStore will return a number
154+
// myStore.invalidate() (added by @macfja/svelte-invalidable) still work
155+
// The value or myStore is saved in the browser localStorage
156+
```
157+
158+
With the full format (`persist` only) you can also add encryption to a storage
159+
160+
```typescript
161+
import { persist, createLocalStorage, createEncryptedStorage } from "@macfja/svelte-persistent-store"
162+
import { writable } from "svelte/store"
163+
164+
const storage = createEncryptedStorage(createLocalStorage(), "5368566D597133743677397A24432646")
165+
const myStore = persist(writable(0), storage, "my-data-key")
166+
```

.docs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
- [Reuse a store](Examples/02-Reuse-Store.md)
77
- [Self updated Storage](Examples/03-Self-Update-Storage.md)
88
- [Encrypt persisted data](Examples/04-Encrypted-Storage.md)
9+
- [Usage of persistent store](Examples/05-Use-Persisted-Store.md)
910

1011
## How to
1112

.docs/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@
99
"declarationDir": "../types",
1010
"sourceMap": false
1111
},
12+
"stripInternal": true,
1213
"files": ["../src/index.ts"]
1314
}

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88

9+
### Added
10+
11+
- New function to create store (`localWritable`, `writable`, `sessionWritable`, `cookieWritable`)
12+
13+
### Changed
14+
15+
- (dev) Move wrappers (+shorthand) to a dedicated file
16+
917
## [2.2.1]
1018

1119
### Fixed

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,17 @@ $title = "My Document"
4040
// if you reload the page the value of $title is 'My Document'
4141
```
4242

43+
```javascript
44+
import { writable } from "@macfja/svelte-persistent-store"
45+
46+
// Create a wriatble store, persisted in browser LocalStorage, with the key `name`
47+
let name = writable("name", "John")
48+
49+
$name = "Jeanne Doe"
50+
51+
// if you reload the page the value of $name is 'Jeanne Doe'
52+
```
53+
4354
## Features
4455

4556
- Multiple storages (Allow to have the best suited usage depending on your use case)

src/alias.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { writable as svelteWritable } from "svelte/store"
2+
import type { Writable, StartStopNotifier } from "svelte/store"
3+
4+
import type { PersistentStore, StorageInterface } from "./core"
5+
import { createCookieStorage, createLocalStorage, createSessionStorage, persist } from "./core"
6+
7+
const sharedCookieStorage = createCookieStorage(),
8+
sharedLocalStorage: StorageInterface<any> = createLocalStorage(),
9+
sharedSessionStorage: StorageInterface<any> = createSessionStorage()
10+
11+
/**
12+
* Persist a store into a cookie
13+
* @param {Writable<*>} store The store to enhance
14+
* @param {string} cookieName The name of the cookie
15+
*/
16+
export function persistCookie<T>(store: Writable<T>, cookieName: string): PersistentStore<T> {
17+
return persist(store, sharedCookieStorage, cookieName)
18+
}
19+
/**
20+
* Persist a store into the browser session storage
21+
* @param {Writable<*>} store The store to enhance
22+
* @param {string} key The name of the key in the browser session storage
23+
*/
24+
export function persistBrowserSession<T>(store: Writable<T>, key: string): PersistentStore<T> {
25+
return persist(store, sharedSessionStorage, key)
26+
}
27+
/**
28+
* Persist a store into the browser local storage
29+
* @param {Writable<*>} store The store to enhance
30+
* @param {string} key The name of the key in the browser local storage
31+
*/
32+
export function persistBrowserLocal<T>(store: Writable<T>, key: string): PersistentStore<T> {
33+
return persist(store, sharedLocalStorage, key)
34+
}
35+
36+
/**
37+
* Create a standard Svelte store persisted in Browser LocalStorage
38+
* @param {string} key The key of the data to persist
39+
* @param {*} [initialValue] The initial data of the store
40+
* @param {StartStopNotifier<*>} [start] start and stop notifications for subscriptions
41+
* @return {PersistentStore<*>}
42+
*/
43+
export function localWritable<T>(key: string, initialValue?: T, start?: StartStopNotifier<T>): PersistentStore<T> {
44+
return persistBrowserLocal(svelteWritable(initialValue, start), key)
45+
}
46+
/**
47+
* Create a standard Svelte store persisted in Browser LocalStorage.
48+
* (Alias of [[localWritable]])
49+
* @param {string} key The key of the data to persist
50+
* @param {*} [initialValue] The initial data of the store
51+
* @param {StartStopNotifier<*>} [start] start and stop notifications for subscriptions
52+
* @return {PersistentStore<*>}
53+
*/
54+
export function writable<T>(key: string, initialValue?: T, start?: StartStopNotifier<T>): PersistentStore<T> {
55+
return localWritable(key, initialValue, start)
56+
}
57+
/**
58+
* Create a standard Svelte store persisted in Browser SessionStorage
59+
* @param {string} key The key of the data to persist
60+
* @param {*} [initialValue] The initial data of the store
61+
* @param {StartStopNotifier<*>} [start] start and stop notifications for subscriptions
62+
* @return {PersistentStore<*>}
63+
*/
64+
export function sessionWritable<T>(key: string, initialValue?: T, start?: StartStopNotifier<T>): PersistentStore<T> {
65+
return persistBrowserSession(svelteWritable(initialValue, start), key)
66+
}
67+
/**
68+
* Create a standard Svelte store persisted in cookie
69+
* @param {string} key The key of the data to persist
70+
* @param {*} [initialValue] The initial data of the store
71+
* @param {StartStopNotifier<*>} [start] start and stop notifications for subscriptions
72+
* @return {PersistentStore<*>}
73+
*/
74+
export function cookieWritable<T>(key: string, initialValue?: T, start?: StartStopNotifier<T>): PersistentStore<T> {
75+
return persistCookie(svelteWritable(initialValue, start), key)
76+
}

src/core.ts

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const warnStorageNotFound = (storageName) => {
4949
* Add a class to the allowed list of classes to be serialized
5050
* @param classDef The class to add to the list
5151
*/
52-
export const addSerializableClass = (classDef: ClassDefinition<any>): void => {
52+
export function addSerializableClass(classDef: ClassDefinition<any>): void {
5353
addSerializable(classDef)
5454
}
5555

@@ -216,34 +216,6 @@ function createListenerFunctions<T>(
216216
}
217217
}
218218

219-
const sharedCookieStorage = createCookieStorage(),
220-
sharedLocalStorage: StorageInterface<any> = createLocalStorage(),
221-
sharedSessionStorage: StorageInterface<any> = createSessionStorage()
222-
/**
223-
* Persist a store into a cookie
224-
* @param {Writable<*>} store The store to enhance
225-
* @param {string} cookieName The name of the cookie
226-
*/
227-
export function persistCookie<T>(store: Writable<T>, cookieName: string): PersistentStore<T> {
228-
return persist(store, sharedCookieStorage, cookieName)
229-
}
230-
/**
231-
* Persist a store into the browser session storage
232-
* @param {Writable<*>} store The store to enhance
233-
* @param {string} key The name of the key in the browser session storage
234-
*/
235-
export function persistBrowserSession<T>(store: Writable<T>, key: string): PersistentStore<T> {
236-
return persist(store, sharedSessionStorage, key)
237-
}
238-
/**
239-
* Persist a store into the browser local storage
240-
* @param {Writable<*>} store The store to enhance
241-
* @param {string} key The name of the key in the browser local storage
242-
*/
243-
export function persistBrowserLocal<T>(store: Writable<T>, key: string): PersistentStore<T> {
244-
return persist(store, sharedLocalStorage, key)
245-
}
246-
247219
function getBrowserStorage(browserStorage: Storage, listenExternalChanges = false): SelfUpdateStorageInterface<any> {
248220
const listenerFunction = (event: StorageEvent) => {
249221
const eventKey = event.key

src/index.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,18 @@ export {
77
createSessionStorage,
88
createIndexedDBStorage,
99
persist,
10-
persistBrowserLocal,
11-
persistBrowserSession,
12-
persistCookie,
1310
disableWarnings,
1411
setSerialization,
1512
} from "./core"
13+
export {
14+
persistBrowserLocal,
15+
persistBrowserSession,
16+
persistCookie,
17+
localWritable,
18+
writable,
19+
sessionWritable,
20+
cookieWritable,
21+
} from "./alias"
1622
export type { CHROME_STORAGE_TYPE, PersistentStore, StorageInterface, SelfUpdateStorageInterface } from "./core"
1723
export { createEncryptionStorage, createEncryptedStorage, noEncryptionBehavior } from "./encryption"
1824
export type { NO_ENCRYPTION_BEHAVIOR, Encryption, GCMEncryption } from "./encryption"

tsdocs.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@
22
module.exports = {
33
customPages: "./.docs",
44
tsconfig: "./.docs/tsconfig.json",
5+
stripInternal: true,
6+
changelog: "CHANGELOG.md",
57
}

0 commit comments

Comments
 (0)