pinia-plugin-subscription 0.0.0-alpha.4 → 0.0.0-beta.2

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/README.md CHANGED
@@ -1,102 +1,181 @@
1
- # Pinia Plugin Subscription
1
+ # pinia-plugin-subscription
2
2
 
3
- This project is a Pinia plugin for Vue.js designed to enhance the functionality of Pinia stores by providing subscription capabilities. It allows developers to subscribe to store changes and execute custom logic when the store state changes.
3
+ ![Pinia](https://img.shields.io/badge/Pinia-2.x-blue?logo=pinia) ![Vue](https://img.shields.io/badge/Vue-3.x-brightgreen?logo=vue.js) ![Nuxt](https://img.shields.io/badge/Nuxt-3.x-00C58E?logo=nuxt.js) ![Vitest](https://img.shields.io/badge/Vitest-tested-brightgreen?logo=vitest)
4
4
 
5
- ## Features
5
+ Pinia plugin for Vue.js that helps building Pinia plugins by centralizing subscriber registration and providing a `Store` base class for store helpers.
6
6
 
7
- - **Store Subscriptions**: Subscribe to Pinia store changes and execute custom logic.
8
- - **Debugging Support**: Enable debug mode to log store changes and subscriptions.
9
- - **Reset Store**: Reset the store to its initial state with custom callbacks.
7
+ This project provides:
8
+ - a lightweight mechanism to declare "subscribers" that are invoked when stores are registered or updated by Pinia;
9
+ - a `Store` base class (helper wrapper) to ease interacting with Pinia stores from subscribers or other plugin code;
10
+ - an API to create a Pinia plugin from a list of subscribers.
10
11
 
11
- ## Installation
12
+ The main goal is to offer a clear API for writing reusable Pinia plugins and to make it easy to extend stores from plugin code.
12
13
 
13
- To install the plugin, you can use npm or yarn:
14
+ ### Basic usage
14
15
 
15
- ```bash
16
- npm install pinia-plugin-subscription
17
- ```
16
+ 1. Import the plugin factory and register your subscribers with Pinia:
18
17
 
19
- or
18
+ ```typescript
19
+ // main.ts
20
+ import { createApp } from 'vue'
21
+ import { createPinia } from 'pinia'
22
+ import { createPlugin } from 'pinia-plugin-subscription'
23
+ import myStoreSubscriber from './src/core/my-store'
24
+ import App from './App.vue'
20
25
 
21
- ```bash
22
- yarn add pinia-plugin-subscription
23
- ```
26
+ const app = createApp(App)
27
+ const pinia = createPinia()
24
28
 
25
- ## Usage
29
+ // Register plugin (subscribers array, debug flag)
30
+ pinia.use(createPlugin([myStoreSubscriber]))
26
31
 
27
- ### Basic Usage
32
+ app.use(pinia)
33
+ app.mount('#app')
34
+ ```
28
35
 
29
- 1. **Import the Plugin**: Import the `createPlugin` function from the plugin.
36
+ 2. A subscriber example using a `Store` subclass:
30
37
 
31
38
  ```typescript
32
- import { createPlugin } from 'pinia-plugin-subscription';
33
- ```
39
+ // src/core/my-store.ts
40
+ import { Store } from 'pinia-plugin-subscription'
34
41
 
35
- 2. **Create a Subscriber**: Create a subscriber object with an `invoke` method that will be called when the store changes.
42
+ class MyStore extends Store {
43
+ constructor(store, options, debug = false) {
44
+ super(store, options, debug)
45
+ this.doSomething()
46
+ }
36
47
 
37
- ```typescript
38
- const subscriber = {
48
+ private doSomething() {
49
+ try {
50
+ console.log('store', this.store)
51
+ console.log('state', this.state)
52
+ console.log('store options', this.options)
53
+
54
+ // conditionaly property added
55
+ if(
56
+ (!this.stateHas('myProperty') || this.getStatePropertyValue('myProperty') === 'old-value')
57
+ && this.storeHas('myAction')
58
+ ){
59
+ this.addToState('myProperty', 'new-value')
60
+ }
61
+ } catch(e) {
62
+ this.debugLog(e)
63
+ }
64
+ }
65
+ }
66
+
67
+ export const myStoreSubscriber = {
39
68
  invoke: (context, debug) => {
40
- console.log('Store changed:', context.store.$state);
69
+ // create an instance of the Store subclass when options.storeOptions is present
70
+ const myStore = MyStore.customizeStore(context.store, context.options, debug)
71
+ if (!myStore) return
72
+
73
+ //Execute logic if store is augmented by plugin
74
+ doAnotherthing(myStore)
75
+ },
76
+ resetStoreCallback: (store) => {
77
+ console.log('[subscriber] store reset:', store?.$id)
41
78
  }
42
- };
79
+ }
43
80
  ```
44
81
 
45
- 3. **Use the Plugin**: Use the plugin in your Pinia instance.
82
+ ### Advanced usage
46
83
 
47
- ```typescript
48
- import { createApp } from 'vue';
49
- import { createPinia } from 'pinia';
50
- import App from './App.vue';
84
+ #### Debug mode
51
85
 
52
- const app = createApp(App);
53
- const pinia = createPinia();
86
+ Enable debug mode to log store changes and internal actions:
54
87
 
55
- pinia.use(createPlugin([subscriber]));
88
+ ```typescript
89
+ pinia.use(createPlugin([subscriber], true))
90
+ ```
56
91
 
57
- app.use(pinia);
58
- app.mount('#app');
59
- ```
92
+ #### Reset store callbacks
60
93
 
61
- ### Advanced Usage
94
+ Subscribers may define `resetStoreCallback` to run custom logic when a store reset is handled by the plugin.
62
95
 
63
- #### Debug Mode
96
+ ```typescript
97
+ const subscriber = {
98
+ invoke: (context, debug) => {
99
+ console.log('Store changed:', context.store.$state)
100
+ },
101
+ resetStoreCallback: (store) => {
102
+ console.log('Store reset:', store.$id)
103
+ }
104
+ }
105
+ ```
64
106
 
65
- Enable debug mode to log store changes and subscriptions.
107
+ ## API
66
108
 
67
- ```typescript
68
- pinia.use(createPlugin([subscriber], true));
69
- ```
109
+ ### `createPlugin(subscribers: PluginSubscriber[], debug?: boolean): PiniaPlugin`
110
+
111
+ Creates a Pinia plugin from the provided `subscribers` and optional `debug` flag. Each subscriber will be invoked with the Pinia plugin context when a store is registered.
112
+
113
+ ### `PluginSubscriber`
114
+
115
+ The `PluginSubscriber` interface has been extended: it's still an object with at least an `invoke(context: PiniaPluginContext, debug?: boolean)` method, but it can now expose several useful properties for plugins:
116
+
117
+ - **`resetStoreCallback?: (store?: Store) => void`**: callback invoked when the store is reset.
118
+ - **`storeOnActionSubscription?: StoreOnActionSubscription`**: provides a native Pinia `onAction` subscription via a getter returning `{ store, callback }`.
119
+ - **`storeMutationSubscription?: StoreMutationSubscription`**: provides a native mutation subscription (`store.$subscribe`) via a getter returning `{ store, callback }`.
120
+ - **`subscriptions: PluginSubscriptions | undefined`**: an object listing plugin-specific subscription functions (see `Store.addSubscription`).
121
+
122
+ These additions make it easier for subscribers to integrate with Pinia's native event cycle and to expose reusable extension points.
70
123
 
71
- #### Reset Store Callbacks
124
+ ## The `PluginSubscriber` class (abstract)
125
+
126
+ The project provides an abstract `PluginSubscriber` implementation ([src/plugins/pluginSubscriber.ts](src/plugins/pluginSubscriber.ts)) that makes it easy to create reusable subscribers:
127
+
128
+ - Constructor: `new PluginSubscriber(pluginName: string, createInstanceFunction: CreateInstance)`
129
+ - Main behavior: in `invoke(context, debug)` the class creates a helper instance (`Store` or subclass) via the `createInstanceFunction` (typically `MyStore.customizeStore`) and exposes on the instance:
130
+ - `subscriptions` (from `store.getSubscriptions()`)
131
+ - `storeMutationSubscription` (from `store.storeSubscribe`)
132
+ - `storeOnActionSubscription` (from `store.onAction`)
133
+ - optionally a `pluginCreated(store)` hook called after initialization
72
134
 
73
- Add custom callbacks to be executed when the store is reset.
74
135
 
75
136
  ```typescript
76
- const subscriber = {
77
- invoke: (context, debug) => {
78
- console.log('Store changed:', context.store.$state);
79
- },
80
- resetStoreCallback: (store) => {
81
- console.log('Store reset:', store);
137
+ import PluginSubscriber from './src/plugins/pluginSubscriber'
138
+ import StoreExtension from './src/extending-pinia-store/core/StoreExtension'
139
+ import { addStore } from './src/extending-pinia-store/plugins/stores'
140
+
141
+ class ExtendingStoreSubscriber extends PluginSubscriber<StoreExtension> {
142
+ constructor() {
143
+ super('extendsPiniaStore', StoreExtension.customizeStore.bind(StoreExtension))
144
+ this.pluginCreated = addStore
82
145
  }
83
- };
146
+ }
147
+
148
+ export const extendingStoreSubscriber = new ExtendingStoreSubscriber()
84
149
  ```
85
150
 
86
- ## API
151
+ Here `ExtendingStoreSubscriber` provides a `createInstanceFunction` that returns a `StoreExtension` instance if `options.storeOptions` is present, and sets a `pluginCreated` hook (here `addStore`) to run plugin-specific logic once the instance is ready.
87
152
 
88
- ### `createPlugin(subscribers: PluginSubscriber[], debug?: boolean): PiniaPlugin`
153
+ ## The `Store` class (summary)
89
154
 
90
- Creates a Pinia plugin with the given subscribers and debug mode.
155
+ The `Store` class (in [src/core/Store.ts](src/core/Store.ts)) is a base wrapper around a `PiniaStore` exposing helpers:
91
156
 
92
- - **subscribers**: An array of subscriber objects with an `invoke` method.
93
- - **debug**: Optional boolean to enable debug mode.
157
+ - Properties: `debug`, `options`, `state`, `store`.
158
+ - Useful methods:
159
+ - `addToState(name, value?)`: adds a property to the store state and exposes it as a `Ref` on the store when appropriate.
160
+ - `addSubscription(pluginName, subscription)`: registers a plugin-specific subscription function (accessible via `getSubscriptions`).
161
+ - `getSubscriptions()`: returns subscriptions registered with `addSubscription` (or `undefined`).
162
+ - `storeSubscribe` (getter/setter): exposes a mutation subscription callback (`store.$subscribe`) as a factory returning `{ store, callback }`.
163
+ - `onAction` (getter/setter): exposes a Pinia `onAction` callback in the same form.
164
+ - `static customizeStore(store, options, debug?)`: instantiate the class (or subclass) when `options.storeOptions` is present.
165
+ - `debugLog(message, args)`: conditional logging when `debug` is true.
166
+ - `hasDeniedFirstChar(property)`, `getOption(...)`, `getValue(value)`, `getStatePropertyValue(...)`.
167
+ - `isOptionApi()`: true when the store uses Pinia Options API.
94
168
 
95
- ### `PluginSubscriber`
169
+ Other small helpers exposed: `stateHas(property)`, `storeHas(property)` and `getValue` to retrieve the real value of a `Ref` or a raw value.
96
170
 
97
- An interface for subscriber objects.
171
+ `Store.customizeStore(...)` is the recommended entry point used by subscribers to create store helper instances.
98
172
 
99
- - **invoke**: A method that will be called when the store changes. It receives the Pinia plugin context and debug mode as arguments.
100
- - **resetStoreCallback**: Optional method that will be called when the store is reset. It receives the store as an argument.
173
+
174
+ ## Testing
101
175
 
176
+ This plugin is tested with Vitest. Coverage (from the included coverage report at [coverage/index.html](coverage/index.html)):
102
177
 
178
+ - Statements: **97.64%** (83/85)
179
+ - Branches: **86.53%** (45/52)
180
+ - Functions: **100%** (38/38)
181
+ - Lines: **97.59%** (81/83)