@composy/store-vue 0.0.1 → 0.0.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.
Files changed (251) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/README.md +169 -154
  3. package/dist/index.js +151 -53
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.min.js +242 -170
  6. package/dist/index.min.js.map +1 -1
  7. package/es/.dts-output-manifest.json +1 -0
  8. package/es/.dts.tsbuildinfo +1 -0
  9. package/es/composables/defineSetupStore.d.ts +0 -1
  10. package/es/composables/defineSetupStore.d.ts.map +1 -1
  11. package/es/composables/defineSetupStore.js +1 -1
  12. package/es/composables/defineSetupStore.js.map +1 -1
  13. package/es/composables/index.d.ts +8 -9
  14. package/es/composables/index.d.ts.map +1 -1
  15. package/es/composables/index.js +1 -1
  16. package/es/composables/useFormStore.d.ts +0 -1
  17. package/es/composables/useFormStore.d.ts.map +1 -1
  18. package/es/composables/useFormStore.js +1 -1
  19. package/es/composables/useFormStore.js.map +1 -1
  20. package/es/composables/useOptimistic.d.ts +1 -52
  21. package/es/composables/useOptimistic.d.ts.map +1 -1
  22. package/es/composables/useOptimistic.js +35 -20
  23. package/es/composables/useOptimistic.js.map +1 -1
  24. package/es/composables/usePersist.d.ts +0 -1
  25. package/es/composables/usePersist.d.ts.map +1 -1
  26. package/es/composables/usePersist.js +16 -7
  27. package/es/composables/usePersist.js.map +1 -1
  28. package/es/composables/usePersistedState.d.ts +0 -1
  29. package/es/composables/usePersistedState.d.ts.map +1 -1
  30. package/es/composables/usePersistedState.js +16 -3
  31. package/es/composables/usePersistedState.js.map +1 -1
  32. package/es/composables/useSharedState.d.ts +0 -1
  33. package/es/composables/useSharedState.d.ts.map +1 -1
  34. package/es/composables/useSharedState.js +25 -8
  35. package/es/composables/useSharedState.js.map +1 -1
  36. package/es/composables/useStore.d.ts +0 -1
  37. package/es/composables/useStore.js +1 -1
  38. package/es/composables/useStore.js.map +1 -1
  39. package/es/composables/useStoreDevtools.d.ts +0 -1
  40. package/es/composables/useStoreDevtools.d.ts.map +1 -1
  41. package/es/composables/useStoreDevtools.js +1 -1
  42. package/es/composables/useStoreDevtools.js.map +1 -1
  43. package/es/composables/useStoreSnapshot.d.ts +0 -1
  44. package/es/composables/useStoreSnapshot.d.ts.map +1 -1
  45. package/es/composables/useStoreSnapshot.js +18 -8
  46. package/es/composables/useStoreSnapshot.js.map +1 -1
  47. package/es/composables/useSubscribe.d.ts +0 -1
  48. package/es/composables/useSubscribe.d.ts.map +1 -1
  49. package/es/composables/useSubscribe.js +1 -1
  50. package/es/composables/useSubscribe.js.map +1 -1
  51. package/es/context/injection-keys.d.ts +0 -1
  52. package/es/context/injection-keys.d.ts.map +1 -1
  53. package/es/context/injection-keys.js +1 -1
  54. package/es/context/injection-keys.js.map +1 -1
  55. package/es/index.d.ts +1 -2
  56. package/es/index.js +2 -2
  57. package/es/index.js.map +1 -1
  58. package/es/plugins/engine-plugin.d.ts +1 -2
  59. package/es/plugins/engine-plugin.d.ts.map +1 -1
  60. package/es/plugins/engine-plugin.js +2 -2
  61. package/es/plugins/engine-plugin.js.map +1 -1
  62. package/es/plugins/enhanced-persist-plugin.d.ts +0 -1
  63. package/es/plugins/enhanced-persist-plugin.js +1 -1
  64. package/es/plugins/index.d.ts +0 -1
  65. package/es/plugins/index.js +1 -1
  66. package/es/plugins/pinia-plugin.d.ts +0 -1
  67. package/es/plugins/pinia-plugin.d.ts.map +1 -1
  68. package/es/plugins/pinia-plugin.js +24 -6
  69. package/es/plugins/pinia-plugin.js.map +1 -1
  70. package/es/plugins/registry-plugin.d.ts +0 -1
  71. package/es/plugins/registry-plugin.js +1 -1
  72. package/es/plugins/vue-plugin.d.ts +0 -1
  73. package/es/plugins/vue-plugin.d.ts.map +1 -1
  74. package/es/plugins/vue-plugin.js +1 -1
  75. package/es/plugins/vue-plugin.js.map +1 -1
  76. package/es/runtime/install-store-app.d.ts +0 -1
  77. package/es/runtime/install-store-app.js +1 -1
  78. package/es/runtime/install-store-app.js.map +1 -1
  79. package/es/runtime/store-plugin-options.d.ts +0 -1
  80. package/es/runtime/store-plugin-options.js +1 -1
  81. package/es/runtime/store-plugin-options.js.map +1 -1
  82. package/es/runtime/store-registry.d.ts +0 -1
  83. package/es/runtime/store-registry.d.ts.map +1 -1
  84. package/es/runtime/store-registry.js +14 -4
  85. package/es/runtime/store-registry.js.map +1 -1
  86. package/es/runtime/store-runtime.d.ts +1 -2
  87. package/es/runtime/store-runtime.d.ts.map +1 -1
  88. package/es/runtime/store-runtime.js +8 -2
  89. package/es/runtime/store-runtime.js.map +1 -1
  90. package/es/types.d.ts +2 -1
  91. package/es/types.d.ts.map +1 -1
  92. package/es/types.js +1 -1
  93. package/esm/composables/defineSetupStore.d.ts.map +1 -1
  94. package/esm/composables/defineSetupStore.js +1 -1
  95. package/esm/composables/defineSetupStore.js.map +1 -1
  96. package/esm/composables/index.d.ts +8 -8
  97. package/esm/composables/index.d.ts.map +1 -1
  98. package/esm/composables/index.js +1 -1
  99. package/esm/composables/useFormStore.d.ts.map +1 -1
  100. package/esm/composables/useFormStore.js +1 -1
  101. package/esm/composables/useFormStore.js.map +1 -1
  102. package/esm/composables/useOptimistic.d.ts +1 -51
  103. package/esm/composables/useOptimistic.d.ts.map +1 -1
  104. package/esm/composables/useOptimistic.js +35 -20
  105. package/esm/composables/useOptimistic.js.map +1 -1
  106. package/esm/composables/usePersist.d.ts.map +1 -1
  107. package/esm/composables/usePersist.js +16 -7
  108. package/esm/composables/usePersist.js.map +1 -1
  109. package/esm/composables/usePersistedState.d.ts.map +1 -1
  110. package/esm/composables/usePersistedState.js +16 -3
  111. package/esm/composables/usePersistedState.js.map +1 -1
  112. package/esm/composables/useSharedState.d.ts.map +1 -1
  113. package/esm/composables/useSharedState.js +25 -8
  114. package/esm/composables/useSharedState.js.map +1 -1
  115. package/esm/composables/useStore.js +1 -1
  116. package/esm/composables/useStore.js.map +1 -1
  117. package/esm/composables/useStoreDevtools.d.ts.map +1 -1
  118. package/esm/composables/useStoreDevtools.js +1 -1
  119. package/esm/composables/useStoreDevtools.js.map +1 -1
  120. package/esm/composables/useStoreSnapshot.d.ts.map +1 -1
  121. package/esm/composables/useStoreSnapshot.js +18 -8
  122. package/esm/composables/useStoreSnapshot.js.map +1 -1
  123. package/esm/composables/useSubscribe.d.ts.map +1 -1
  124. package/esm/composables/useSubscribe.js +1 -1
  125. package/esm/composables/useSubscribe.js.map +1 -1
  126. package/esm/context/injection-keys.d.ts.map +1 -1
  127. package/esm/context/injection-keys.js +1 -1
  128. package/esm/context/injection-keys.js.map +1 -1
  129. package/esm/index.d.ts +1 -1
  130. package/esm/index.js +2 -2
  131. package/esm/index.js.map +1 -1
  132. package/esm/plugins/engine-plugin.d.ts +1 -1
  133. package/esm/plugins/engine-plugin.d.ts.map +1 -1
  134. package/esm/plugins/engine-plugin.js +2 -2
  135. package/esm/plugins/engine-plugin.js.map +1 -1
  136. package/esm/plugins/enhanced-persist-plugin.js +1 -1
  137. package/esm/plugins/index.js +1 -1
  138. package/esm/plugins/pinia-plugin.d.ts.map +1 -1
  139. package/esm/plugins/pinia-plugin.js +24 -6
  140. package/esm/plugins/pinia-plugin.js.map +1 -1
  141. package/esm/plugins/registry-plugin.js +1 -1
  142. package/esm/plugins/vue-plugin.d.ts.map +1 -1
  143. package/esm/plugins/vue-plugin.js +1 -1
  144. package/esm/plugins/vue-plugin.js.map +1 -1
  145. package/esm/runtime/install-store-app.js +1 -1
  146. package/esm/runtime/install-store-app.js.map +1 -1
  147. package/esm/runtime/store-plugin-options.js +1 -1
  148. package/esm/runtime/store-plugin-options.js.map +1 -1
  149. package/esm/runtime/store-registry.d.ts.map +1 -1
  150. package/esm/runtime/store-registry.js +14 -4
  151. package/esm/runtime/store-registry.js.map +1 -1
  152. package/esm/runtime/store-runtime.d.ts +1 -1
  153. package/esm/runtime/store-runtime.d.ts.map +1 -1
  154. package/esm/runtime/store-runtime.js +8 -2
  155. package/esm/runtime/store-runtime.js.map +1 -1
  156. package/esm/types.d.ts +2 -0
  157. package/esm/types.d.ts.map +1 -1
  158. package/esm/types.js +1 -1
  159. package/lib/composables/defineSetupStore.cjs +1 -1
  160. package/lib/composables/defineSetupStore.cjs.map +1 -1
  161. package/lib/composables/{defineSetupStore.d.ts → defineSetupStore.d.cts} +0 -1
  162. package/lib/composables/defineSetupStore.d.cts.map +1 -0
  163. package/lib/composables/index.cjs +1 -1
  164. package/lib/composables/{index.d.ts → index.d.cts} +8 -9
  165. package/lib/composables/index.d.cts.map +1 -0
  166. package/lib/composables/useFormStore.cjs +1 -1
  167. package/lib/composables/useFormStore.cjs.map +1 -1
  168. package/lib/composables/{useFormStore.d.ts → useFormStore.d.cts} +0 -1
  169. package/lib/composables/useFormStore.d.cts.map +1 -0
  170. package/lib/composables/useOptimistic.cjs +35 -20
  171. package/lib/composables/useOptimistic.cjs.map +1 -1
  172. package/lib/composables/useOptimistic.d.cts +16 -0
  173. package/lib/composables/useOptimistic.d.cts.map +1 -0
  174. package/lib/composables/usePersist.cjs +16 -7
  175. package/lib/composables/usePersist.cjs.map +1 -1
  176. package/lib/composables/{usePersist.d.ts → usePersist.d.cts} +0 -1
  177. package/lib/composables/usePersist.d.cts.map +1 -0
  178. package/lib/composables/usePersistedState.cjs +16 -3
  179. package/lib/composables/usePersistedState.cjs.map +1 -1
  180. package/lib/composables/{usePersistedState.d.ts → usePersistedState.d.cts} +0 -1
  181. package/lib/composables/usePersistedState.d.cts.map +1 -0
  182. package/lib/composables/useSharedState.cjs +24 -7
  183. package/lib/composables/useSharedState.cjs.map +1 -1
  184. package/lib/composables/{useSharedState.d.ts → useSharedState.d.cts} +0 -1
  185. package/lib/composables/useSharedState.d.cts.map +1 -0
  186. package/lib/composables/useStore.cjs +1 -1
  187. package/lib/composables/useStore.cjs.map +1 -1
  188. package/lib/composables/{useStore.d.ts → useStore.d.cts} +0 -1
  189. package/lib/composables/useStore.d.cts.map +1 -0
  190. package/lib/composables/useStoreDevtools.cjs +1 -1
  191. package/lib/composables/useStoreDevtools.cjs.map +1 -1
  192. package/lib/composables/{useStoreDevtools.d.ts → useStoreDevtools.d.cts} +0 -1
  193. package/lib/composables/useStoreDevtools.d.cts.map +1 -0
  194. package/lib/composables/useStoreSnapshot.cjs +18 -8
  195. package/lib/composables/useStoreSnapshot.cjs.map +1 -1
  196. package/lib/composables/{useStoreSnapshot.d.ts → useStoreSnapshot.d.cts} +0 -1
  197. package/lib/composables/useStoreSnapshot.d.cts.map +1 -0
  198. package/lib/composables/useSubscribe.cjs +1 -1
  199. package/lib/composables/useSubscribe.cjs.map +1 -1
  200. package/lib/composables/{useSubscribe.d.ts → useSubscribe.d.cts} +0 -1
  201. package/lib/composables/useSubscribe.d.cts.map +1 -0
  202. package/lib/context/injection-keys.cjs +1 -1
  203. package/lib/context/injection-keys.cjs.map +1 -1
  204. package/lib/context/{injection-keys.d.ts → injection-keys.d.cts} +0 -1
  205. package/lib/context/injection-keys.d.cts.map +1 -0
  206. package/lib/index.cjs +2 -2
  207. package/lib/index.cjs.map +1 -1
  208. package/lib/{index.d.ts → index.d.cts} +1 -2
  209. package/lib/index.d.cts.map +1 -0
  210. package/lib/plugins/engine-plugin.cjs +2 -2
  211. package/lib/plugins/engine-plugin.cjs.map +1 -1
  212. package/lib/plugins/{engine-plugin.d.ts → engine-plugin.d.cts} +1 -2
  213. package/lib/plugins/engine-plugin.d.cts.map +1 -0
  214. package/lib/plugins/enhanced-persist-plugin.cjs +1 -1
  215. package/lib/plugins/{enhanced-persist-plugin.d.ts → enhanced-persist-plugin.d.cts} +0 -1
  216. package/lib/plugins/enhanced-persist-plugin.d.cts.map +1 -0
  217. package/lib/plugins/index.cjs +1 -1
  218. package/lib/plugins/{index.d.ts → index.d.cts} +0 -1
  219. package/lib/plugins/index.d.cts.map +1 -0
  220. package/lib/plugins/pinia-plugin.cjs +24 -6
  221. package/lib/plugins/pinia-plugin.cjs.map +1 -1
  222. package/lib/plugins/{pinia-plugin.d.ts → pinia-plugin.d.cts} +0 -1
  223. package/lib/plugins/pinia-plugin.d.cts.map +1 -0
  224. package/lib/plugins/registry-plugin.cjs +1 -1
  225. package/lib/plugins/{registry-plugin.d.ts → registry-plugin.d.cts} +0 -1
  226. package/lib/plugins/registry-plugin.d.cts.map +1 -0
  227. package/lib/plugins/vue-plugin.cjs +1 -1
  228. package/lib/plugins/vue-plugin.cjs.map +1 -1
  229. package/lib/plugins/{vue-plugin.d.ts → vue-plugin.d.cts} +0 -1
  230. package/lib/plugins/vue-plugin.d.cts.map +1 -0
  231. package/lib/runtime/install-store-app.cjs +1 -1
  232. package/lib/runtime/install-store-app.cjs.map +1 -1
  233. package/lib/runtime/{install-store-app.d.ts → install-store-app.d.cts} +0 -1
  234. package/lib/runtime/install-store-app.d.cts.map +1 -0
  235. package/lib/runtime/store-plugin-options.cjs +1 -1
  236. package/lib/runtime/store-plugin-options.cjs.map +1 -1
  237. package/lib/runtime/{store-plugin-options.d.ts → store-plugin-options.d.cts} +0 -1
  238. package/lib/runtime/store-plugin-options.d.cts.map +1 -0
  239. package/lib/runtime/store-registry.cjs +14 -4
  240. package/lib/runtime/store-registry.cjs.map +1 -1
  241. package/lib/runtime/{store-registry.d.ts → store-registry.d.cts} +0 -1
  242. package/lib/runtime/store-registry.d.cts.map +1 -0
  243. package/lib/runtime/store-runtime.cjs +8 -2
  244. package/lib/runtime/store-runtime.cjs.map +1 -1
  245. package/lib/runtime/{store-runtime.d.ts → store-runtime.d.cts} +1 -2
  246. package/lib/runtime/store-runtime.d.cts.map +1 -0
  247. package/lib/types.cjs +1 -1
  248. package/lib/{types.d.ts → types.d.cts} +2 -1
  249. package/lib/types.d.cts.map +1 -0
  250. package/package.json +19 -16
  251. package/lib/composables/useOptimistic.d.ts +0 -67
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * ***********************************
3
3
  * @composy/store-vue v0.0.1 *
4
4
  * Built with rollup *
5
- * Build time: 2024-08-17 11:39:29 *
5
+ * Build time: 2024-10-12 17:40:04 *
6
6
  * Build mode: production *
7
7
  * Minified: No *
8
8
  * ***********************************
@@ -15,7 +15,7 @@
15
15
  "vue",
16
16
  "@composy/store-core",
17
17
  "@composy/store-core/engine"
18
- ], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.LDesignStoreVue = {}, global.Pinia, global.Vue, global.ComposyStoreCore, global.ComposyStoreCore));
18
+ ], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.LDesignStoreVue = {}, global.Pinia, global.Vue, global.LDesignStoreCore, global.LDesignStoreCore));
19
19
  })(this, function(exports, pinia, vue, _composy_store_core, _composy_store_core_engine) {
20
20
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
21
21
  //#region src/composables/defineSetupStore.ts
@@ -214,39 +214,54 @@
214
214
  }
215
215
  function useOptimistic(initialState) {
216
216
  const state = (0, vue.ref)((0, _composy_store_core.deepClone)(initialState));
217
+ let committedState = (0, _composy_store_core.deepClone)(initialState);
218
+ const operations = [];
217
219
  const isPending = (0, vue.ref)(false);
218
220
  const isRolledBack = (0, vue.ref)(false);
219
221
  const pending = (0, vue.ref)([]);
222
+ const refresh = () => {
223
+ let nextState = (0, _composy_store_core.deepClone)(committedState);
224
+ operations.forEach((operation) => {
225
+ if (operation.status !== "rolled-back") nextState = operation.apply(nextState);
226
+ });
227
+ state.value = (0, _composy_store_core.deepClone)(nextState);
228
+ pending.value = operations.filter((operation) => operation.status === "pending").map((operation) => ({
229
+ id: operation.id,
230
+ snapshot: (0, _composy_store_core.deepClone)(operation.snapshot),
231
+ status: operation.status,
232
+ timestamp: operation.timestamp
233
+ }));
234
+ isPending.value = pending.value.length > 0;
235
+ };
236
+ const reconcile = () => {
237
+ while (operations[0] && operations[0].status !== "pending") {
238
+ const operation = operations.shift();
239
+ if (!operation || operation.status === "rolled-back") continue;
240
+ committedState = operation.apply((0, _composy_store_core.deepClone)(committedState));
241
+ }
242
+ refresh();
243
+ };
220
244
  async function mutate(optimisticValue, confirm) {
221
245
  const snapshot = (0, _composy_store_core.deepClone)(state.value);
222
- const entryId = uid();
223
- const entry = {
224
- id: entryId,
246
+ const apply = typeof optimisticValue === "function" ? (previous) => (0, _composy_store_core.deepClone)(optimisticValue((0, _composy_store_core.deepClone)(previous))) : () => (0, _composy_store_core.deepClone)(optimisticValue);
247
+ const operation = {
248
+ id: uid(),
225
249
  snapshot,
226
250
  status: "pending",
227
- timestamp: Date.now()
251
+ timestamp: Date.now(),
252
+ apply
228
253
  };
229
- pending.value = [...pending.value, entry];
230
- isPending.value = true;
254
+ operations.push(operation);
231
255
  isRolledBack.value = false;
232
- if (typeof optimisticValue === "function") state.value = optimisticValue(state.value);
233
- else state.value = optimisticValue;
256
+ refresh();
234
257
  try {
235
258
  await confirm();
236
- pending.value = pending.value.map((e) => e.id === entryId ? {
237
- ...e,
238
- status: "confirmed"
239
- } : e);
259
+ operation.status = "confirmed";
240
260
  } catch {
241
- state.value = snapshot;
261
+ operation.status = "rolled-back";
242
262
  isRolledBack.value = true;
243
- pending.value = pending.value.map((e) => e.id === entryId ? {
244
- ...e,
245
- status: "rolled-back"
246
- } : e);
247
263
  } finally {
248
- pending.value = pending.value.filter((e) => e.status === "pending");
249
- isPending.value = pending.value.length > 0;
264
+ reconcile();
250
265
  }
251
266
  }
252
267
  return {
@@ -261,10 +276,14 @@
261
276
  //#region src/composables/usePersist.ts
262
277
  function getStorage$2(type) {
263
278
  if (typeof window === "undefined") return null;
264
- return type === "localStorage" ? localStorage : sessionStorage;
279
+ try {
280
+ return type === "localStorage" ? window.localStorage : window.sessionStorage;
281
+ } catch {
282
+ return null;
283
+ }
265
284
  }
266
285
  function usePersist(options) {
267
- const { key, storage: storageType = "localStorage", defaultValue, serialize = JSON.stringify, deserialize = JSON.parse } = options;
286
+ const { key, storage: storageType = "localStorage", defaultValue, serialize = JSON.stringify, deserialize = JSON.parse, restoreOnMounted = true } = options;
268
287
  const storage = getStorage$2(storageType);
269
288
  const value = (0, vue.ref)(defaultValue);
270
289
  const restore = () => {
@@ -293,7 +312,7 @@
293
312
  console.error(`[usePersist] \u6E05\u9664\u5931\u8D25 (${key}):`, error);
294
313
  }
295
314
  };
296
- (0, vue.onMounted)(() => {
315
+ if (restoreOnMounted) (0, vue.onMounted)(() => {
297
316
  restore();
298
317
  });
299
318
  (0, vue.watch)(value, () => {
@@ -315,12 +334,13 @@
315
334
  return value;
316
335
  }
317
336
  function usePersistedRefWithTTL(key, defaultValue, ttl) {
318
- const { value } = usePersist({
337
+ const persisted = usePersist({
319
338
  key,
320
339
  defaultValue: {
321
340
  value: defaultValue,
322
341
  expiry: 0
323
342
  },
343
+ restoreOnMounted: false,
324
344
  serialize: (data) => JSON.stringify(data),
325
345
  deserialize: (str) => {
326
346
  const data = JSON.parse(str);
@@ -331,13 +351,17 @@
331
351
  return data;
332
352
  }
333
353
  });
334
- const wrappedRef = (0, vue.ref)(value.value.value);
354
+ persisted.restore();
355
+ const wrappedRef = (0, vue.ref)(persisted.value.value.value);
335
356
  (0, vue.watch)(wrappedRef, (newValue) => {
336
- value.value = {
357
+ persisted.value.value = {
337
358
  value: newValue,
338
359
  expiry: Date.now() + ttl
339
360
  };
340
361
  });
362
+ (0, vue.watch)(persisted.value, (stored) => {
363
+ if (!Object.is(wrappedRef.value, stored.value)) wrappedRef.value = stored.value;
364
+ }, { deep: true });
341
365
  return wrappedRef;
342
366
  }
343
367
  //#endregion
@@ -361,6 +385,7 @@
361
385
  const storage = getStorage$1(storageType);
362
386
  const createDefaultValue = () => (0, _composy_store_core.deepClone)(defaultValue);
363
387
  const state = (0, vue.ref)(createDefaultValue());
388
+ let skipNextSave = false;
364
389
  const save = () => {
365
390
  if (!storage) return;
366
391
  try {
@@ -374,6 +399,7 @@
374
399
  console.error(`[usePersistedState] \u4FDD\u5B58\u5931\u8D25 (${key}):`, error);
375
400
  }
376
401
  };
402
+ const debouncedSave = debounceDelay > 0 ? (0, _composy_store_core.debounce)(save, debounceDelay) : null;
377
403
  const clear = () => {
378
404
  if (!storage) return;
379
405
  try {
@@ -401,6 +427,8 @@
401
427
  }
402
428
  };
403
429
  const reset = () => {
430
+ debouncedSave?.cancel();
431
+ skipNextSave = true;
404
432
  state.value = createDefaultValue();
405
433
  clear();
406
434
  };
@@ -415,9 +443,14 @@
415
443
  return false;
416
444
  }
417
445
  };
418
- const debouncedSave = debounceDelay > 0 ? (0, _composy_store_core.debounce)(save, debounceDelay) : null;
419
446
  const handleStorageEvent = (event) => {
420
- if (event.key !== key || !event.newValue) return;
447
+ if (event.key !== key) return;
448
+ if (!event.newValue) {
449
+ debouncedSave?.cancel();
450
+ skipNextSave = true;
451
+ state.value = createDefaultValue();
452
+ return;
453
+ }
421
454
  try {
422
455
  const item = JSON.parse(event.newValue);
423
456
  if (item.expiresAt && Date.now() > item.expiresAt) return;
@@ -428,6 +461,10 @@
428
461
  };
429
462
  restore();
430
463
  (0, vue.watch)(state, (newValue, oldValue) => {
464
+ if (skipNextSave) {
465
+ skipNextSave = false;
466
+ return;
467
+ }
431
468
  if (onBeforeChange?.(newValue, oldValue) === false) return;
432
469
  if (debouncedSave) debouncedSave();
433
470
  else save();
@@ -455,7 +492,11 @@
455
492
  const peerCount = (0, vue.ref)(0);
456
493
  const lastSyncAt = (0, vue.ref)(null);
457
494
  let channel = null;
458
- let isReceiving = false;
495
+ const originId = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
496
+ let revision = 0;
497
+ const latestRemoteRevision = /* @__PURE__ */ new Map();
498
+ let pendingRemoteState;
499
+ let hasPendingRemoteState = false;
459
500
  if (typeof BroadcastChannel === "undefined") {
460
501
  console.warn("[useSharedState] BroadcastChannel not supported in this environment");
461
502
  return {
@@ -484,7 +525,9 @@
484
525
  channel.postMessage({
485
526
  type: "state-update",
486
527
  payload: (0, _composy_store_core.deepClone)(state.value),
487
- timestamp: Date.now()
528
+ timestamp: Date.now(),
529
+ origin: originId,
530
+ revision: ++revision
488
531
  });
489
532
  } catch (e) {
490
533
  console.warn("[useSharedState] broadcast error:", e);
@@ -494,15 +537,26 @@
494
537
  const msg = event.data;
495
538
  if (!msg || typeof msg !== "object") return;
496
539
  if (msg.type === "state-update") {
497
- isReceiving = true;
498
- state.value = msg.payload;
540
+ if (msg.origin === originId) return;
541
+ const remoteRevision = typeof msg.revision === "number" ? msg.revision : 0;
542
+ if (remoteRevision <= (latestRemoteRevision.get(String(msg.origin)) ?? -1)) return;
543
+ latestRemoteRevision.set(String(msg.origin), remoteRevision);
544
+ pendingRemoteState = (0, _composy_store_core.deepClone)(msg.payload);
545
+ hasPendingRemoteState = true;
546
+ state.value = pendingRemoteState;
499
547
  lastSyncAt.value = msg.timestamp || Date.now();
500
- isReceiving = false;
501
548
  } else if (msg.type === "ping") channel?.postMessage({ type: "pong" });
502
549
  else if (msg.type === "pong") peerCount.value++;
503
550
  };
504
551
  const stopWatch = (0, vue.watch)(state, () => {
505
- if (!isReceiving) broadcast();
552
+ if (hasPendingRemoteState) {
553
+ if ((0, _composy_store_core.deepEqual)(state.value, pendingRemoteState)) {
554
+ hasPendingRemoteState = false;
555
+ return;
556
+ }
557
+ hasPendingRemoteState = false;
558
+ }
559
+ broadcast();
506
560
  }, { deep });
507
561
  function close() {
508
562
  stopWatch();
@@ -739,6 +793,7 @@
739
793
  const currentIndex = (0, vue.ref)(-1);
740
794
  let debounceTimer;
741
795
  let isRestoring = false;
796
+ let previousAutoRecordState;
742
797
  const getState = () => {
743
798
  return typeof state === "function" ? state() : state.value;
744
799
  };
@@ -769,6 +824,7 @@
769
824
  try {
770
825
  setState((0, _composy_store_core.deepClone)(snapshots.value[index].state));
771
826
  currentIndex.value = index;
827
+ previousAutoRecordState = (0, _composy_store_core.deepClone)(getState());
772
828
  return true;
773
829
  } finally {
774
830
  isRestoring = false;
@@ -776,10 +832,12 @@
776
832
  };
777
833
  const undo = () => {
778
834
  if (!canUndo.value) return false;
779
- currentIndex.value--;
835
+ const targetIndex = currentIndex.value - 1;
780
836
  isRestoring = true;
781
837
  try {
782
- setState((0, _composy_store_core.deepClone)(snapshots.value[currentIndex.value].state));
838
+ setState((0, _composy_store_core.deepClone)(snapshots.value[targetIndex].state));
839
+ currentIndex.value = targetIndex;
840
+ previousAutoRecordState = (0, _composy_store_core.deepClone)(getState());
783
841
  return true;
784
842
  } finally {
785
843
  isRestoring = false;
@@ -787,10 +845,12 @@
787
845
  };
788
846
  const redo = () => {
789
847
  if (!canRedo.value) return false;
790
- currentIndex.value++;
848
+ const targetIndex = currentIndex.value + 1;
791
849
  isRestoring = true;
792
850
  try {
793
- setState((0, _composy_store_core.deepClone)(snapshots.value[currentIndex.value].state));
851
+ setState((0, _composy_store_core.deepClone)(snapshots.value[targetIndex].state));
852
+ currentIndex.value = targetIndex;
853
+ previousAutoRecordState = (0, _composy_store_core.deepClone)(getState());
794
854
  return true;
795
855
  } finally {
796
856
  isRestoring = false;
@@ -798,10 +858,11 @@
798
858
  };
799
859
  const goto = (index) => {
800
860
  if (index < 0 || index >= snapshots.value.length) return false;
801
- currentIndex.value = index;
802
861
  isRestoring = true;
803
862
  try {
804
863
  setState((0, _composy_store_core.deepClone)(snapshots.value[index].state));
864
+ currentIndex.value = index;
865
+ previousAutoRecordState = (0, _composy_store_core.deepClone)(getState());
805
866
  return true;
806
867
  } finally {
807
868
  isRestoring = false;
@@ -836,9 +897,12 @@
836
897
  }
837
898
  };
838
899
  if (autoRecord) {
839
- const stopWatch = (0, vue.watch)(typeof state === "function" ? (0, vue.computed)(state) : state, (newState, oldState) => {
900
+ const stateRef = typeof state === "function" ? (0, vue.computed)(state) : state;
901
+ previousAutoRecordState = (0, _composy_store_core.deepClone)(getState());
902
+ const stopWatch = (0, vue.watch)(stateRef, (newState, oldState) => {
840
903
  if (isRestoring) return;
841
- if ((0, _composy_store_core.deepEqual)(newState, oldState)) return;
904
+ if ((0, _composy_store_core.deepEqual)(newState, previousAutoRecordState ?? oldState)) return;
905
+ previousAutoRecordState = (0, _composy_store_core.deepClone)(newState);
842
906
  if (debounceTimer) clearTimeout(debounceTimer);
843
907
  debounceTimer = setTimeout(() => {
844
908
  takeSnapshot();
@@ -917,7 +981,11 @@
917
981
  const activePersistControllers = /* @__PURE__ */ new Set();
918
982
  function getStorage(type) {
919
983
  if (typeof window === "undefined") return null;
920
- return type === "localStorage" ? window.localStorage : window.sessionStorage;
984
+ try {
985
+ return type === "localStorage" ? window.localStorage : window.sessionStorage;
986
+ } catch {
987
+ return null;
988
+ }
921
989
  }
922
990
  function normalizePersistConfig(value) {
923
991
  if (!value) return null;
@@ -962,17 +1030,21 @@
962
1030
  function createPersistPluginController(options = {}) {
963
1031
  const { storage: defaultStorage = "localStorage", keyPrefix = "ldesign-store:", debounce: debounceDelay = 100, debug = false, syncTabs: defaultSyncTabs = false, defaultTTL } = options;
964
1032
  const cleanupMap = /* @__PURE__ */ new Map();
1033
+ let isDisposed = false;
965
1034
  const dispose = () => {
1035
+ if (isDisposed) return;
1036
+ isDisposed = true;
966
1037
  cleanupMap.forEach((cleanup) => cleanup());
967
1038
  cleanupMap.clear();
968
1039
  activePersistControllers.delete(dispose);
969
1040
  };
970
1041
  activePersistControllers.add(dispose);
971
1042
  const plugin = (context) => {
1043
+ if (isDisposed) return;
972
1044
  const { store, options: storeOptions } = context;
973
1045
  const config = normalizePersistConfig(storeOptions.persist);
974
1046
  if (!config) return;
975
- const storage = getStorage(config.storage === "sessionStorage" ? "sessionStorage" : defaultStorage);
1047
+ const storage = getStorage(config.storage ?? defaultStorage);
976
1048
  const serializer = config.serializer?.serialize ?? JSON.stringify;
977
1049
  const deserialize = config.serializer?.deserialize ?? JSON.parse;
978
1050
  const syncTabs = config.syncTabs ?? defaultSyncTabs;
@@ -1032,7 +1104,16 @@
1032
1104
  let stopStorageSync = () => {};
1033
1105
  if (syncTabs && typeof window !== "undefined") {
1034
1106
  const handleStorage = (event) => {
1035
- if (event.key !== key || !event.newValue) return;
1107
+ if (event.key !== key) return;
1108
+ if (event.newValue === null) {
1109
+ isRestoring = true;
1110
+ try {
1111
+ store.$reset?.();
1112
+ } finally {
1113
+ isRestoring = false;
1114
+ }
1115
+ return;
1116
+ }
1036
1117
  try {
1037
1118
  const storageItem = JSON.parse(event.newValue);
1038
1119
  if (storageItem.expiresAt && Date.now() > storageItem.expiresAt) return;
@@ -1050,9 +1131,10 @@
1050
1131
  saveState.cancel();
1051
1132
  stopSubscribe();
1052
1133
  stopStorageSync();
1053
- cleanupMap.delete(key);
1134
+ cleanupMap.delete(store);
1135
+ store[STORE_PERSIST_DISPOSE_KEY]?.();
1054
1136
  };
1055
- cleanupMap.set(key, cleanup);
1137
+ cleanupMap.set(store, cleanup);
1056
1138
  patchPersistDispose(store, cleanup);
1057
1139
  restoreState();
1058
1140
  };
@@ -1090,7 +1172,7 @@
1090
1172
  if (restorePatchedDispose) restorePatchedDispose();
1091
1173
  const originalDispose = store.$dispose;
1092
1174
  store.$dispose = function patchedDispose() {
1093
- unregister(store.$id);
1175
+ unregister();
1094
1176
  return originalDispose.call(this);
1095
1177
  };
1096
1178
  store[STORE_DISPOSE_PATCH_KEY] = () => {
@@ -1100,12 +1182,17 @@
1100
1182
  }
1101
1183
  function createStoreRegistry() {
1102
1184
  const stores = /* @__PURE__ */ new Map();
1103
- const unregister = (storeId) => {
1185
+ const unregister = (storeId, expectedStore) => {
1186
+ const store = stores.get(storeId);
1187
+ if (!store || expectedStore && store !== expectedStore) return;
1104
1188
  stores.delete(storeId);
1189
+ store[STORE_DISPOSE_PATCH_KEY]?.();
1105
1190
  };
1106
1191
  const register = (store) => {
1192
+ const existingStore = stores.get(store.$id);
1193
+ if (existingStore && existingStore !== store) unregister(store.$id, existingStore);
1107
1194
  stores.set(store.$id, store);
1108
- patchStoreDispose(store, unregister);
1195
+ patchStoreDispose(store, () => unregister(store.$id, store));
1109
1196
  };
1110
1197
  const hasStore = (storeId) => {
1111
1198
  return stores.has(storeId);
@@ -1125,6 +1212,9 @@
1125
1212
  });
1126
1213
  };
1127
1214
  const clear = () => {
1215
+ stores.forEach((store) => {
1216
+ store[STORE_DISPOSE_PATCH_KEY]?.();
1217
+ });
1128
1218
  stores.clear();
1129
1219
  };
1130
1220
  const registerExistingStores = (pinia) => {
@@ -1154,6 +1244,8 @@
1154
1244
  }
1155
1245
  let globalRegistry = createStoreRegistry();
1156
1246
  function setGlobalStoreRegistry(registry) {
1247
+ if (registry === globalRegistry) return;
1248
+ globalRegistry.clear();
1157
1249
  globalRegistry = registry ?? createStoreRegistry();
1158
1250
  }
1159
1251
  function getStoreRegistry() {
@@ -1180,11 +1272,15 @@
1180
1272
  const pinia$1 = resolvedOptions.pinia ?? (0, pinia.createPinia)();
1181
1273
  if (pinia$1[STORE_RUNTIME_KEY]) return pinia$1[STORE_RUNTIME_KEY];
1182
1274
  const registry = createStoreRegistry();
1275
+ let isActive = true;
1183
1276
  const persistController = resolvedOptions.persist ? createPersistPluginController({
1184
1277
  ...resolvedOptions.persistOptions,
1185
1278
  debug: resolvedOptions.debug || resolvedOptions.persistOptions.debug
1186
1279
  }) : null;
1187
- pinia$1.use(createStoreRegistryPlugin(registry));
1280
+ const registryPlugin = createStoreRegistryPlugin(registry);
1281
+ pinia$1.use((context) => {
1282
+ if (isActive) registryPlugin(context);
1283
+ });
1188
1284
  persistController && pinia$1.use(persistController.plugin);
1189
1285
  registry.registerExistingStores(pinia$1);
1190
1286
  const runtime = {
@@ -1197,6 +1293,8 @@
1197
1293
  * 释放所有资源:清除运行时标记、持久化插件、注册表
1198
1294
  */
1199
1295
  dispose: () => {
1296
+ if (!isActive) return;
1297
+ isActive = false;
1200
1298
  if (pinia$1[STORE_RUNTIME_KEY] === runtime) delete pinia$1[STORE_RUNTIME_KEY];
1201
1299
  persistController?.dispose();
1202
1300
  registry.clear();
@@ -1260,7 +1358,7 @@
1260
1358
  return getGlobalStoreAPI$1();
1261
1359
  }
1262
1360
  function createStoreEnginePlugin(options = {}) {
1263
- const { debug = false, dependencies = [], name = "store", version = "1.0.0" } = options;
1361
+ const { debug = false, dependencies = [], name = "store", version = "0.0.1" } = options;
1264
1362
  let bridge = null;
1265
1363
  const createBridge = () => {
1266
1364
  const activeBridge = (0, _composy_store_core_engine.createStoreEngineBridge)({
@@ -1326,7 +1424,7 @@
1326
1424
  }
1327
1425
  //#endregion
1328
1426
  //#region src/index.ts
1329
- const version = "1.0.0";
1427
+ const version = "0.0.1";
1330
1428
  const name = "@composy/store-vue";
1331
1429
  //#endregion
1332
1430
  Object.defineProperty(exports, "batch", {