pinia-plugin-persist-state 0.1.1 → 0.1.2-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/README.md +37 -21
- package/SECURITY.md +4 -4
- package/dist/pinia-plugin-persist-state.js +343 -1153
- package/dist/services/Crypt.d.ts +9 -14
- package/dist/services/IndexedDB.d.ts +14 -24
- package/dist/services/Persister.d.ts +6 -2
- package/dist/services/WindowStorage.d.ts +4 -4
- package/dist/types/index.d.ts +4 -2
- package/dist/types/storage.d.ts +4 -4
- package/dist/types/store.d.ts +23 -2
- package/package.json +7 -6
- package/dist/pinia-plugin-persist-state.umd.cjs +0 -5
- package/dist/utils/constantes.d.ts +0 -1
- package/dist/utils/pluginConsole.d.ts +0 -6
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,38 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.1.2-beta.0]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Added an object-based `createPersistStatePlugin` configuration to explicitly select `storage`, `databaseName`, `objectStoreName`, and `cryptKey`.
|
|
12
|
+
- Added `persistenceKey` to persist a store under a stable or application-specific record key instead of its Pinia `$id`.
|
|
13
|
+
- Added opt-in cache metadata and restore policies through `cache`, including `maxAge`, schema `version`, and expiration/version-mismatch actions.
|
|
14
|
+
- Added `debounceMs` for trailing, per-store automatic persistence; automatic writes use a 200 ms delay by default.
|
|
15
|
+
- Added `flushPersistedState()` to immediately write the latest store state and cancel a pending debounced write.
|
|
16
|
+
- Added `transformState` to convert a filtered snapshot into an application-defined persistent representation before it is stored.
|
|
17
|
+
- Added `fake-indexeddb` integration tests for real IndexedDB updates, connection reuse, selective deletion, database isolation, and transaction errors.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- Retained the legacy positional `createPersistStatePlugin(storageOrDatabaseName?, cryptKey?)` signature for compatibility. Non-window-storage names are interpreted as IndexedDB database names using the `persistedStore` object store.
|
|
21
|
+
- Replaced per-store `dbName` with `storage` to express a storage backend override without conflating the backend, IndexedDB database, and persisted record key.
|
|
22
|
+
- IndexedDB now reuses open connections and waits for transaction completion before resolving storage operations.
|
|
23
|
+
- The default IndexedDB model uses one application database, a stable object store, and one record per persisted Pinia store.
|
|
24
|
+
- `removePersistedState()` is asynchronous and waits for prior writes to complete.
|
|
25
|
+
- Window Storage remains responsible for serializing complete records; IndexedDB retains native values.
|
|
26
|
+
- `null`, `undefined`, and values considered empty by `pinia-plugin-subscription` are intentionally omitted from persisted snapshots before `transformState` runs.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
- Replaced IndexedDB read-then-update writes with atomic `put()` writes to prevent stale records from being rewritten.
|
|
30
|
+
- Serialized persistence requests and discard superseded snapshots before writing, preventing older asynchronous writes from overwriting newer state.
|
|
31
|
+
- Aligned package ESM metadata with the generated bundle by removing the reference to a nonexistent CommonJS artifact.
|
|
32
|
+
- Aligned storage operations on asynchronous `Promise<void>` contracts so write and removal failures can propagate to callers.
|
|
33
|
+
|
|
34
|
+
### Security
|
|
35
|
+
- New encrypted values use AES-GCM with PBKDF2 and an independent random 16-byte salt plus 12-byte IV for every encrypted value.
|
|
36
|
+
- Introduced the versioned encrypted payload format `v1:salt:iv:ciphertext`.
|
|
37
|
+
- Preserved decryption support for legacy `iv:ciphertext` payloads generated with the historical salt.
|
|
38
|
+
- Encrypted properties preserve JSON-compatible types including strings, numbers, booleans, arrays, and objects; unsupported values are rejected.
|
|
39
|
+
|
|
8
40
|
## [0.1.1]
|
|
9
41
|
|
|
10
42
|
### Fixed
|
package/README.md
CHANGED
|
@@ -4,23 +4,23 @@ A small Pinia plugin that adds persistence and optional encryption to your Pinia
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Features
|
|
8
8
|
|
|
9
9
|
- Persist store state to LocalStorage, SessionStorage or IndexedDB
|
|
10
10
|
- Selective encryption for specific properties using Web Crypto (AES-GCM)
|
|
11
11
|
- Per-store options via `storeOptions` when defining a store
|
|
12
12
|
- Augmented store API: `persistState`, `remember`, `removePersistedState`, `watch`, `stopWatch`
|
|
13
|
-
-
|
|
13
|
+
- Explicit configuration of the persistence backend and IndexedDB storage
|
|
14
14
|
- SSR-safe hydration flow: methods are injected immediately on client, persistence restore is executed during hydration lifecycle
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
18
|
-
##
|
|
18
|
+
## Installation
|
|
19
19
|
|
|
20
20
|
Install the package (example):
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
npm install --save persist-
|
|
23
|
+
npm install --save pinia-plugin-persist-state
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
Then register the plugin with Pinia in your app entry (see `src/main.ts`):
|
|
@@ -29,15 +29,18 @@ Then register the plugin with Pinia in your app entry (see `src/main.ts`):
|
|
|
29
29
|
import { createApp } from 'vue'
|
|
30
30
|
import { createPinia } from 'pinia'
|
|
31
31
|
import { createPlugin } from 'pinia-plugin-subscription'
|
|
32
|
-
import { createPersistStatePlugin, PLUGIN_NAME } from 'persist-
|
|
32
|
+
import { createPersistStatePlugin, PLUGIN_NAME } from 'pinia-plugin-persist-state'
|
|
33
33
|
|
|
34
34
|
const app = createApp(App)
|
|
35
35
|
const pinia = createPinia()
|
|
36
36
|
|
|
37
|
-
// Pass `dbName` (e.g. 'localStorage', 'sessionStorage' or a DB name for IndexedDB)
|
|
38
|
-
// and an optional `cryptKey` to enable encryption support
|
|
39
37
|
pinia.use(createPlugin([
|
|
40
|
-
createPersistStatePlugin(
|
|
38
|
+
createPersistStatePlugin({
|
|
39
|
+
storage: 'indexedDB',
|
|
40
|
+
databaseName: 'my-application',
|
|
41
|
+
objectStoreName: 'persistedStore',
|
|
42
|
+
cryptKey: 'my-secret-key'
|
|
43
|
+
})
|
|
41
44
|
]))
|
|
42
45
|
|
|
43
46
|
app.use(pinia)
|
|
@@ -47,10 +50,10 @@ For Nuxt/SSR projects, prefer `createHydrationPlugin` from `pinia-plugin-subscri
|
|
|
47
50
|
|
|
48
51
|
```ts
|
|
49
52
|
import { createHydrationPlugin } from 'pinia-plugin-subscription'
|
|
50
|
-
import { createPersistStatePlugin } from 'persist-
|
|
53
|
+
import { createPersistStatePlugin } from 'pinia-plugin-persist-state'
|
|
51
54
|
|
|
52
55
|
pinia.use(createHydrationPlugin([
|
|
53
|
-
createPersistStatePlugin('localStorage', 'my-secret-key')
|
|
56
|
+
createPersistStatePlugin({ storage: 'localStorage', cryptKey: 'my-secret-key' })
|
|
54
57
|
], {
|
|
55
58
|
runtimeEnvironment: import.meta.client ? 'client' : 'server'
|
|
56
59
|
}))
|
|
@@ -58,7 +61,7 @@ pinia.use(createHydrationPlugin([
|
|
|
58
61
|
|
|
59
62
|
---
|
|
60
63
|
|
|
61
|
-
##
|
|
64
|
+
## Usage
|
|
62
65
|
|
|
63
66
|
When defining a store you can pass `storeOptions` (type: `PersistedStoreOptions`) as part of the `defineStore` options. Example in `src/stores/test.ts`:
|
|
64
67
|
|
|
@@ -92,27 +95,38 @@ export const useTestStore = defineStore('testStore', () => {
|
|
|
92
95
|
|
|
93
96
|
If `persist` or `watchMutation` are `true` the plugin will attempt to persist the store state using the configured persister: localStorage, sessionStorage or IndexedDB.
|
|
94
97
|
|
|
98
|
+
`createPersistStatePlugin(storageOrDatabaseName?, cryptKey?)` remains supported for compatibility. A value of `'localStorage'` or `'sessionStorage'` selects that storage; any other string is interpreted as an IndexedDB database name and uses the default `persistedStore` object store.
|
|
99
|
+
|
|
95
100
|
---
|
|
96
101
|
|
|
97
|
-
##
|
|
102
|
+
## PersistedStoreOptions
|
|
98
103
|
|
|
99
104
|
Fields available when setting `storeOptions`:
|
|
100
105
|
|
|
101
|
-
- `
|
|
106
|
+
- `storage?: 'localStorage' | 'sessionStorage' | 'indexedDB'` — Optional backend override for this store. IndexedDB settings remain configured at plugin level.
|
|
107
|
+
- `persistenceKey?: string` — Record key used for this store. Defaults to the Pinia `$id` and is useful for stable, readable or parameterized keys.
|
|
108
|
+
- `cache?: CacheOptions` — Opt-in cache metadata and restore policy. Without it, the state is persisted in the historical raw format.
|
|
102
109
|
- `excludedKeys?: string[]` — List of state properties that should NOT be persisted.
|
|
103
110
|
- `persist?: boolean` — Enable or disable persistence for the store (default: `false`).
|
|
104
111
|
- `persistedPropertiesToEncrypt?: string[]` — List of property names to be encrypted when persisted.
|
|
112
|
+
- `transformState?: (state) => state` — Optional synchronous transformer applied to the filtered snapshot after selected properties are encrypted and before storage. Use it to convert application-specific values into a persistent representation.
|
|
105
113
|
- `watchMutation?: boolean` — When `true`, plugin watches store mutations and automatically persists changes.
|
|
114
|
+
- `debounceMs?: number` — Delay in milliseconds before an automatic persistence is written. Defaults to `200`; use `0` to persist each mutation immediately.
|
|
115
|
+
|
|
116
|
+
`CacheOptions` supports `maxAge?: number`, `version?: number`, `onExpired?: 'ignore' | 'remove' | 'restore'`, and `onVersionMismatch?: 'ignore' | 'remove' | 'restore'`. Cache metadata is written only when `cache` is configured.
|
|
117
|
+
|
|
118
|
+
`null` and `undefined` state values are intentionally omitted from persisted snapshots. Empty values handled by `pinia-plugin-subscription` are also omitted. `transformState` receives the resulting snapshot and must return the representation to persist; it must not mutate the store state. A transformer only changes the written representation, so use values that can be restored directly by the store or handle reconstruction in the store hydration flow.
|
|
106
119
|
|
|
107
120
|
---
|
|
108
121
|
|
|
109
|
-
##
|
|
122
|
+
## Augmented Store API
|
|
110
123
|
|
|
111
124
|
When the plugin is active stores gain the following methods (see `PersistedStore` interface):
|
|
112
125
|
|
|
113
126
|
- `persistState(): Promise<void>` — Immediately persist the current store state (ignores empty values and excluded keys).
|
|
127
|
+
- `flushPersistedState(): Promise<void>` — Cancels a pending automatic persistence and immediately persists the current store state.
|
|
114
128
|
- `remember(): Promise<void>` — Load persisted state and apply it to the store (used on plugin init).
|
|
115
|
-
- `removePersistedState(): void
|
|
129
|
+
- `removePersistedState(): Promise<void>` — Delete the persisted entry for this store after any running write completes.
|
|
116
130
|
- `watch(): void` — Start watching for mutations (sets `watchMutation = true`).
|
|
117
131
|
- `stopWatch(): void` — Stop auto-persisting on mutations (sets `watchMutation = false`).
|
|
118
132
|
|
|
@@ -120,21 +134,23 @@ Note: encrypted properties are automatically decrypted when remembered (if a cry
|
|
|
120
134
|
|
|
121
135
|
---
|
|
122
136
|
|
|
123
|
-
##
|
|
137
|
+
## Encryption
|
|
138
|
+
|
|
139
|
+
Optionally supply a `cryptKey` when creating the plugin, e.g. `createPersistStatePlugin({ storage: 'localStorage', cryptKey: 'my-secret' })`.
|
|
140
|
+
The plugin uses the Web Crypto API (PBKDF2 + AES-GCM) to encrypt properties listed in `persistedPropertiesToEncrypt` on each store. Only the specified properties will be encrypted. New encrypted values use a versioned `v1:salt:iv:ciphertext` format with a random salt and IV for every value; records in the previous `iv:ciphertext` format remain readable.
|
|
124
141
|
|
|
125
|
-
|
|
126
|
-
The plugin uses the Web Crypto API (PBKDF2 + AES-GCM) to encrypt properties listed in `persistedPropertiesToEncrypt` on each store. Only the specified properties will be encrypted.
|
|
142
|
+
The storage adapter remains responsible for serializing the persisted record: Window Storage uses JSON and IndexedDB stores native values. Encryption encodes only the selected value and restores its JSON type (string, number, boolean, array, or object). Encrypted values must be JSON-serializable; functions, symbols, `undefined`, cyclic objects, and `BigInt` are not supported.
|
|
127
143
|
|
|
128
144
|
---
|
|
129
145
|
|
|
130
|
-
##
|
|
146
|
+
## Notes
|
|
131
147
|
|
|
132
148
|
- The plugin augments Pinia store definitions using the `pinia-plugin-subscription` helper. It adds `storeOptions` to Pinia's `DefineStoreOptionsBase` type through declaration merging.
|
|
133
149
|
- The $reset method is available for stores augmented by the plugin (also setup store 😁).
|
|
134
|
-
-
|
|
150
|
+
- With IndexedDB, `databaseName` identifies the application database, `objectStoreName` identifies the persisted record collection, and `persistenceKey` (or `$id`) identifies each record.
|
|
135
151
|
|
|
136
152
|
---
|
|
137
153
|
|
|
138
|
-
##
|
|
154
|
+
## License
|
|
139
155
|
|
|
140
156
|
MIT
|
package/SECURITY.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Reporting Security Vulnerabilities
|
|
4
4
|
|
|
5
|
-
If you discover a security vulnerability in pinia-plugin-
|
|
5
|
+
If you discover a security vulnerability in pinia-plugin-persist-state, please do **NOT** open a public GitHub issue. Instead, please email the maintainers privately.
|
|
6
6
|
|
|
7
7
|
**Email:** [Security Contact - reach out via GitHub profile]
|
|
8
8
|
|
|
@@ -30,7 +30,7 @@ We will:
|
|
|
30
30
|
|
|
31
31
|
## Security Best Practices
|
|
32
32
|
|
|
33
|
-
When using pinia-plugin-
|
|
33
|
+
When using pinia-plugin-persist-state:
|
|
34
34
|
|
|
35
35
|
1. **Keep Dependencies Updated:** Regularly update Pinia, Vue, and other dependencies to the latest versions
|
|
36
36
|
2. **Review Plugin Code:** Always review subscriber code before using in production
|
|
@@ -58,7 +58,7 @@ We monitor these dependencies for vulnerabilities and recommend keeping them upd
|
|
|
58
58
|
|
|
59
59
|
This policy covers:
|
|
60
60
|
|
|
61
|
-
- ✅ Code in the pinia-plugin-
|
|
61
|
+
- ✅ Code in the pinia-plugin-persist-state repository
|
|
62
62
|
- ✅ Published npm packages
|
|
63
63
|
- ✅ Security of the plugin API
|
|
64
64
|
|
|
@@ -72,4 +72,4 @@ This policy does NOT cover:
|
|
|
72
72
|
|
|
73
73
|
For general security questions or concerns, open a private security advisory on GitHub.
|
|
74
74
|
|
|
75
|
-
Thank you for helping keep pinia-plugin-
|
|
75
|
+
Thank you for helping keep pinia-plugin-persist-state secure! 🔒
|