pinia-plugin-subscription 0.2.1 → 1.0.0-beta.1
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 +37 -1
- package/README.md +289 -4
- package/SECURITY.md +19 -1
- package/dist/chunks/Store-DHUAJv-P.js +257 -0
- package/dist/chunks/Store-DHUAJv-P.js.map +1 -0
- package/dist/core/PluginSubscriber.d.ts +39 -12
- package/dist/core/PluginSubscription.d.ts +20 -5
- package/dist/core/Store.d.ts +111 -12
- package/dist/factories/console-trace-listener.d.ts +7 -0
- package/dist/factories/trace-listener.d.ts +16 -0
- package/dist/factories/trace-registry.d.ts +17 -0
- package/dist/helpers/index.d.ts +5 -0
- package/dist/helpers.js +345 -5
- package/dist/helpers.js.map +1 -1
- package/dist/lib/main.d.ts +1 -3
- package/dist/pinia-plugin-subscription.js +208 -216
- package/dist/pinia-plugin-subscription.js.map +1 -1
- package/dist/plugins/createHydrationPlugin.d.ts +7 -0
- package/dist/plugins/createPlugin.d.ts +9 -2
- package/dist/system/Tracer.d.ts +20 -0
- package/dist/system/log.d.ts +12 -1
- package/dist/types/index.d.ts +17 -6
- package/dist/types/plugin.d.ts +119 -7
- package/dist/types/store.d.ts +3 -8
- package/dist/types/trace.d.ts +121 -0
- package/dist/utils/store.d.ts +2 -1
- package/docs/authoring-plugins.md +53 -24
- package/docs/using-plugins.md +76 -19
- package/package.json +3 -2
- package/dist/chunks/index-DKdl-fiq.js +0 -337
- package/dist/chunks/index-DKdl-fiq.js.map +0 -1
- package/dist/system/Debug.d.ts +0 -13
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { AnyObject } from './index';
|
|
2
|
+
import type Tracer from '../system/Tracer';
|
|
3
|
+
export interface AddTraceListenerOptions {
|
|
4
|
+
filterMode?: TraceListenerFilterMode;
|
|
5
|
+
groupBy?: TraceListenerGroupBy;
|
|
6
|
+
}
|
|
7
|
+
export interface ConsoleTraceEventArgs extends Omit<TraceEvent, 'level' | 'timestamp'> {
|
|
8
|
+
}
|
|
9
|
+
export type ConsoleTraceEvent = Array<string | ConsoleTraceEventArgs>;
|
|
10
|
+
/**
|
|
11
|
+
* A trace listener that supports grouping of trace events.
|
|
12
|
+
*/
|
|
13
|
+
export interface ConsoleTraceGroupListener extends Omit<TraceListener, 'filter'> {
|
|
14
|
+
createGroup: (key: string) => void;
|
|
15
|
+
logGroup: (key: string) => void;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Severity of a trace event.
|
|
19
|
+
* `error` events are delivered to matching listeners, or reported with `console.error` when none match.
|
|
20
|
+
*/
|
|
21
|
+
export type TraceLevel = 'debug' | 'error';
|
|
22
|
+
/**
|
|
23
|
+
* Cheap descriptor of an event, built before the payload is resolved.
|
|
24
|
+
* Filters receive this object so that discarded events never allocate a payload.
|
|
25
|
+
*/
|
|
26
|
+
export interface TraceEventMetadata {
|
|
27
|
+
/** Label describing the event, e.g. `Subscription:Delivery`. */
|
|
28
|
+
label: string;
|
|
29
|
+
/** Severity of the trace event. */
|
|
30
|
+
level: TraceLevel;
|
|
31
|
+
/** Structured, colon separated identifier, e.g. `subscription:delivery`. */
|
|
32
|
+
namespace: string;
|
|
33
|
+
/** Instance the event belongs to, usually a Pinia `store.$id`. */
|
|
34
|
+
scope?: string;
|
|
35
|
+
/** Emitting class name, e.g. `PluginSubscription`. */
|
|
36
|
+
source: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A resolved trace event, handed over to listeners.
|
|
40
|
+
*/
|
|
41
|
+
export interface TraceEvent extends TraceEventMetadata {
|
|
42
|
+
error?: unknown;
|
|
43
|
+
payload?: AnyObject;
|
|
44
|
+
timestamp: number;
|
|
45
|
+
}
|
|
46
|
+
type TraceFilterCriterionComparator = 'equals' | 'contains' | 'startsWith' | 'endsWith';
|
|
47
|
+
export interface TraceFilterCriterion {
|
|
48
|
+
comparator: TraceFilterCriterionComparator;
|
|
49
|
+
target: keyof TraceEventMetadata;
|
|
50
|
+
value: string;
|
|
51
|
+
}
|
|
52
|
+
export interface TraceFilterFactoryCriterion extends Omit<TraceFilterCriterion, 'comparator'> {
|
|
53
|
+
comparator?: TraceFilterCriterionComparator;
|
|
54
|
+
}
|
|
55
|
+
export type TraceFilterFactoryParam = {
|
|
56
|
+
handler?: TraceHandler;
|
|
57
|
+
filter: TraceFilter | TraceFilterFactoryCriterion[];
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Event data. Prefer the function form: it is only invoked when a listener
|
|
61
|
+
* actually consumes the event, keeping unobserved tracing allocation free.
|
|
62
|
+
*/
|
|
63
|
+
export type TracePayload = AnyObject | (() => AnyObject);
|
|
64
|
+
/**
|
|
65
|
+
* Determines whether a trace event should be delivered to a listener.
|
|
66
|
+
* @param event The metadata of the trace event.
|
|
67
|
+
* @returns `true` if the event should be delivered to the listener, otherwise `false`.
|
|
68
|
+
*/
|
|
69
|
+
export type TraceFilter = (event: TraceEventMetadata) => boolean;
|
|
70
|
+
export interface TraceGroupListener extends ConsoleTraceGroupListener, TraceListener {
|
|
71
|
+
groupBy: TraceListenerGroupBy;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Handles a trace event.
|
|
75
|
+
* @param event The resolved trace event to handle.
|
|
76
|
+
*/
|
|
77
|
+
export type TraceHandler = (event: TraceEvent) => void;
|
|
78
|
+
export interface TraceListener {
|
|
79
|
+
/** Evaluated on every event; return `true` to receive it. */
|
|
80
|
+
filter: TraceFilter;
|
|
81
|
+
/** Handles the trace event when it passes the filter. */
|
|
82
|
+
handler: TraceHandler;
|
|
83
|
+
}
|
|
84
|
+
export type TraceListenerFilterMode = 'every' | 'some';
|
|
85
|
+
export type TraceListenerGroupBy = keyof TraceEventMetadata;
|
|
86
|
+
/** Removes a previously registered listener. */
|
|
87
|
+
export type TraceListenerRemover = () => void;
|
|
88
|
+
export type TraceRegistry = {
|
|
89
|
+
/**
|
|
90
|
+
* Registers a trace listener and returns its remover.
|
|
91
|
+
* Listeners are evaluated in registration order.
|
|
92
|
+
* @param listener The trace listener to register.
|
|
93
|
+
* @returns A function that removes the registered listener when called.
|
|
94
|
+
*/
|
|
95
|
+
addTraceListener: (listener: TraceListener | TraceFilterFactoryParam, filterMode?: 'every' | 'some') => TraceListenerRemover;
|
|
96
|
+
/**
|
|
97
|
+
* Clears all registered trace listeners.
|
|
98
|
+
*/
|
|
99
|
+
clearTraceListeners: () => void;
|
|
100
|
+
/**
|
|
101
|
+
* Creates a new tracer instance.
|
|
102
|
+
* @param source The source of the tracer, usually the class name.
|
|
103
|
+
* @param options Optional tracer options.
|
|
104
|
+
* @returns A new tracer instance.
|
|
105
|
+
*/
|
|
106
|
+
createTracer: (source: string, options?: TracerOptions) => Tracer;
|
|
107
|
+
/**
|
|
108
|
+
* Checks if there are any registered trace listeners.
|
|
109
|
+
* @returns True if there are registered trace listeners, otherwise false.
|
|
110
|
+
*/
|
|
111
|
+
hasTraceListeners: () => boolean;
|
|
112
|
+
};
|
|
113
|
+
export interface TracerHandler {
|
|
114
|
+
closeGroup: (payload: TraceEvent) => undefined;
|
|
115
|
+
createTracer: (source: string) => Tracer;
|
|
116
|
+
startGroup: (payload: TraceEvent) => undefined;
|
|
117
|
+
}
|
|
118
|
+
export interface TracerOptions {
|
|
119
|
+
scope?: string;
|
|
120
|
+
}
|
|
121
|
+
export {};
|
package/dist/utils/store.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { DefineStoreOptions, SetupStoreDefinition, StateTree, Store, StoreDefinition, _GettersTree } from "pinia";
|
|
2
2
|
import type { AnyObject } from "../types";
|
|
3
|
-
import type { DefineAStoreDefinition, DefineAStoreSetupContext, EmptyExtensions,
|
|
3
|
+
import type { DefineAStoreDefinition, DefineAStoreSetupContext, EmptyExtensions, StoreOptions } from "../types/store";
|
|
4
|
+
import type { PluginStoreOptions } from "../types/plugin";
|
|
4
5
|
export declare const itemState: {
|
|
5
6
|
'@id': undefined;
|
|
6
7
|
id: undefined;
|
|
@@ -27,7 +27,7 @@ Two authoring styles are available:
|
|
|
27
27
|
no classes.
|
|
28
28
|
2. **`PluginSubscriber` abstract class + `Store` subclass** — recommended
|
|
29
29
|
for richer plugins: the `Store` subclass wraps the pinia store with
|
|
30
|
-
helpers (state extension, subscriptions,
|
|
30
|
+
helpers (state extension, subscriptions, structured tracing).
|
|
31
31
|
|
|
32
32
|
## Your first subscriber: a plain object
|
|
33
33
|
|
|
@@ -37,7 +37,7 @@ Two authoring styles are available:
|
|
|
37
37
|
export const myStoreSubscriber = {
|
|
38
38
|
name: 'my-plugin',
|
|
39
39
|
|
|
40
|
-
invoke: (context
|
|
40
|
+
invoke: (context) => {
|
|
41
41
|
// context contains `store`, `options`, `pinia`
|
|
42
42
|
console.log('store registered', context.store.$id)
|
|
43
43
|
|
|
@@ -58,7 +58,7 @@ import type { PluginSubscriberInterface } from 'pinia-plugin-subscription'
|
|
|
58
58
|
export const myStoreSubscriber: PluginSubscriberInterface = {
|
|
59
59
|
name: 'my-plugin',
|
|
60
60
|
|
|
61
|
-
invoke: (context
|
|
61
|
+
invoke: (context) => {
|
|
62
62
|
console.log('store registered', context.store.$id)
|
|
63
63
|
|
|
64
64
|
return true
|
|
@@ -82,17 +82,16 @@ pinia.use(createPlugin([myStoreSubscriber]))
|
|
|
82
82
|
|
|
83
83
|
| Member | Type | Description |
|
|
84
84
|
| --- | --- | --- |
|
|
85
|
-
| `name` (required) | `string` | Unique plugin name
|
|
86
|
-
| `invoke` (required) | `(context: PiniaPluginContext
|
|
85
|
+
| `name` (required) | `string` | Unique plugin name. |
|
|
86
|
+
| `invoke` (required) | `(context: PiniaPluginContext) => boolean` | Called when a store is registered. Return `false` to skip the store. |
|
|
87
87
|
| `execution` | `PluginExecutionOptions` | Where/when the subscriber runs — see [Execution policy & SSR](#execution-policy--ssr). |
|
|
88
88
|
| `hydrationScheduler` | `(run: () => void) => void` | Custom scheduler used when hydration is deferred. |
|
|
89
|
-
| `hydrate` | `(context
|
|
90
|
-
| `afterHydration` | `(context
|
|
89
|
+
| `hydrate` | `(context) => void \| Promise<void>` | SSR-safe initialization hook; guaranteed to run before `afterHydration`. |
|
|
90
|
+
| `afterHydration` | `(context) => void \| Promise<void>` | Post-hydration lifecycle hook. |
|
|
91
91
|
| `resetStoreCallback` | `(store?: Store) => void` | Custom logic executed when a registered store is reset. |
|
|
92
92
|
| `storeOnActionSubscription` | `{ store, callback }` (getter) | Action subscription forwarded to the returned store's `$onAction`, including after deferred hydration; removed on store disposal. |
|
|
93
93
|
| `storeMutationSubscription` | `{ store, callback }` (getter) | Mutation subscription forwarded to pinia's `$subscribe`. |
|
|
94
94
|
| `subscriptions` | `Record<string, PluginSubscription>` | Plugin-specific subscription functions exposed to other plugins. |
|
|
95
|
-
| `console` | `Console` | Custom console used for debug logging. |
|
|
96
95
|
|
|
97
96
|
All members except `name` and `invoke` are optional.
|
|
98
97
|
|
|
@@ -117,7 +116,7 @@ checks when they call your plugin's custom methods.
|
|
|
117
116
|
Constructor:
|
|
118
117
|
|
|
119
118
|
```ts
|
|
120
|
-
constructor(pluginName: string, createInstance: CreateInstance
|
|
119
|
+
constructor(pluginName: string, createInstance: CreateInstance)
|
|
121
120
|
```
|
|
122
121
|
|
|
123
122
|
| Member | Kind | Description |
|
|
@@ -136,20 +135,19 @@ constructor(pluginName: string, createInstance: CreateInstance, pluginConsole?:
|
|
|
136
135
|
import { PluginSubscriber, Store } from 'pinia-plugin-subscription'
|
|
137
136
|
|
|
138
137
|
class MyPlugin extends Store {
|
|
139
|
-
constructor(store, options
|
|
140
|
-
super(store, options
|
|
138
|
+
constructor(store, options) {
|
|
139
|
+
super(store, options)
|
|
141
140
|
this.doSomething()
|
|
142
141
|
}
|
|
143
142
|
|
|
144
143
|
doSomething() {
|
|
145
|
-
this.
|
|
144
|
+
this.trace('my-plugin:doSomething', () => ({ storeId: this.store.$id }))
|
|
146
145
|
}
|
|
147
146
|
}
|
|
148
147
|
|
|
149
148
|
class MyPluginSubscriber extends PluginSubscriber {
|
|
150
149
|
constructor() {
|
|
151
|
-
super('my-plugin', (store, options
|
|
152
|
-
new MyPlugin(store, options, debug, customConsole))
|
|
150
|
+
super('my-plugin', (store, options) => new MyPlugin(store, options))
|
|
153
151
|
}
|
|
154
152
|
}
|
|
155
153
|
|
|
@@ -165,13 +163,13 @@ class MyPlugin extends Store {
|
|
|
165
163
|
protected override _className: string = 'MyPlugin'
|
|
166
164
|
protected static override _requiredKeys?: string[] = ['my-plugin-option']
|
|
167
165
|
|
|
168
|
-
constructor(store, options
|
|
169
|
-
super(store, options
|
|
166
|
+
constructor(store, options) {
|
|
167
|
+
super(store, options)
|
|
170
168
|
this.doSomething()
|
|
171
169
|
}
|
|
172
170
|
|
|
173
171
|
doSomething(): void {
|
|
174
|
-
this.
|
|
172
|
+
this.trace('my-plugin:doSomething', () => ({ storeId: this.store.$id }))
|
|
175
173
|
}
|
|
176
174
|
}
|
|
177
175
|
|
|
@@ -195,7 +193,7 @@ export const myStoreSubscriber = new MyPluginSubscriber()
|
|
|
195
193
|
|
|
196
194
|
`Store` wraps a pinia store (`PiniaStore`) and exposes:
|
|
197
195
|
|
|
198
|
-
**Properties:** `
|
|
196
|
+
**Properties:** `options`, `state`, `store`.
|
|
199
197
|
|
|
200
198
|
**Methods:**
|
|
201
199
|
|
|
@@ -208,8 +206,10 @@ export const myStoreSubscriber = new MyPluginSubscriber()
|
|
|
208
206
|
| `getStatePropertyValue(propertyName)` | Reads a state property, unwrapping refs. |
|
|
209
207
|
| `storeSubscribe` (getter/setter) | Factory for pinia's `$subscribe` (`{ store, callback }`). |
|
|
210
208
|
| `onAction` (getter/setter) | Factory for pinia's `$onAction` (`{ store, callback }`). |
|
|
211
|
-
| `static customizeStore(store, options
|
|
212
|
-
| `
|
|
209
|
+
| `static customizeStore(store, options)` | Recommended factory; guarded by `_requiredKeys` (see above). |
|
|
210
|
+
| `trace(label, payload?, scope?, namespace?)` | Emits a structured trace event. The default scope is the wrapped store ID. |
|
|
211
|
+
| `traceError(label, error, payload?, scope?, namespace?)` | Emits an error event; if no listener matches, reports it with `console.error` without rethrowing it. |
|
|
212
|
+
| `classNameAddedToTraceNamespace` (getter/setter) | Controls whether the store class name is prefixed to trace labels; enabled by default. |
|
|
213
213
|
| `stateHas(property)` / `storeHas(property)` | Safe `hasOwnProperty` checks on state / store. |
|
|
214
214
|
| `getValue(value)` | Unwraps a ref or returns the value as-is. |
|
|
215
215
|
| `isOptionApi()` | Whether the store uses the options API. |
|
|
@@ -234,7 +234,7 @@ export const persistedStateSubscriber = {
|
|
|
234
234
|
hydrationScheduler: (run) => {
|
|
235
235
|
nextTick(() => run())
|
|
236
236
|
},
|
|
237
|
-
invoke: (context
|
|
237
|
+
invoke: (context) => {
|
|
238
238
|
// ...
|
|
239
239
|
return true
|
|
240
240
|
}
|
|
@@ -256,7 +256,7 @@ export const persistedStateSubscriber: PluginSubscriberInterface = {
|
|
|
256
256
|
hydrationScheduler: (run) => {
|
|
257
257
|
nextTick(() => run())
|
|
258
258
|
},
|
|
259
|
-
invoke: (context
|
|
259
|
+
invoke: (context) => {
|
|
260
260
|
// ...
|
|
261
261
|
return true
|
|
262
262
|
}
|
|
@@ -360,6 +360,35 @@ const mySubscriber = {
|
|
|
360
360
|
This keeps the server render deterministic and prevents browser-only
|
|
361
361
|
initialization from crashing Nuxt or SSR builds.
|
|
362
362
|
|
|
363
|
+
### Emitting trace events
|
|
364
|
+
|
|
365
|
+
Use `trace()` and `traceError()` from a `Store` subclass to emit structured
|
|
366
|
+
events. The first argument is a human-readable label; by default the store
|
|
367
|
+
class name is prefixed to it and the normalized label becomes the namespace.
|
|
368
|
+
Pass an explicit fourth `namespace` argument to control the namespace, or set
|
|
369
|
+
`classNameAddedToTraceNamespace = false` to omit the class prefix. Prefer a
|
|
370
|
+
payload factory so data is not built unless a listener consumes the event:
|
|
371
|
+
|
|
372
|
+
```ts
|
|
373
|
+
class CartStore extends Store {
|
|
374
|
+
reportItems(): void {
|
|
375
|
+
this.trace(
|
|
376
|
+
'cart:items',
|
|
377
|
+
() => ({ items: this.state.items }),
|
|
378
|
+
this.store.$id,
|
|
379
|
+
'cart:items'
|
|
380
|
+
)
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
`createTracerRegistry()` and `createConsoleTraceListener()` are available
|
|
386
|
+
from `pinia-plugin-subscription/helpers`. Register listeners on a registry
|
|
387
|
+
and pass its `createTracer` factory through `createPlugin()` options to
|
|
388
|
+
connect them to plugin and store events. Listener filters can be callbacks
|
|
389
|
+
over event metadata or criteria using `equals`, `contains`, `startsWith` and
|
|
390
|
+
`endsWith` comparisons.
|
|
391
|
+
|
|
363
392
|
## Typing per-store options: `StoreOptionsExtensions` (TypeScript)
|
|
364
393
|
|
|
365
394
|
This package is the only one allowed to augment pinia's
|
|
@@ -395,7 +424,7 @@ Guidelines:
|
|
|
395
424
|
- Always declare **optional** keys with names specific enough to avoid
|
|
396
425
|
collisions (prefer `myPluginOption` over `options`).
|
|
397
426
|
- At runtime, merged options are delivered to your subscriber's
|
|
398
|
-
`invoke(context
|
|
427
|
+
`invoke(context)` through `context.options.storeOptions` — no
|
|
399
428
|
extra wiring needed.
|
|
400
429
|
- Never redeclare `DefineStoreOptionsBase` or `PiniaCustomProperties`; only
|
|
401
430
|
this package owns those augmentations.
|
|
@@ -403,6 +432,6 @@ Guidelines:
|
|
|
403
432
|
## Reference implementation
|
|
404
433
|
|
|
405
434
|
The demo app ships a complete plugin implementation in
|
|
406
|
-
[`
|
|
435
|
+
[`demo/`](../demo/): a
|
|
407
436
|
`PluginSubscriber` subclass, a `Store` subclass, option typing and SSR
|
|
408
437
|
guards. Run `npm run dev` to explore it live.
|
package/docs/using-plugins.md
CHANGED
|
@@ -22,8 +22,8 @@ Plugins built on `pinia-plugin-subscription` share a common contract:
|
|
|
22
22
|
- **`$reset` on registered stores** — every store registered by the plugin
|
|
23
23
|
gains a `$reset()` method that restores its initial state, including
|
|
24
24
|
setup-style stores where pinia does not provide one natively.
|
|
25
|
-
- **
|
|
26
|
-
|
|
25
|
+
- **Runtime-filtered tracing** — register trace listeners and filter events by
|
|
26
|
+
source, namespace, scope, or level.
|
|
27
27
|
- **SSR-safe execution** — each plugin declares where (`client`, `server`
|
|
28
28
|
or `both`) and when (`immediate` or deferred after hydration) it runs.
|
|
29
29
|
- **State rollback on action failure** — actions listed in the
|
|
@@ -46,15 +46,14 @@ Compatible plugins expose **subscribers** that are passed to
|
|
|
46
46
|
```js
|
|
47
47
|
import { createApp } from 'vue'
|
|
48
48
|
import { createPinia } from 'pinia'
|
|
49
|
-
import { createPlugin
|
|
49
|
+
import { createPlugin } from 'pinia-plugin-subscription'
|
|
50
50
|
import { myStoreSubscriber } from './plugins/my-store'
|
|
51
51
|
import App from './App.vue'
|
|
52
52
|
|
|
53
53
|
const app = createApp(App)
|
|
54
54
|
const pinia = createPinia()
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
pinia.use(createPlugin([myStoreSubscriber], [PLUGIN_NAME]))
|
|
56
|
+
pinia.use(createPlugin([myStoreSubscriber]))
|
|
58
57
|
|
|
59
58
|
app.use(pinia)
|
|
60
59
|
app.mount('#app')
|
|
@@ -66,12 +65,12 @@ The TypeScript version is identical — `createPlugin()` is fully typed and
|
|
|
66
65
|
requires no generics:
|
|
67
66
|
|
|
68
67
|
```ts
|
|
69
|
-
import { createPlugin
|
|
68
|
+
import { createPlugin } from 'pinia-plugin-subscription'
|
|
70
69
|
import type { PluginSubscriberInterface } from 'pinia-plugin-subscription'
|
|
71
70
|
|
|
72
71
|
const subscribers: PluginSubscriberInterface[] = [myStoreSubscriber]
|
|
73
72
|
|
|
74
|
-
pinia.use(createPlugin(subscribers
|
|
73
|
+
pinia.use(createPlugin(subscribers))
|
|
75
74
|
```
|
|
76
75
|
|
|
77
76
|
## Defining stores: `defineAStore`
|
|
@@ -232,9 +231,7 @@ export const useMyStore = defineAStoreCtx('myStore', (ctx) => {
|
|
|
232
231
|
|
|
233
232
|
`defineAStoreCtx()` enables the `enhancedStore` store option automatically.
|
|
234
233
|
The internal setup-context lookup is cleaned up as soon as the store is
|
|
235
|
-
associated (and on store dispose), which limits map growth over time.
|
|
236
|
-
`storeOptions.debug` is `true`, setup-context map size transitions are
|
|
237
|
-
logged for observability.
|
|
234
|
+
associated (and on store dispose), which limits map growth over time.
|
|
238
235
|
|
|
239
236
|
## `$reset` on registered stores
|
|
240
237
|
|
|
@@ -316,17 +313,46 @@ try {
|
|
|
316
313
|
(forwarded to the action via `apply()`).
|
|
317
314
|
- The original error is rethrown after the state is restored.
|
|
318
315
|
|
|
319
|
-
##
|
|
316
|
+
## Tracing
|
|
320
317
|
|
|
321
|
-
|
|
322
|
-
`createPlugin()`:
|
|
318
|
+
Register listeners independently from plugin construction:
|
|
323
319
|
|
|
324
320
|
```js
|
|
325
|
-
|
|
321
|
+
import {
|
|
322
|
+
createConsoleTraceListener,
|
|
323
|
+
createTracerRegistry
|
|
324
|
+
} from 'pinia-plugin-subscription/helpers'
|
|
325
|
+
import {
|
|
326
|
+
createPlugin
|
|
327
|
+
} from 'pinia-plugin-subscription'
|
|
328
|
+
|
|
329
|
+
const traceRegistry = createTracerRegistry()
|
|
330
|
+
|
|
331
|
+
traceRegistry.addTraceListener({
|
|
332
|
+
...createConsoleTraceListener(),
|
|
333
|
+
filter: event => event.scope === 'cart'
|
|
334
|
+
})
|
|
335
|
+
|
|
336
|
+
pinia.use(createPlugin([myStoreSubscriber], {
|
|
337
|
+
createTracer: traceRegistry.createTracer
|
|
338
|
+
}))
|
|
326
339
|
```
|
|
327
340
|
|
|
328
|
-
|
|
329
|
-
|
|
341
|
+
Filters run in real time and can target a source, namespace, store scope, or
|
|
342
|
+
trace level without passing diagnostic options through subscribers.
|
|
343
|
+
You can also use comparison criteria (`equals`, `contains`, `startsWith` or
|
|
344
|
+
`endsWith`) instead of a filter callback; criteria are combined with `every`
|
|
345
|
+
by default or `some` when requested. If criteria are provided without a
|
|
346
|
+
handler, the registry uses its styled console listener.
|
|
347
|
+
|
|
348
|
+
```js
|
|
349
|
+
traceRegistry.addTraceListener({
|
|
350
|
+
filter: [
|
|
351
|
+
{ target: 'scope', value: 'cart' },
|
|
352
|
+
{ target: 'namespace', comparator: 'startsWith', value: 'pluginsubscription:subscription:' }
|
|
353
|
+
]
|
|
354
|
+
}, 'every')
|
|
355
|
+
```
|
|
330
356
|
|
|
331
357
|
## SSR / Nuxt
|
|
332
358
|
|
|
@@ -334,16 +360,48 @@ The package is SSR-safe by design. Each compatible plugin declares its own
|
|
|
334
360
|
execution policy, so nothing browser-only runs on the server unless the
|
|
335
361
|
plugin explicitly allows it.
|
|
336
362
|
|
|
363
|
+
For request isolation, create the app, Pinia instance, trace registry, and
|
|
364
|
+
plugin inside the per-request app factory. Do not store the registry or the
|
|
365
|
+
`createPlugin()` result at module scope: both retain request-associated
|
|
366
|
+
listeners or plugin state. A new registry per request also avoids races
|
|
367
|
+
between concurrent requests; do not clear a shared registry when one request
|
|
368
|
+
finishes.
|
|
369
|
+
|
|
370
|
+
```js
|
|
371
|
+
import { createSSRApp } from 'vue'
|
|
372
|
+
import { createPinia } from 'pinia'
|
|
373
|
+
import { createPlugin } from 'pinia-plugin-subscription'
|
|
374
|
+
import { createTracerRegistry } from 'pinia-plugin-subscription/helpers'
|
|
375
|
+
import App from './App.vue'
|
|
376
|
+
import { subscribers } from './subscribers'
|
|
377
|
+
|
|
378
|
+
export function createRequestApp(traceListener) {
|
|
379
|
+
const app = createSSRApp(App)
|
|
380
|
+
const pinia = createPinia()
|
|
381
|
+
const traceRegistry = createTracerRegistry()
|
|
382
|
+
|
|
383
|
+
traceRegistry.addTraceListener(traceListener)
|
|
384
|
+
pinia.use(createPlugin(subscribers, {
|
|
385
|
+
createTracer: traceRegistry.createTracer
|
|
386
|
+
}))
|
|
387
|
+
app.use(pinia)
|
|
388
|
+
|
|
389
|
+
return { app, pinia }
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
Call `createRequestApp()` once for each incoming SSR request. The request's
|
|
394
|
+
listener is then reachable only through that request's registry and plugin.
|
|
395
|
+
|
|
337
396
|
When a plugin needs a runtime-specific scheduler or environment override —
|
|
338
397
|
without forcing every app to re-declare the plugin's execution policy —
|
|
339
398
|
register it through the dedicated hydration helper:
|
|
340
399
|
|
|
341
400
|
```js
|
|
342
401
|
import { nextTick } from 'vue'
|
|
343
|
-
import { createHydrationPlugin
|
|
402
|
+
import { createHydrationPlugin } from 'pinia-plugin-subscription'
|
|
344
403
|
|
|
345
404
|
pinia.use(createHydrationPlugin([persistedStateSubscriber], {
|
|
346
|
-
debug: [PLUGIN_NAME],
|
|
347
405
|
hydrationScheduler: (run) => {
|
|
348
406
|
nextTick(() => run())
|
|
349
407
|
}
|
|
@@ -355,7 +413,6 @@ pinia.use(createHydrationPlugin([persistedStateSubscriber], {
|
|
|
355
413
|
|
|
356
414
|
| Option | Type | Description |
|
|
357
415
|
| --- | --- | --- |
|
|
358
|
-
| `debug` | `string[]` | Plugin names to debug. |
|
|
359
416
|
| `execution` | `PluginExecutionOptions` | Global execution policy override. |
|
|
360
417
|
| `hydrationScheduler` | `(run: () => void) => void` | Scheduler used for deferred hydration. |
|
|
361
418
|
| `runtimeEnvironment` | `'client' \| 'server'` | Forces the runtime environment. |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pinia-plugin-subscription",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-beta.1",
|
|
4
4
|
"description": "Pinia plugin for Vue.js that helps building Pinia plugins by centralizing subscriber registration and providing a Store base class for store helpers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -69,7 +69,8 @@
|
|
|
69
69
|
"dev:library": "vite",
|
|
70
70
|
"test": "vitest",
|
|
71
71
|
"coverage": "vitest run --coverage",
|
|
72
|
-
"build": "vitest && vite build && tsc --emitDeclarationOnly --outDir dist && node scripts/measure-bundle.mjs",
|
|
72
|
+
"build": "vitest && vite build && tsc --emitDeclarationOnly --outDir dist && npm run check:leaks && node scripts/measure-bundle.mjs",
|
|
73
|
+
"check:leaks": "node scripts/check-dist-leaks.mjs",
|
|
73
74
|
"bundle:check": "vite build --config vite.config.ts && node scripts/measure-bundle.mjs",
|
|
74
75
|
"build:demo": "vite --config vite.demo.config.ts build",
|
|
75
76
|
"preview": "vite preview --config vite.demo.config.ts"
|