pinia-react 1.5.2 → 2.0.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/dist/index.js CHANGED
@@ -1,385 +1,392 @@
1
- // src/createPinia.ts
2
- import { effectScope, markRaw, ref } from "@maoism/runtime-core";
3
-
4
1
  // src/rootStore.ts
5
- var getActivePinia = () => activePinia;
6
2
  var activePinia;
7
- function setActivePinia(_pinia) {
8
- activePinia = _pinia;
3
+ function setActivePinia(pinia) {
4
+ activePinia = pinia;
5
+ }
6
+ function getActivePinia() {
7
+ if (!activePinia) {
8
+ throw new Error(
9
+ "[pinia-react] getActivePinia was called with no active Pinia. Did you forget to install pinia?\nconst pinia = createPinia() or createPinia() first.\n"
10
+ );
11
+ }
12
+ return activePinia;
9
13
  }
10
14
 
11
15
  // src/createPinia.ts
12
16
  function createPinia() {
13
- const scope = effectScope(true);
14
- const state = scope.run(() => ref({}));
17
+ const state = {};
15
18
  const _p = [];
16
- const pinia = markRaw({
19
+ const _s = /* @__PURE__ */ new Map();
20
+ const _scopes = /* @__PURE__ */ new Map();
21
+ const pinia = {
17
22
  use(plugin) {
18
23
  _p.push(plugin);
19
24
  return this;
20
25
  },
21
26
  _p,
22
- _e: scope,
23
- _s: /* @__PURE__ */ new Map(),
27
+ _s,
28
+ _scopes,
24
29
  state
25
- });
30
+ };
26
31
  setActivePinia(pinia);
27
32
  return pinia;
28
33
  }
29
34
 
30
35
  // src/store.ts
31
- import {
32
- activeEffect,
33
- computed,
34
- effectScope as effectScope2,
35
- markRaw as markRaw2,
36
- nextTick,
37
- ReactiveEffect,
38
- reactive,
39
- toRaw,
40
- toRefs,
41
- watch
42
- } from "@maoism/runtime-core";
43
- import { useCallback, useEffect, useId, useRef, useSyncExternalStore } from "react";
44
-
45
- // src/subscription.ts
46
- var noop = () => {
47
- };
48
- function addSubscription(activeComponentCleanUp2, subscriptions, callback, detached, onCleanup = noop) {
49
- subscriptions.add(callback);
50
- const removeSubscription = () => {
51
- subscriptions.delete(callback);
52
- onCleanup();
53
- };
54
- if (!detached) {
55
- activeComponentCleanUp2[0].push(removeSubscription);
56
- }
57
- return removeSubscription;
58
- }
59
- function triggerSubscriptions(subscriptions, ...args) {
60
- subscriptions.forEach((callback) => {
61
- callback(...args);
62
- });
63
- }
64
-
65
- // src/types.ts
66
- var MutationType = /* @__PURE__ */ ((MutationType2) => {
67
- MutationType2["direct"] = "direct";
68
- MutationType2["patchObject"] = "patch object";
69
- MutationType2["patchFunction"] = "patch function";
70
- return MutationType2;
71
- })(MutationType || {});
72
-
73
- // src/utils.ts
74
- import { isReactive, isRef } from "@maoism/runtime-core";
75
- function noop2() {
76
- return {};
77
- }
78
- function isPlainObject(o) {
79
- return o && typeof o === "object" && Object.prototype.toString.call(o) === "[object Object]" && typeof o.toJSON !== "function";
80
- }
81
- function mergeReactiveObjects(target, patchToApply) {
82
- if (target instanceof Map && patchToApply instanceof Map) {
83
- patchToApply.forEach((value, key) => target.set(key, value));
84
- }
85
- if (target instanceof Set && patchToApply instanceof Set) {
86
- patchToApply.forEach(target.add, target);
87
- }
88
- for (const key in patchToApply) {
89
- if (!Object.hasOwn(patchToApply, key)) continue;
90
- const subPatch = patchToApply[key];
91
- const targetValue = target[key];
92
- if (isPlainObject(targetValue) && isPlainObject(subPatch) && // biome-ignore lint/suspicious/noPrototypeBuiltins: <>
93
- target.hasOwnProperty(key) && !isRef(subPatch) && !isReactive(subPatch)) {
94
- target[key] = mergeReactiveObjects(targetValue, subPatch);
95
- } else {
96
- target[key] = subPatch;
97
- }
98
- }
99
- return target;
100
- }
101
-
102
- // src/store.ts
103
- var ACTION_MARKER = Symbol();
104
- var ACTION_NAME = Symbol();
105
- var { assign } = Object;
106
- function createOptionsStore(id, options, pinia) {
107
- const { state, actions, getters } = options;
108
- const initialState = pinia.state.value[id];
109
- let store;
110
- function setup() {
111
- if (!initialState) {
112
- pinia.state.value[id] = state ? state() : {};
36
+ import { enablePatches, produce, setAutoFreeze } from "immer";
37
+ import { useCallback, useRef, useSyncExternalStore } from "react";
38
+ enablePatches();
39
+ setAutoFreeze(false);
40
+ var activeListenerId = null;
41
+ var activeGetterKey = null;
42
+ function isAffected(patches, trackedPaths) {
43
+ if (trackedPaths.size === 0) return false;
44
+ const tracked = Array.from(trackedPaths).map((p) => p.split("."));
45
+ for (const patch of patches) {
46
+ const patchPath = patch.path.map(String);
47
+ for (const trackedPath of tracked) {
48
+ const len = Math.min(patchPath.length, trackedPath.length);
49
+ let isPrefixMatch = true;
50
+ for (let i = 0; i < len; i++) {
51
+ if (patchPath[i] !== trackedPath[i]) {
52
+ isPrefixMatch = false;
53
+ break;
54
+ }
55
+ }
56
+ if (isPrefixMatch) return true;
113
57
  }
114
- const localState = toRefs(pinia.state.value[id]);
115
- return assign(
116
- localState,
117
- actions,
118
- Object.keys(getters || {}).reduce(
119
- (computedGetters, name) => {
120
- if (name in localState) {
121
- console.warn(
122
- `[\u{1F34D}]: A getter cannot have the same name as another state property. Rename one of them. Found with "${name}" in store "${id}".`
123
- );
124
- }
125
- computedGetters[name] = markRaw2(
126
- computed(() => {
127
- setActivePinia(pinia);
128
- const store2 = pinia._s.get(id);
129
- return getters[name].call(store2, store2);
130
- })
131
- );
132
- return computedGetters;
133
- },
134
- {}
135
- )
136
- );
137
58
  }
138
- store = createSetupStore(id, setup, options, pinia);
139
- return store;
59
+ return false;
140
60
  }
141
- function createSetupStore($id, setup, options = {}, pinia) {
142
- let scope;
143
- const optionsForPlugin = assign({ actions: {} }, options);
144
- const $subscribeOptions = { deep: true };
145
- let isListening;
146
- let isSyncListening;
147
- const subscriptions = /* @__PURE__ */ new Set();
148
- const actionSubscriptions = /* @__PURE__ */ new Set();
149
- const debuggerEvents = [];
150
- let activeListener;
151
- function $patch(partialStateOrMutator) {
152
- let subscriptionMutation;
153
- isListening = isSyncListening = false;
154
- if (typeof partialStateOrMutator === "function") {
155
- partialStateOrMutator(pinia.state.value[$id]);
156
- subscriptionMutation = {
157
- type: "patch function" /* patchFunction */,
158
- storeId: $id,
159
- events: debuggerEvents
160
- };
161
- } else {
162
- mergeReactiveObjects(pinia.state.value[$id], partialStateOrMutator);
163
- subscriptionMutation = {
164
- type: "patch object" /* patchObject */,
165
- payload: partialStateOrMutator,
166
- storeId: $id,
167
- events: debuggerEvents
168
- };
61
+ function defineStore(id, options) {
62
+ const getters = options.getters || {};
63
+ function resolveGetterDependencies(getterName, getterDepsMap, visited = /* @__PURE__ */ new Set()) {
64
+ if (visited.has(getterName)) {
65
+ console.warn(`[pinia-react] Circular dependency in getters detected involving: ${getterName}`);
66
+ return /* @__PURE__ */ new Set();
169
67
  }
170
- activeListener = Symbol();
171
- const myListenerId = activeListener;
172
- nextTick().then(() => {
173
- if (activeListener === myListenerId) {
174
- isListening = true;
68
+ visited.add(getterName);
69
+ const finalDeps = /* @__PURE__ */ new Set();
70
+ const directDeps = getterDepsMap.get(getterName);
71
+ if (!directDeps) return finalDeps;
72
+ for (const dep of directDeps) {
73
+ if (dep in getters) {
74
+ const nestedDeps = resolveGetterDependencies(dep, getterDepsMap, visited);
75
+ nestedDeps.forEach((d) => finalDeps.add(d));
76
+ } else {
77
+ finalDeps.add(dep);
175
78
  }
176
- });
177
- isSyncListening = true;
178
- triggerSubscriptions(subscriptions, subscriptionMutation, pinia.state.value[$id]);
179
- }
180
- const $reset = function $reset2() {
181
- const { state } = options;
182
- const newState = state ? state() : {};
183
- this.$patch(($state) => {
184
- assign($state, newState);
185
- });
186
- };
187
- const action = (fn, name = "") => {
188
- if (ACTION_MARKER in fn) {
189
- ;
190
- fn[ACTION_NAME] = name;
191
- return fn;
192
79
  }
193
- const wrappedAction = function() {
194
- setActivePinia(pinia);
195
- const args = Array.from(arguments);
196
- const afterCallbackSet = /* @__PURE__ */ new Set();
197
- const onErrorCallbackSet = /* @__PURE__ */ new Set();
198
- function after(callback) {
199
- afterCallbackSet.add(callback);
200
- }
201
- function onError(callback) {
202
- onErrorCallbackSet.add(callback);
203
- }
204
- triggerSubscriptions(actionSubscriptions, {
205
- args,
206
- name: wrappedAction[ACTION_NAME],
207
- store,
208
- after,
209
- onError
210
- });
211
- let ret;
212
- try {
213
- ret = fn.apply(this && this.$id === $id ? this : store, args);
214
- } catch (error) {
215
- triggerSubscriptions(onErrorCallbackSet, error);
216
- throw error;
217
- }
218
- if (ret instanceof Promise) {
219
- return ret.then((value) => {
220
- triggerSubscriptions(afterCallbackSet, value);
221
- return value;
222
- }).catch((error) => {
223
- triggerSubscriptions(onErrorCallbackSet, error);
224
- return Promise.reject(error);
80
+ return finalDeps;
81
+ }
82
+ function createStoreInstance() {
83
+ const pinia = getActivePinia();
84
+ const initialState = options.state();
85
+ let storePublicApi;
86
+ let devTools;
87
+ let isTimeTraveling = false;
88
+ const localScope = {
89
+ currentState: initialState,
90
+ listeners: /* @__PURE__ */ new Set(),
91
+ getterCache: /* @__PURE__ */ new Map(),
92
+ getterDependencies: /* @__PURE__ */ new Map(),
93
+ subscribers: /* @__PURE__ */ new Map(),
94
+ createStoreProxy: (_onAccess) => storePublicApi
95
+ };
96
+ pinia._scopes.set(id, localScope);
97
+ const isGetterComputing = /* @__PURE__ */ new Set();
98
+ const emit = (nextState, oldState, patches) => {
99
+ localScope.listeners.forEach((fn) => fn(nextState, oldState, patches));
100
+ localScope.subscribers.forEach((getterKeys, storeId) => {
101
+ const subscriberScope = pinia._scopes.get(storeId);
102
+ if (!subscriberScope) return;
103
+ let shouldNotify = false;
104
+ getterKeys.forEach((key) => {
105
+ if (subscriberScope.getterCache.has(key)) {
106
+ subscriberScope.getterCache.delete(key);
107
+ shouldNotify = true;
108
+ }
225
109
  });
110
+ if (shouldNotify) {
111
+ const oldSubState = subscriberScope.currentState;
112
+ const newSubState = { ...oldSubState };
113
+ subscriberScope.currentState = newSubState;
114
+ pinia.state[storeId] = newSubState;
115
+ subscriberScope.listeners.forEach((fn) => fn(newSubState, oldSubState, []));
116
+ }
117
+ });
118
+ };
119
+ const internalPatch = (updater, actionName, isReset = false) => {
120
+ if (isTimeTraveling) return;
121
+ const oldState = localScope.currentState;
122
+ let patches = [];
123
+ const nextState = produce(oldState, updater, (p) => {
124
+ patches = p;
125
+ });
126
+ if (patches.length > 0 || isReset) {
127
+ localScope.currentState = nextState;
128
+ pinia.state[id] = nextState;
129
+ if (devTools) {
130
+ devTools.send({ type: actionName, payload: patches }, nextState);
131
+ }
132
+ emit(nextState, oldState, patches);
226
133
  }
227
- triggerSubscriptions(afterCallbackSet, ret);
228
- return ret;
229
134
  };
230
- wrappedAction[ACTION_MARKER] = true;
231
- wrappedAction[ACTION_NAME] = name;
232
- return wrappedAction;
233
- };
234
- const partialStore = {
235
- _p: pinia,
236
- // _s: scope,
237
- $id,
238
- $onAction: addSubscription.bind(null, activeComponentCleanUp, actionSubscriptions),
239
- $patch,
240
- $reset,
241
- $subscribe(callback, options2 = {}) {
242
- const removeSubscription = addSubscription([[]], subscriptions, callback, options2.detached, () => stopWatcher());
243
- const stopWatcher = scope.run(
244
- () => watch(
245
- () => pinia.state.value[$id],
246
- (state) => {
247
- if (options2.flush === "sync" ? isSyncListening : isListening) {
248
- callback(
249
- {
250
- storeId: $id,
251
- type: "direct" /* direct */,
252
- events: debuggerEvents
253
- },
254
- state
255
- );
135
+ const $patch = (updater) => {
136
+ internalPatch((draft) => {
137
+ updater(draft);
138
+ }, "@patch");
139
+ };
140
+ const $reset = () => internalPatch(() => options.state(), "@reset", true);
141
+ const $subscribe = (callback) => {
142
+ const listener = (state, prev, patches) => callback(state, prev);
143
+ localScope.listeners.add(listener);
144
+ return () => localScope.listeners.delete(listener);
145
+ };
146
+ const getterInvalidationListener = (_state, _prevState, patches) => {
147
+ localScope.getterDependencies.forEach((_deps, getterName) => {
148
+ const resolvedDeps = resolveGetterDependencies(getterName, localScope.getterDependencies);
149
+ if (isAffected(patches, resolvedDeps)) {
150
+ localScope.getterCache.delete(getterName);
151
+ }
152
+ });
153
+ };
154
+ localScope.listeners.add(getterInvalidationListener);
155
+ const originalActions = options.actions || {};
156
+ const wrappedActions = {};
157
+ const proxyTarget = {};
158
+ function createStoreProxy(onAccess) {
159
+ const readonlyWarning = () => {
160
+ console.warn(`[${id}] Store is read-only. Use actions for mutations.`);
161
+ return false;
162
+ };
163
+ const createStateProxy = (stateTarget, path, onDeepAccess) => {
164
+ return new Proxy(stateTarget, {
165
+ get(obj, key) {
166
+ if (typeof key === "symbol") return Reflect.get(obj, key);
167
+ const currentPath = [...path, String(key)];
168
+ const value = Reflect.get(obj, key);
169
+ if (typeof value === "object" && value !== null) {
170
+ return createStateProxy(value, currentPath, onDeepAccess);
256
171
  }
172
+ onDeepAccess?.(currentPath);
173
+ return value;
257
174
  },
258
- assign({}, $subscribeOptions, options2)
259
- )
260
- );
261
- return removeSubscription;
175
+ set: readonlyWarning
176
+ });
177
+ };
178
+ return new Proxy(proxyTarget, {
179
+ get(_target, key, receiver) {
180
+ const strKey = String(key);
181
+ if (strKey === "$state") return localScope.currentState;
182
+ if (strKey === "$patch") return $patch;
183
+ if (strKey === "$reset") return $reset;
184
+ if (strKey === "$subscribe") return $subscribe;
185
+ const state = localScope.currentState;
186
+ if (strKey in state) {
187
+ const value = state[strKey];
188
+ if (typeof value === "object" && value !== null) {
189
+ return createStateProxy(value, [strKey], onAccess);
190
+ }
191
+ onAccess?.([strKey]);
192
+ return value;
193
+ }
194
+ if (strKey in getters) {
195
+ onAccess?.([strKey]);
196
+ if (localScope.getterCache.has(strKey)) return localScope.getterCache.get(strKey);
197
+ if (isGetterComputing.has(strKey)) {
198
+ console.warn(`[pinia-react] Circular dependency detected in getter "${strKey}"`);
199
+ return void 0;
200
+ }
201
+ isGetterComputing.add(strKey);
202
+ const dependencies = /* @__PURE__ */ new Set();
203
+ const prevListenerId = activeListenerId;
204
+ const prevGetterKey = activeGetterKey;
205
+ activeListenerId = id;
206
+ activeGetterKey = strKey;
207
+ try {
208
+ const onGetterAccess = (path) => {
209
+ dependencies.add(path[0]);
210
+ };
211
+ const trackingProxyForThis = createStoreProxy(onGetterAccess);
212
+ const trackingStateProxy = createStateProxy(state, [], onGetterAccess);
213
+ const result = getters[strKey].call(trackingProxyForThis, trackingStateProxy);
214
+ localScope.getterDependencies.set(strKey, dependencies);
215
+ localScope.getterCache.set(strKey, result);
216
+ return result;
217
+ } finally {
218
+ activeListenerId = prevListenerId;
219
+ activeGetterKey = prevGetterKey;
220
+ isGetterComputing.delete(strKey);
221
+ }
222
+ }
223
+ if (strKey in wrappedActions) {
224
+ return wrappedActions[strKey];
225
+ }
226
+ return Reflect.get(_target, key, receiver);
227
+ },
228
+ set(_target, key, value, receiver) {
229
+ const strKey = String(key);
230
+ if (strKey === "$state") {
231
+ console.warn(`[${id}] Do not replace "$state" directly. Use "$patch()" to replace the whole state.`);
232
+ return false;
233
+ }
234
+ if (strKey in localScope.currentState || strKey in getters || strKey in wrappedActions) {
235
+ return readonlyWarning();
236
+ }
237
+ return Reflect.set(_target, key, value, receiver);
238
+ }
239
+ });
262
240
  }
263
- // $dispose
264
- };
265
- const store = reactive(partialStore);
266
- pinia._s.set($id, store);
267
- scope = effectScope2();
268
- const setupStore = scope.run(() => setup({ action }));
269
- for (const key in setupStore) {
270
- const prop = setupStore[key];
271
- if (typeof prop === "function") {
272
- const actionValue = action(prop, key);
273
- setupStore[key] = actionValue;
274
- optionsForPlugin.actions[key] = prop;
241
+ storePublicApi = createStoreProxy();
242
+ Object.keys(originalActions).forEach((actionName) => {
243
+ const originalAction = originalActions[actionName];
244
+ wrappedActions[actionName] = (...args) => {
245
+ let returnValue;
246
+ const recipe = (draft) => {
247
+ const actionContextProxy = new Proxy({}, {
248
+ get(_, key) {
249
+ const strKey = String(key);
250
+ if (Reflect.has(draft, strKey)) return draft[strKey];
251
+ if (strKey in getters) {
252
+ return getters[strKey].call(actionContextProxy, draft);
253
+ }
254
+ return Reflect.get(storePublicApi, key, storePublicApi);
255
+ },
256
+ set(_, key, value) {
257
+ ;
258
+ draft[String(key)] = value;
259
+ return true;
260
+ }
261
+ });
262
+ returnValue = originalAction.apply(actionContextProxy, args);
263
+ };
264
+ internalPatch(recipe, actionName);
265
+ return returnValue;
266
+ };
267
+ });
268
+ localScope.createStoreProxy = createStoreProxy;
269
+ pinia._p.forEach((plugin) => {
270
+ const pluginResult = plugin({ id, store: storePublicApi, options });
271
+ if (pluginResult) {
272
+ Object.defineProperties(proxyTarget, Object.getOwnPropertyDescriptors(pluginResult));
273
+ }
274
+ });
275
+ pinia._s.set(id, storePublicApi);
276
+ if (typeof window !== "undefined" && window.__REDUX_DEVTOOLS_EXTENSION__) {
277
+ devTools = window.__REDUX_DEVTOOLS_EXTENSION__.connect({ name: id });
278
+ devTools.init(localScope.currentState);
279
+ devTools.subscribe((message) => {
280
+ if (message.type === "DISPATCH") {
281
+ const payloadType = message.payload?.type;
282
+ switch (payloadType) {
283
+ case "JUMP_TO_STATE":
284
+ case "JUMP_TO_ACTION":
285
+ case "IMPORT_STATE": {
286
+ const newState = typeof message.state === "string" ? JSON.parse(message.state) : message.state;
287
+ if (!newState || typeof newState !== "object") return;
288
+ isTimeTraveling = true;
289
+ const oldState = localScope.currentState;
290
+ localScope.currentState = newState;
291
+ pinia.state[id] = newState;
292
+ localScope.getterCache.clear();
293
+ emit(newState, oldState, []);
294
+ isTimeTraveling = false;
295
+ break;
296
+ }
297
+ case "COMMIT": {
298
+ devTools.init(localScope.currentState);
299
+ break;
300
+ }
301
+ case "ROLLBACK": {
302
+ const newState = typeof message.state === "string" ? JSON.parse(message.state) : message.state;
303
+ if (!newState || typeof newState !== "object") return;
304
+ isTimeTraveling = true;
305
+ const oldState = localScope.currentState;
306
+ localScope.currentState = newState;
307
+ pinia.state[id] = newState;
308
+ localScope.getterCache.clear();
309
+ emit(newState, oldState, []);
310
+ isTimeTraveling = false;
311
+ break;
312
+ }
313
+ case "RESET": {
314
+ const originalState = options.state();
315
+ devTools.init(originalState);
316
+ internalPatch(() => originalState, "@reset", true);
317
+ break;
318
+ }
319
+ default:
320
+ break;
321
+ }
322
+ }
323
+ });
275
324
  }
325
+ return storePublicApi;
276
326
  }
277
- assign(store, setupStore);
278
- assign(toRaw(store), setupStore);
279
- Object.defineProperty(store, "$state", {
280
- get: () => pinia.state.value[$id],
281
- set: (state) => {
282
- $patch(($state) => {
283
- assign($state, state);
284
- });
327
+ function getStore() {
328
+ const pinia = getActivePinia();
329
+ if (!pinia._s.has(id)) {
330
+ createStoreInstance();
285
331
  }
286
- });
287
- pinia._p.forEach((extender) => {
288
- assign(
289
- store,
290
- scope.run(
291
- () => extender({
292
- store,
293
- pinia,
294
- options: optionsForPlugin
295
- })
296
- )
297
- );
298
- });
299
- isListening = true;
300
- isSyncListening = true;
301
- return store;
302
- }
303
- var activeComponentCleanUp = [[]];
304
- function defineStore(id, options) {
305
- const effectMap = /* @__PURE__ */ new WeakMap();
306
- const subscribeMap = /* @__PURE__ */ new WeakMap();
307
- const cleanUpMap = /* @__PURE__ */ new WeakMap();
308
- function useStore(pinia) {
309
- if (pinia) setActivePinia(pinia);
310
- if (!activePinia) {
311
- throw new Error(
312
- `[\u{1F34D}]: "getActivePinia()" was called but there was no active Pinia. Are you trying to use a store before calling "createPinia()"?
313
- `
314
- );
332
+ if (activeListenerId && activeGetterKey && activeListenerId !== id) {
333
+ const accessedStoreScope = pinia._scopes.get(id);
334
+ if (accessedStoreScope) {
335
+ let subscribers = accessedStoreScope.subscribers.get(activeListenerId);
336
+ if (!subscribers) {
337
+ subscribers = /* @__PURE__ */ new Set();
338
+ accessedStoreScope.subscribers.set(activeListenerId, subscribers);
339
+ }
340
+ subscribers.add(activeGetterKey);
341
+ }
315
342
  }
316
- pinia = activePinia;
317
- const lastEffect = activeEffect.value;
318
- activeEffect.value = void 0;
319
- if (!pinia._s.has(id)) createOptionsStore(id, options, pinia);
320
- activeEffect.value = lastEffect;
321
- const store = pinia._s.get(id);
322
- const _id = useRef([useId()]);
323
- const storeSnapshotRef = useRef({ ...store });
324
- const isCollectDep = useRef(false);
325
- if (!cleanUpMap.get(_id.current)) {
326
- cleanUpMap.set(_id.current, []);
343
+ return pinia._s.get(id);
344
+ }
345
+ function useStore() {
346
+ const pinia = getActivePinia();
347
+ if (!pinia._s.has(id)) {
348
+ createStoreInstance();
327
349
  }
328
- activeComponentCleanUp[0] = cleanUpMap.get(_id.current);
329
- useEffect(() => {
330
- activeComponentCleanUp[0] = cleanUpMap.get(_id.current);
331
- return () => {
332
- cleanUpMap.get(_id.current).forEach((fn) => {
333
- fn();
334
- });
335
- };
336
- }, []);
337
- const subscribe = useCallback((onStoreChange) => {
338
- subscribeMap.set(_id.current, onStoreChange);
339
- return () => {
340
- const effect2 = effectMap.get(_id.current);
341
- if (effect2) effect2.stop();
342
- subscribeMap.delete(_id.current);
343
- effectMap.delete(_id.current);
344
- };
345
- }, []);
346
- useSyncExternalStore(
347
- subscribe,
348
- () => storeSnapshotRef.current,
349
- () => storeSnapshotRef.current
350
+ const currentScope = pinia._scopes.get(id);
351
+ const trackedPaths = useRef(/* @__PURE__ */ new Set());
352
+ trackedPaths.current.clear();
353
+ const subscribe = useCallback(
354
+ (onStoreChange) => {
355
+ const listener = (_state, _prevState, patches) => {
356
+ let shouldUpdate = false;
357
+ for (const path of trackedPaths.current) {
358
+ const topKey = path.split(".")[0];
359
+ if (topKey in getters) {
360
+ if (!currentScope.getterCache.has(topKey)) {
361
+ shouldUpdate = true;
362
+ break;
363
+ }
364
+ } else {
365
+ if (patches.length > 0 && isAffected(patches, /* @__PURE__ */ new Set([path]))) {
366
+ shouldUpdate = true;
367
+ break;
368
+ }
369
+ }
370
+ }
371
+ if (shouldUpdate) {
372
+ onStoreChange();
373
+ }
374
+ };
375
+ currentScope.listeners.add(listener);
376
+ return () => currentScope.listeners.delete(listener);
377
+ },
378
+ [currentScope]
350
379
  );
351
- let effect = effectMap.get(_id.current);
352
- if (!effect) {
353
- const fn = () => {
354
- const onStoreChange = subscribeMap.get(_id.current);
355
- if (!isCollectDep.current) {
356
- storeSnapshotRef.current = { ...store };
357
- onStoreChange?.();
358
- }
359
- };
360
- effect = new ReactiveEffect(fn, noop2, () => {
361
- if (effect?.dirty) effect.run();
362
- });
363
- activeEffect.value = effect;
364
- isCollectDep.current = true;
365
- effect.run();
366
- effectMap.set(_id.current, effect);
367
- isCollectDep.current = false;
368
- }
369
- return store;
380
+ const getSnapshot = useCallback(() => currentScope.currentState, [currentScope]);
381
+ useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
382
+ const trackingProxy = currentScope.createStoreProxy((path) => {
383
+ trackedPaths.current.add(path.join("."));
384
+ });
385
+ return trackingProxy;
370
386
  }
371
- useStore.$id = id;
372
- useStore.$getStore = (pinia) => {
373
- if (pinia) setActivePinia(pinia);
374
- pinia = activePinia;
375
- if (!pinia._s.has(id)) createOptionsStore(id, options, pinia);
376
- const store = pinia._s.get(id);
377
- return store;
378
- };
379
- return useStore;
387
+ return { useStore, getStore };
380
388
  }
381
389
  export {
382
- MutationType,
383
390
  createPinia,
384
391
  defineStore,
385
392
  getActivePinia,