@composy/store-vue 0.0.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.
Files changed (256) hide show
  1. package/README.md +154 -0
  2. package/dist/index.js +1536 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/index.min.js +1008 -0
  5. package/dist/index.min.js.map +1 -0
  6. package/es/composables/defineSetupStore.d.ts +120 -0
  7. package/es/composables/defineSetupStore.d.ts.map +1 -0
  8. package/es/composables/defineSetupStore.js +29 -0
  9. package/es/composables/defineSetupStore.js.map +1 -0
  10. package/es/composables/index.d.ts +24 -0
  11. package/es/composables/index.d.ts.map +1 -0
  12. package/es/composables/index.js +21 -0
  13. package/es/composables/useFormStore.d.ts +131 -0
  14. package/es/composables/useFormStore.d.ts.map +1 -0
  15. package/es/composables/useFormStore.js +189 -0
  16. package/es/composables/useFormStore.js.map +1 -0
  17. package/es/composables/useOptimistic.d.ts +67 -0
  18. package/es/composables/useOptimistic.d.ts.map +1 -0
  19. package/es/composables/useOptimistic.js +64 -0
  20. package/es/composables/useOptimistic.js.map +1 -0
  21. package/es/composables/usePersist.d.ts +68 -0
  22. package/es/composables/usePersist.d.ts.map +1 -0
  23. package/es/composables/usePersist.js +96 -0
  24. package/es/composables/usePersist.js.map +1 -0
  25. package/es/composables/usePersistedState.d.ts +59 -0
  26. package/es/composables/usePersistedState.d.ts.map +1 -0
  27. package/es/composables/usePersistedState.js +121 -0
  28. package/es/composables/usePersistedState.js.map +1 -0
  29. package/es/composables/useSharedState.d.ts +62 -0
  30. package/es/composables/useSharedState.d.ts.map +1 -0
  31. package/es/composables/useSharedState.js +94 -0
  32. package/es/composables/useSharedState.js.map +1 -0
  33. package/es/composables/useStore.d.ts +99 -0
  34. package/es/composables/useStore.d.ts.map +1 -0
  35. package/es/composables/useStore.js +61 -0
  36. package/es/composables/useStore.js.map +1 -0
  37. package/es/composables/useStoreDevtools.d.ts +31 -0
  38. package/es/composables/useStoreDevtools.d.ts.map +1 -0
  39. package/es/composables/useStoreDevtools.js +112 -0
  40. package/es/composables/useStoreDevtools.js.map +1 -0
  41. package/es/composables/useStoreSnapshot.d.ts +122 -0
  42. package/es/composables/useStoreSnapshot.d.ts.map +1 -0
  43. package/es/composables/useStoreSnapshot.js +209 -0
  44. package/es/composables/useStoreSnapshot.js.map +1 -0
  45. package/es/composables/useSubscribe.d.ts +90 -0
  46. package/es/composables/useSubscribe.d.ts.map +1 -0
  47. package/es/composables/useSubscribe.js +53 -0
  48. package/es/composables/useSubscribe.js.map +1 -0
  49. package/es/context/injection-keys.d.ts +8 -0
  50. package/es/context/injection-keys.d.ts.map +1 -0
  51. package/es/context/injection-keys.js +17 -0
  52. package/es/context/injection-keys.js.map +1 -0
  53. package/es/index.d.ts +24 -0
  54. package/es/index.d.ts.map +1 -0
  55. package/es/index.js +32 -0
  56. package/es/index.js.map +1 -0
  57. package/es/plugins/engine-plugin.d.ts +36 -0
  58. package/es/plugins/engine-plugin.d.ts.map +1 -0
  59. package/es/plugins/engine-plugin.js +83 -0
  60. package/es/plugins/engine-plugin.js.map +1 -0
  61. package/es/plugins/enhanced-persist-plugin.d.ts +3 -0
  62. package/es/plugins/enhanced-persist-plugin.d.ts.map +1 -0
  63. package/es/plugins/enhanced-persist-plugin.js +12 -0
  64. package/es/plugins/index.d.ts +7 -0
  65. package/es/plugins/index.d.ts.map +1 -0
  66. package/es/plugins/index.js +15 -0
  67. package/es/plugins/pinia-plugin.d.ts +68 -0
  68. package/es/plugins/pinia-plugin.d.ts.map +1 -0
  69. package/es/plugins/pinia-plugin.js +172 -0
  70. package/es/plugins/pinia-plugin.js.map +1 -0
  71. package/es/plugins/registry-plugin.d.ts +2 -0
  72. package/es/plugins/registry-plugin.d.ts.map +1 -0
  73. package/es/plugins/registry-plugin.js +12 -0
  74. package/es/plugins/vue-plugin.d.ts +10 -0
  75. package/es/plugins/vue-plugin.d.ts.map +1 -0
  76. package/es/plugins/vue-plugin.js +24 -0
  77. package/es/plugins/vue-plugin.js.map +1 -0
  78. package/es/runtime/install-store-app.d.ts +23 -0
  79. package/es/runtime/install-store-app.d.ts.map +1 -0
  80. package/es/runtime/install-store-app.js +54 -0
  81. package/es/runtime/install-store-app.js.map +1 -0
  82. package/es/runtime/store-plugin-options.d.ts +40 -0
  83. package/es/runtime/store-plugin-options.d.ts.map +1 -0
  84. package/es/runtime/store-plugin-options.js +24 -0
  85. package/es/runtime/store-plugin-options.js.map +1 -0
  86. package/es/runtime/store-registry.d.ts +64 -0
  87. package/es/runtime/store-registry.d.ts.map +1 -0
  88. package/es/runtime/store-registry.js +102 -0
  89. package/es/runtime/store-registry.js.map +1 -0
  90. package/es/runtime/store-runtime.d.ts +46 -0
  91. package/es/runtime/store-runtime.d.ts.map +1 -0
  92. package/es/runtime/store-runtime.js +58 -0
  93. package/es/runtime/store-runtime.js.map +1 -0
  94. package/es/types.d.ts +167 -0
  95. package/es/types.d.ts.map +1 -0
  96. package/es/types.js +10 -0
  97. package/esm/composables/defineSetupStore.d.ts +120 -0
  98. package/esm/composables/defineSetupStore.d.ts.map +1 -0
  99. package/esm/composables/defineSetupStore.js +29 -0
  100. package/esm/composables/defineSetupStore.js.map +1 -0
  101. package/esm/composables/index.d.ts +24 -0
  102. package/esm/composables/index.d.ts.map +1 -0
  103. package/esm/composables/index.js +21 -0
  104. package/esm/composables/useFormStore.d.ts +131 -0
  105. package/esm/composables/useFormStore.d.ts.map +1 -0
  106. package/esm/composables/useFormStore.js +189 -0
  107. package/esm/composables/useFormStore.js.map +1 -0
  108. package/esm/composables/useOptimistic.d.ts +67 -0
  109. package/esm/composables/useOptimistic.d.ts.map +1 -0
  110. package/esm/composables/useOptimistic.js +64 -0
  111. package/esm/composables/useOptimistic.js.map +1 -0
  112. package/esm/composables/usePersist.d.ts +68 -0
  113. package/esm/composables/usePersist.d.ts.map +1 -0
  114. package/esm/composables/usePersist.js +96 -0
  115. package/esm/composables/usePersist.js.map +1 -0
  116. package/esm/composables/usePersistedState.d.ts +59 -0
  117. package/esm/composables/usePersistedState.d.ts.map +1 -0
  118. package/esm/composables/usePersistedState.js +121 -0
  119. package/esm/composables/usePersistedState.js.map +1 -0
  120. package/esm/composables/useSharedState.d.ts +62 -0
  121. package/esm/composables/useSharedState.d.ts.map +1 -0
  122. package/esm/composables/useSharedState.js +94 -0
  123. package/esm/composables/useSharedState.js.map +1 -0
  124. package/esm/composables/useStore.d.ts +99 -0
  125. package/esm/composables/useStore.d.ts.map +1 -0
  126. package/esm/composables/useStore.js +61 -0
  127. package/esm/composables/useStore.js.map +1 -0
  128. package/esm/composables/useStoreDevtools.d.ts +31 -0
  129. package/esm/composables/useStoreDevtools.d.ts.map +1 -0
  130. package/esm/composables/useStoreDevtools.js +112 -0
  131. package/esm/composables/useStoreDevtools.js.map +1 -0
  132. package/esm/composables/useStoreSnapshot.d.ts +122 -0
  133. package/esm/composables/useStoreSnapshot.d.ts.map +1 -0
  134. package/esm/composables/useStoreSnapshot.js +209 -0
  135. package/esm/composables/useStoreSnapshot.js.map +1 -0
  136. package/esm/composables/useSubscribe.d.ts +90 -0
  137. package/esm/composables/useSubscribe.d.ts.map +1 -0
  138. package/esm/composables/useSubscribe.js +53 -0
  139. package/esm/composables/useSubscribe.js.map +1 -0
  140. package/esm/context/injection-keys.d.ts +8 -0
  141. package/esm/context/injection-keys.d.ts.map +1 -0
  142. package/esm/context/injection-keys.js +17 -0
  143. package/esm/context/injection-keys.js.map +1 -0
  144. package/esm/index.d.ts +24 -0
  145. package/esm/index.d.ts.map +1 -0
  146. package/esm/index.js +34 -0
  147. package/esm/index.js.map +1 -0
  148. package/esm/plugins/engine-plugin.d.ts +36 -0
  149. package/esm/plugins/engine-plugin.d.ts.map +1 -0
  150. package/esm/plugins/engine-plugin.js +83 -0
  151. package/esm/plugins/engine-plugin.js.map +1 -0
  152. package/esm/plugins/enhanced-persist-plugin.d.ts +3 -0
  153. package/esm/plugins/enhanced-persist-plugin.d.ts.map +1 -0
  154. package/esm/plugins/enhanced-persist-plugin.js +12 -0
  155. package/esm/plugins/index.d.ts +7 -0
  156. package/esm/plugins/index.d.ts.map +1 -0
  157. package/esm/plugins/index.js +16 -0
  158. package/esm/plugins/pinia-plugin.d.ts +68 -0
  159. package/esm/plugins/pinia-plugin.d.ts.map +1 -0
  160. package/esm/plugins/pinia-plugin.js +172 -0
  161. package/esm/plugins/pinia-plugin.js.map +1 -0
  162. package/esm/plugins/registry-plugin.d.ts +2 -0
  163. package/esm/plugins/registry-plugin.d.ts.map +1 -0
  164. package/esm/plugins/registry-plugin.js +12 -0
  165. package/esm/plugins/vue-plugin.d.ts +10 -0
  166. package/esm/plugins/vue-plugin.d.ts.map +1 -0
  167. package/esm/plugins/vue-plugin.js +24 -0
  168. package/esm/plugins/vue-plugin.js.map +1 -0
  169. package/esm/runtime/install-store-app.d.ts +23 -0
  170. package/esm/runtime/install-store-app.d.ts.map +1 -0
  171. package/esm/runtime/install-store-app.js +54 -0
  172. package/esm/runtime/install-store-app.js.map +1 -0
  173. package/esm/runtime/store-plugin-options.d.ts +40 -0
  174. package/esm/runtime/store-plugin-options.d.ts.map +1 -0
  175. package/esm/runtime/store-plugin-options.js +24 -0
  176. package/esm/runtime/store-plugin-options.js.map +1 -0
  177. package/esm/runtime/store-registry.d.ts +64 -0
  178. package/esm/runtime/store-registry.d.ts.map +1 -0
  179. package/esm/runtime/store-registry.js +94 -0
  180. package/esm/runtime/store-registry.js.map +1 -0
  181. package/esm/runtime/store-runtime.d.ts +46 -0
  182. package/esm/runtime/store-runtime.d.ts.map +1 -0
  183. package/esm/runtime/store-runtime.js +58 -0
  184. package/esm/runtime/store-runtime.js.map +1 -0
  185. package/esm/types.d.ts +167 -0
  186. package/esm/types.d.ts.map +1 -0
  187. package/esm/types.js +10 -0
  188. package/lib/composables/defineSetupStore.cjs +33 -0
  189. package/lib/composables/defineSetupStore.cjs.map +1 -0
  190. package/lib/composables/defineSetupStore.d.ts +120 -0
  191. package/lib/composables/index.cjs +46 -0
  192. package/lib/composables/index.d.ts +24 -0
  193. package/lib/composables/useFormStore.cjs +197 -0
  194. package/lib/composables/useFormStore.cjs.map +1 -0
  195. package/lib/composables/useFormStore.d.ts +131 -0
  196. package/lib/composables/useOptimistic.cjs +66 -0
  197. package/lib/composables/useOptimistic.cjs.map +1 -0
  198. package/lib/composables/useOptimistic.d.ts +67 -0
  199. package/lib/composables/usePersist.cjs +100 -0
  200. package/lib/composables/usePersist.cjs.map +1 -0
  201. package/lib/composables/usePersist.d.ts +68 -0
  202. package/lib/composables/usePersistedState.cjs +123 -0
  203. package/lib/composables/usePersistedState.cjs.map +1 -0
  204. package/lib/composables/usePersistedState.d.ts +59 -0
  205. package/lib/composables/useSharedState.cjs +96 -0
  206. package/lib/composables/useSharedState.cjs.map +1 -0
  207. package/lib/composables/useSharedState.d.ts +62 -0
  208. package/lib/composables/useStore.cjs +65 -0
  209. package/lib/composables/useStore.cjs.map +1 -0
  210. package/lib/composables/useStore.d.ts +99 -0
  211. package/lib/composables/useStoreDevtools.cjs +114 -0
  212. package/lib/composables/useStoreDevtools.cjs.map +1 -0
  213. package/lib/composables/useStoreDevtools.d.ts +31 -0
  214. package/lib/composables/useStoreSnapshot.cjs +211 -0
  215. package/lib/composables/useStoreSnapshot.cjs.map +1 -0
  216. package/lib/composables/useStoreSnapshot.d.ts +122 -0
  217. package/lib/composables/useSubscribe.cjs +57 -0
  218. package/lib/composables/useSubscribe.cjs.map +1 -0
  219. package/lib/composables/useSubscribe.d.ts +90 -0
  220. package/lib/context/injection-keys.cjs +21 -0
  221. package/lib/context/injection-keys.cjs.map +1 -0
  222. package/lib/context/injection-keys.d.ts +8 -0
  223. package/lib/index.cjs +235 -0
  224. package/lib/index.cjs.map +1 -0
  225. package/lib/index.d.ts +24 -0
  226. package/lib/package.json +3 -0
  227. package/lib/plugins/engine-plugin.cjs +90 -0
  228. package/lib/plugins/engine-plugin.cjs.map +1 -0
  229. package/lib/plugins/engine-plugin.d.ts +36 -0
  230. package/lib/plugins/enhanced-persist-plugin.cjs +15 -0
  231. package/lib/plugins/enhanced-persist-plugin.d.ts +3 -0
  232. package/lib/plugins/index.cjs +28 -0
  233. package/lib/plugins/index.d.ts +7 -0
  234. package/lib/plugins/pinia-plugin.cjs +177 -0
  235. package/lib/plugins/pinia-plugin.cjs.map +1 -0
  236. package/lib/plugins/pinia-plugin.d.ts +68 -0
  237. package/lib/plugins/registry-plugin.cjs +18 -0
  238. package/lib/plugins/registry-plugin.d.ts +2 -0
  239. package/lib/plugins/vue-plugin.cjs +26 -0
  240. package/lib/plugins/vue-plugin.cjs.map +1 -0
  241. package/lib/plugins/vue-plugin.d.ts +10 -0
  242. package/lib/runtime/install-store-app.cjs +57 -0
  243. package/lib/runtime/install-store-app.cjs.map +1 -0
  244. package/lib/runtime/install-store-app.d.ts +23 -0
  245. package/lib/runtime/store-plugin-options.cjs +26 -0
  246. package/lib/runtime/store-plugin-options.cjs.map +1 -0
  247. package/lib/runtime/store-plugin-options.d.ts +40 -0
  248. package/lib/runtime/store-registry.cjs +108 -0
  249. package/lib/runtime/store-registry.cjs.map +1 -0
  250. package/lib/runtime/store-registry.d.ts +64 -0
  251. package/lib/runtime/store-runtime.cjs +62 -0
  252. package/lib/runtime/store-runtime.cjs.map +1 -0
  253. package/lib/runtime/store-runtime.d.ts +46 -0
  254. package/lib/types.cjs +12 -0
  255. package/lib/types.d.ts +167 -0
  256. package/package.json +115 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStore.js","names":[],"sources":["../../src/composables/useStore.ts"],"sourcesContent":["/**\n * useStore Composable\n *\n * 提供在组件中使用 Store 的便捷方法\n * @module composables/useStore\n */\n\nimport type { StoreGeneric } from 'pinia'\nimport type { Ref } from 'vue'\nimport { storeToRefs } from 'pinia'\nimport { computed, ref, watch } from 'vue'\n\n/**\n * useStore 选项\n */\nexport interface UseStoreOptions {\n /** 是否立即同步状态 */\n immediate?: boolean\n /** 是否深度监听 */\n deep?: boolean\n}\n\n/**\n * 通用 Store Hook\n *\n * 提供对 Pinia Store 的便捷访问\n *\n * @template T - Store 类型\n * @param useStoreHook - Pinia useStore hook\n * @param _options - 选项\n * @returns Store 包装对象\n *\n * @example\n * ```typescript\n * // 定义 Store\n * const useCounterStore = defineStore('counter', {\n * state: () => ({ count: 0 }),\n * actions: {\n * increment() { this.count++ }\n * }\n * })\n *\n * // 在组件中使用\n * const { store, refs, reset } = useStore(useCounterStore)\n *\n * // 访问响应式状态\n * console.log(refs.count.value)\n *\n * // 调用 action\n * store.increment()\n * ```\n */\nexport function useStore<T extends StoreGeneric>(\n useStoreHook: () => T,\n _options: UseStoreOptions = {},\n): {\n store: T\n refs: ReturnType<typeof storeToRefs<T>>\n reset: () => void\n patch: (partial: Partial<T> | ((state: T) => void)) => void\n} {\n const store = useStoreHook()\n\n // 获取响应式 refs\n const refs = storeToRefs(store)\n\n // 重置函数\n const reset = (): void => {\n if ('$reset' in store && typeof store.$reset === 'function') {\n (store.$reset as () => void)()\n }\n }\n\n // 批量更新函数\n const patch = (partial: Partial<T> | ((state: T) => void)): void => {\n if ('$patch' in store && typeof store.$patch === 'function') {\n (store.$patch as (partial: unknown) => void)(partial)\n }\n }\n\n return {\n store,\n refs,\n reset,\n patch,\n }\n}\n\n/**\n * 创建简单的响应式 Store\n *\n * 不依赖 Pinia,适用于简单场景\n *\n * @template S - 状态类型\n * @param initialState - 初始状态\n * @returns 响应式 Store\n *\n * @example\n * ```typescript\n * const { state, setState, reset } = useSimpleStore({\n * count: 0,\n * name: 'test'\n * })\n *\n * // 更新状态\n * setState({ count: 1 })\n *\n * // 重置\n * reset()\n * ```\n */\nexport function useSimpleStore<S extends Record<string, unknown>>(\n initialState: S,\n): {\n state: Ref<S>\n setState: (partial: Partial<S>) => void\n reset: () => void\n subscribe: (callback: (state: S) => void) => () => void\n} {\n const state = ref({ ...initialState }) as Ref<S>\n const initialStateCopy = { ...initialState }\n\n const setState = (partial: Partial<S>): void => {\n Object.assign(state.value, partial)\n }\n\n const reset = (): void => {\n state.value = { ...initialStateCopy } as S\n }\n\n const subscribe = (callback: (state: S) => void): (() => void) => {\n const stop = watch(\n state,\n (newState) => {\n callback(newState)\n },\n { deep: true },\n )\n return stop\n }\n\n return {\n state,\n setState,\n reset,\n subscribe,\n }\n}\n\n/**\n * 创建计算属性 Store\n *\n * @template S - 状态类型\n * @template G - Getters 类型\n * @param state - 状态\n * @param getters - 计算属性\n * @returns 带计算属性的 Store\n */\nexport function useComputedStore<\n S extends Record<string, unknown>,\n G extends Record<string, (state: S) => unknown>,\n>(\n state: Ref<S>,\n getters: G,\n): {\n state: Ref<S>\n getters: { [K in keyof G]: ReturnType<G[K]> }\n} {\n const computedGetters = {} as { [K in keyof G]: ReturnType<G[K]> }\n\n for (const key in getters) {\n (computedGetters as Record<string, unknown>)[key] = computed(() =>\n getters[key](state.value),\n )\n }\n\n return {\n state,\n getters: computedGetters,\n }\n}\n\n"],"mappings":";;;;;;;;;;;;AAoDO,SAAS,SACd,cACA,WAA4B,CAAC,GAM7B;CACA,MAAM,QAAQ,aAAa;CAG3B,MAAM,OAAO,YAAY,KAAK;CAG9B,MAAM,cAAoB;EACxB,IAAI,YAAY,SAAS,OAAO,MAAM,WAAW,YAC9C,MAAM,OAAsB;CAEjC;CAGA,MAAM,SAAS,YAAqD;EAClE,IAAI,YAAY,SAAS,OAAO,MAAM,WAAW,YAC9C,MAAM,OAAsC,OAAO;CAExD;CAEA,OAAO;EACL;EACA;EACA;EACA;CACF;AACF;AAyBO,SAAS,eACd,cAMA;CACA,MAAM,QAAQ,IAAI,EAAE,GAAG,aAAa,CAAC;CACrC,MAAM,mBAAmB,EAAE,GAAG,aAAa;CAE3C,MAAM,YAAY,YAA8B;EAC9C,OAAO,OAAO,MAAM,OAAO,OAAO;CACpC;CAEA,MAAM,cAAoB;EACxB,MAAM,QAAQ,EAAE,GAAG,iBAAiB;CACtC;CAEA,MAAM,aAAa,aAA+C;EAQhE,OAPa,MACX,QACC,aAAa;GACZ,SAAS,QAAQ;EACnB,GACA,EAAE,MAAM,KAAK,CAER;CACT;CAEA,OAAO;EACL;EACA;EACA;EACA;CACF;AACF;AAWO,SAAS,iBAId,OACA,SAIA;CACA,MAAM,kBAAkB,CAAC;CAEzB,KAAA,MAAW,OAAO,SACf,gBAA4C,OAAO,eAClD,QAAQ,IAAG,CAAE,MAAM,KAAK,CAC1B;CAGF,OAAO;EACL;EACA,SAAS;CACX;AACF"}
@@ -0,0 +1,31 @@
1
+ import type { Ref } from 'vue';
2
+ export interface StoreInfo {
3
+ id: string;
4
+ state: Record<string, unknown>;
5
+ active: boolean;
6
+ }
7
+ export interface EventLogEntry {
8
+ type: string;
9
+ payload: unknown;
10
+ timestamp: number;
11
+ time: string;
12
+ }
13
+ export interface UseStoreDevtoolsReturn {
14
+ stores: Ref<StoreInfo[]>;
15
+ eventLog: Ref<EventLogEntry[]>;
16
+ isMonitoring: Ref<boolean>;
17
+ startMonitoring: () => void;
18
+ stopMonitoring: () => void;
19
+ clearLog: () => void;
20
+ refreshStores: () => void;
21
+ getStoreState: (id: string) => Record<string, unknown> | null;
22
+ resetStore: (id: string) => boolean;
23
+ resetAllStores: () => void;
24
+ }
25
+ export declare function useStoreDevtools(options?: {
26
+ /**
27
+ * 最多保留多少条事件日志。
28
+ */
29
+ maxLogEntries?: number;
30
+ }): UseStoreDevtoolsReturn;
31
+ //# sourceMappingURL=useStoreDevtools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStoreDevtools.d.ts","sourceRoot":"","sources":["../../src/composables/useStoreDevtools.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AAe9B,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,MAAM,EAAE,OAAO,CAAA;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC,CAAA;IACxB,QAAQ,EAAE,GAAG,CAAC,aAAa,EAAE,CAAC,CAAA;IAC9B,YAAY,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;IAC1B,eAAe,EAAE,MAAM,IAAI,CAAA;IAC3B,cAAc,EAAE,MAAM,IAAI,CAAA;IAC1B,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,aAAa,EAAE,MAAM,IAAI,CAAA;IACzB,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IAC7D,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAA;IACnC,cAAc,EAAE,MAAM,IAAI,CAAA;CAC3B;AAwBD,wBAAgB,gBAAgB,CAAC,OAAO,GAAE;IACxC;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;CAClB,GAAG,sBAAsB,CAkH9B"}
@@ -0,0 +1,112 @@
1
+ /*!
2
+ * ***********************************
3
+ * @composy/store-vue v0.0.1 *
4
+ * Built with rollup *
5
+ * Build time: 2024-08-17 11:39:29 *
6
+ * Build mode: production *
7
+ * Minified: No *
8
+ * ***********************************
9
+ */
10
+ import { getActivePinia } from "pinia";
11
+ import { onUnmounted, ref } from "vue";
12
+ import { deepClone, globalEventBus } from "@composy/store-core";
13
+ //#region src/composables/useStoreDevtools.ts
14
+ const STORE_REFRESH_EVENTS = /* @__PURE__ */ new Set([
15
+ "store:created",
16
+ "store:disposed",
17
+ "state:changed"
18
+ ]);
19
+ function formatTime(timestamp) {
20
+ const date = new Date(timestamp);
21
+ return `${date.getHours().toString().padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}:${date.getSeconds().toString().padStart(2, "0")}.${date.getMilliseconds().toString().padStart(3, "0")}`;
22
+ }
23
+ function getPinia() {
24
+ return getActivePinia() ?? null;
25
+ }
26
+ function snapshotStore(store, id) {
27
+ return {
28
+ id,
29
+ state: deepClone(store.$state),
30
+ active: true
31
+ };
32
+ }
33
+ function useStoreDevtools(options = {}) {
34
+ const { maxLogEntries = 200 } = options;
35
+ const stores = ref([]);
36
+ const eventLog = ref([]);
37
+ const isMonitoring = ref(false);
38
+ let unsubscribe = null;
39
+ function refreshStores() {
40
+ const pinia = getPinia();
41
+ if (!pinia?._s) {
42
+ stores.value = [];
43
+ return;
44
+ }
45
+ stores.value = Array.from(pinia._s.entries(), ([id, store]) => {
46
+ return snapshotStore(store, id);
47
+ });
48
+ }
49
+ function startMonitoring() {
50
+ if (isMonitoring.value) return;
51
+ isMonitoring.value = true;
52
+ unsubscribe = globalEventBus.on("*", (data) => {
53
+ const entry = {
54
+ type: data.type,
55
+ payload: data.payload,
56
+ timestamp: data.timestamp,
57
+ time: formatTime(data.timestamp)
58
+ };
59
+ eventLog.value = [entry, ...eventLog.value].slice(0, maxLogEntries);
60
+ if (STORE_REFRESH_EVENTS.has(data.type)) refreshStores();
61
+ });
62
+ }
63
+ function stopMonitoring() {
64
+ if (!isMonitoring.value) return;
65
+ isMonitoring.value = false;
66
+ unsubscribe?.();
67
+ unsubscribe = null;
68
+ }
69
+ function clearLog() {
70
+ eventLog.value = [];
71
+ }
72
+ function getStoreState(id) {
73
+ const store = getPinia()?._s?.get(id);
74
+ if (!store) return null;
75
+ return deepClone(store.$state);
76
+ }
77
+ function resetStore(id) {
78
+ const store = getPinia()?._s?.get(id);
79
+ if (!store || typeof store.$reset !== "function") return false;
80
+ store.$reset();
81
+ refreshStores();
82
+ return true;
83
+ }
84
+ function resetAllStores() {
85
+ const pinia = getPinia();
86
+ if (!pinia?._s) return;
87
+ pinia._s.forEach((store) => {
88
+ if (typeof store.$reset === "function") store.$reset();
89
+ });
90
+ refreshStores();
91
+ }
92
+ refreshStores();
93
+ onUnmounted(() => {
94
+ stopMonitoring();
95
+ });
96
+ return {
97
+ stores,
98
+ eventLog,
99
+ isMonitoring,
100
+ startMonitoring,
101
+ stopMonitoring,
102
+ clearLog,
103
+ refreshStores,
104
+ getStoreState,
105
+ resetStore,
106
+ resetAllStores
107
+ };
108
+ }
109
+ //#endregion
110
+ export { useStoreDevtools };
111
+ /*! End of @composy/store-vue | Powered by @composy/builder */
112
+ //# sourceMappingURL=useStoreDevtools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStoreDevtools.js","names":[],"sources":["../../src/composables/useStoreDevtools.ts"],"sourcesContent":["import type { EventData } from '@composy/store-core'\nimport type { Pinia, StoreGeneric } from 'pinia'\nimport type { Ref } from 'vue'\nimport { deepClone, globalEventBus } from '@composy/store-core'\nimport { getActivePinia } from 'pinia'\nimport { onUnmounted, ref } from 'vue'\n\nconst STORE_REFRESH_EVENTS = new Set([\n 'store:created',\n 'store:disposed',\n 'state:changed',\n])\n\ntype PiniaWithStores = Pinia & {\n _s?: Map<string, StoreGeneric>\n}\n\nexport interface StoreInfo {\n id: string\n state: Record<string, unknown>\n active: boolean\n}\n\nexport interface EventLogEntry {\n type: string\n payload: unknown\n timestamp: number\n time: string\n}\n\nexport interface UseStoreDevtoolsReturn {\n stores: Ref<StoreInfo[]>\n eventLog: Ref<EventLogEntry[]>\n isMonitoring: Ref<boolean>\n startMonitoring: () => void\n stopMonitoring: () => void\n clearLog: () => void\n refreshStores: () => void\n getStoreState: (id: string) => Record<string, unknown> | null\n resetStore: (id: string) => boolean\n resetAllStores: () => void\n}\n\nfunction formatTime(timestamp: number): string {\n const date = new Date(timestamp)\n const hours = date.getHours().toString().padStart(2, '0')\n const minutes = date.getMinutes().toString().padStart(2, '0')\n const seconds = date.getSeconds().toString().padStart(2, '0')\n const milliseconds = date.getMilliseconds().toString().padStart(3, '0')\n\n return `${hours}:${minutes}:${seconds}.${milliseconds}`\n}\n\nfunction getPinia(): PiniaWithStores | null {\n return (getActivePinia() ?? null) as PiniaWithStores | null\n}\n\nfunction snapshotStore(store: StoreGeneric, id: string): StoreInfo {\n return {\n id,\n state: deepClone(store.$state),\n active: true,\n }\n}\n\nexport function useStoreDevtools(options: {\n /**\n * 最多保留多少条事件日志。\n */\n maxLogEntries?: number\n} = {}): UseStoreDevtoolsReturn {\n const { maxLogEntries = 200 } = options\n\n const stores = ref<StoreInfo[]>([])\n const eventLog = ref<EventLogEntry[]>([])\n const isMonitoring = ref(false)\n\n let unsubscribe: (() => void) | null = null\n\n function refreshStores(): void {\n const pinia = getPinia()\n if (!pinia?._s) {\n stores.value = []\n return\n }\n\n stores.value = Array.from(pinia._s.entries(), ([id, store]) => {\n return snapshotStore(store, id)\n })\n }\n\n function startMonitoring(): void {\n if (isMonitoring.value) {\n return\n }\n\n isMonitoring.value = true\n unsubscribe = globalEventBus.on('*', (data: EventData) => {\n const entry: EventLogEntry = {\n type: data.type,\n payload: data.payload,\n timestamp: data.timestamp,\n time: formatTime(data.timestamp),\n }\n\n eventLog.value = [entry, ...eventLog.value].slice(0, maxLogEntries)\n\n if (STORE_REFRESH_EVENTS.has(data.type)) {\n refreshStores()\n }\n })\n }\n\n function stopMonitoring(): void {\n if (!isMonitoring.value) {\n return\n }\n\n isMonitoring.value = false\n unsubscribe?.()\n unsubscribe = null\n }\n\n function clearLog(): void {\n eventLog.value = []\n }\n\n function getStoreState(id: string): Record<string, unknown> | null {\n const pinia = getPinia()\n const store = pinia?._s?.get(id)\n\n if (!store) {\n return null\n }\n\n return deepClone(store.$state)\n }\n\n function resetStore(id: string): boolean {\n const pinia = getPinia()\n const store = pinia?._s?.get(id)\n\n if (!store || typeof store.$reset !== 'function') {\n return false\n }\n\n store.$reset()\n refreshStores()\n return true\n }\n\n function resetAllStores(): void {\n const pinia = getPinia()\n if (!pinia?._s) {\n return\n }\n\n pinia._s.forEach((store) => {\n if (typeof store.$reset === 'function') {\n store.$reset()\n }\n })\n\n refreshStores()\n }\n\n refreshStores()\n\n onUnmounted(() => {\n stopMonitoring()\n })\n\n return {\n stores,\n eventLog,\n isMonitoring,\n startMonitoring,\n stopMonitoring,\n clearLog,\n refreshStores,\n getStoreState,\n resetStore,\n resetAllStores,\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAOA,MAAM,uCAAuB,IAAI,IAAI;CACnC;CACA;CACA;AACF,CAAC;AAgCD,SAAS,WAAW,WAA2B;CAC7C,MAAM,OAAO,IAAI,KAAK,SAAS;CAM/B,OAAO,GALO,KAAK,SAAS,CAAA,CAAE,SAAS,CAAA,CAAE,SAAS,GAAG,GAK3C,EAAK,GAJC,KAAK,WAAW,CAAA,CAAE,SAAS,CAAA,CAAE,SAAS,GAAG,GAItC,EAAO,GAHV,KAAK,WAAW,CAAA,CAAE,SAAS,CAAA,CAAE,SAAS,GAAG,GAG3B,EAAO,GAFhB,KAAK,gBAAgB,CAAA,CAAE,SAAS,CAAA,CAAE,SAAS,GAAG,GAE1B;AAC3C;AAEA,SAAS,WAAmC;CAC1C,OAAQ,eAAe,KAAK;AAC9B;AAEA,SAAS,cAAc,OAAqB,IAAuB;CACjE,OAAO;EACL;EACA,OAAO,UAAU,MAAM,MAAM;EAC7B,QAAQ;CACV;AACF;AAEO,SAAS,iBAAiB,UAK7B,CAAC,GAA2B;CAC9B,MAAM,EAAE,gBAAgB,QAAQ;CAEhC,MAAM,SAAS,IAAiB,CAAC,CAAC;CAClC,MAAM,WAAW,IAAqB,CAAC,CAAC;CACxC,MAAM,eAAe,IAAI,KAAK;CAE9B,IAAI,cAAmC;CAEvC,SAAS,gBAAsB;EAC7B,MAAM,QAAQ,SAAS;EACvB,IAAI,CAAC,OAAO,IAAI;GACd,OAAO,QAAQ,CAAC;GAChB;EACF;EAEA,OAAO,QAAQ,MAAM,KAAK,MAAM,GAAG,QAAQ,IAAI,CAAC,IAAI,WAAW;GAC7D,OAAO,cAAc,OAAO,EAAE;EAChC,CAAC;CACH;CAEA,SAAS,kBAAwB;EAC/B,IAAI,aAAa,OACf;EAGF,aAAa,QAAQ;EACrB,cAAc,eAAe,GAAG,MAAM,SAAoB;GACxD,MAAM,QAAuB;IAC3B,MAAM,KAAK;IACX,SAAS,KAAK;IACd,WAAW,KAAK;IAChB,MAAM,WAAW,KAAK,SAAS;GACjC;GAEA,SAAS,QAAQ,CAAC,OAAO,GAAG,SAAS,KAAK,CAAA,CAAE,MAAM,GAAG,aAAa;GAElE,IAAI,qBAAqB,IAAI,KAAK,IAAI,GACpC,cAAc;EAElB,CAAC;CACH;CAEA,SAAS,iBAAuB;EAC9B,IAAI,CAAC,aAAa,OAChB;EAGF,aAAa,QAAQ;EACrB,cAAc;EACd,cAAc;CAChB;CAEA,SAAS,WAAiB;EACxB,SAAS,QAAQ,CAAC;CACpB;CAEA,SAAS,cAAc,IAA4C;EAEjE,MAAM,QADQ,SACA,CAAA,EAAO,IAAI,IAAI,EAAE;EAE/B,IAAI,CAAC,OACH,OAAO;EAGT,OAAO,UAAU,MAAM,MAAM;CAC/B;CAEA,SAAS,WAAW,IAAqB;EAEvC,MAAM,QADQ,SACA,CAAA,EAAO,IAAI,IAAI,EAAE;EAE/B,IAAI,CAAC,SAAS,OAAO,MAAM,WAAW,YACpC,OAAO;EAGT,MAAM,OAAO;EACb,cAAc;EACd,OAAO;CACT;CAEA,SAAS,iBAAuB;EAC9B,MAAM,QAAQ,SAAS;EACvB,IAAI,CAAC,OAAO,IACV;EAGF,MAAM,GAAG,SAAS,UAAU;GAC1B,IAAI,OAAO,MAAM,WAAW,YAC1B,MAAM,OAAO;EAEjB,CAAC;EAED,cAAc;CAChB;CAEA,cAAc;CAEd,kBAAkB;EAChB,eAAe;CACjB,CAAC;CAED,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * useStoreSnapshot - Store 状态快照工具
3
+ *
4
+ * 提供状态快照、历史记录和调试功能
5
+ * @module composables/useStoreSnapshot
6
+ */
7
+ import type { ComputedRef, Ref } from 'vue';
8
+ /**
9
+ * 状态快照
10
+ */
11
+ export interface StateSnapshot<S = unknown> {
12
+ /** 快照 ID */
13
+ id: string;
14
+ /** 状态数据 */
15
+ state: S;
16
+ /** 时间戳 */
17
+ timestamp: number;
18
+ /** 快照标签 */
19
+ label?: string;
20
+ /** 元数据 */
21
+ meta?: Record<string, unknown>;
22
+ }
23
+ /**
24
+ * 状态差异
25
+ */
26
+ export interface StateDiff {
27
+ /** 差异路径 */
28
+ path: string;
29
+ /** 旧值 */
30
+ oldValue: unknown;
31
+ /** 新值 */
32
+ newValue: unknown;
33
+ /** 差异类型 */
34
+ type: 'add' | 'remove' | 'change';
35
+ }
36
+ /**
37
+ * useStoreSnapshot 选项
38
+ */
39
+ export interface UseStoreSnapshotOptions {
40
+ /** 最大快照数量 */
41
+ maxSnapshots?: number;
42
+ /** 是否自动记录 */
43
+ autoRecord?: boolean;
44
+ /** 自动记录防抖延迟(毫秒) */
45
+ debounceMs?: number;
46
+ /** 是否深度监听 */
47
+ deep?: boolean;
48
+ }
49
+ /**
50
+ * useStoreSnapshot 返回值
51
+ */
52
+ export interface UseStoreSnapshotReturn<S> {
53
+ /** 快照列表 */
54
+ snapshots: Ref<Array<StateSnapshot<S>>>;
55
+ /** 当前快照索引 */
56
+ currentIndex: Ref<number>;
57
+ /** 是否可以撤销 */
58
+ canUndo: ComputedRef<boolean>;
59
+ /** 是否可以重做 */
60
+ canRedo: ComputedRef<boolean>;
61
+ /** 创建快照 */
62
+ takeSnapshot: (label?: string, meta?: Record<string, unknown>) => StateSnapshot<S>;
63
+ /** 恢复快照 */
64
+ restoreSnapshot: (id: string) => boolean;
65
+ /** 撤销 */
66
+ undo: () => boolean;
67
+ /** 重做 */
68
+ redo: () => boolean;
69
+ /** 跳转到指定快照 */
70
+ goto: (index: number) => boolean;
71
+ /** 清空快照 */
72
+ clearSnapshots: () => void;
73
+ /** 获取状态差异 */
74
+ getDiff: (snapshotId1: string, snapshotId2: string) => StateDiff[];
75
+ /** 导出快照 */
76
+ exportSnapshots: () => string;
77
+ /** 导入快照 */
78
+ importSnapshots: (data: string) => boolean;
79
+ }
80
+ /**
81
+ * Store 状态快照 Hook
82
+ *
83
+ * 提供状态快照、撤销/重做和调试功能
84
+ *
85
+ * @template S - 状态类型
86
+ * @param state - 响应式状态
87
+ * @param setState - 状态设置函数
88
+ * @param options - 配置选项
89
+ * @returns 快照操作对象
90
+ *
91
+ * @example
92
+ * ```typescript
93
+ * const store = useCounterStore()
94
+ *
95
+ * const {
96
+ * snapshots,
97
+ * canUndo,
98
+ * canRedo,
99
+ * takeSnapshot,
100
+ * undo,
101
+ * redo,
102
+ * getDiff
103
+ * } = useStoreSnapshot(
104
+ * () => store.$state,
105
+ * (state) => store.$patch(state),
106
+ * { maxSnapshots: 50, autoRecord: true }
107
+ * )
108
+ *
109
+ * // 手动创建快照
110
+ * takeSnapshot('保存点 1')
111
+ *
112
+ * // 撤销操作
113
+ * if (canUndo.value) {
114
+ * undo()
115
+ * }
116
+ *
117
+ * // 获取状态差异
118
+ * const diff = getDiff(snapshots.value[0].id, snapshots.value[1].id)
119
+ * ```
120
+ */
121
+ export declare function useStoreSnapshot<S>(state: Ref<S> | (() => S), setState: (state: S) => void, options?: UseStoreSnapshotOptions): UseStoreSnapshotReturn<S>;
122
+ //# sourceMappingURL=useStoreSnapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStoreSnapshot.d.ts","sourceRoot":"","sources":["../../src/composables/useStoreSnapshot.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAC,WAAW,EAAE,GAAG,EAAC,MAAM,KAAK,CAAC;AAI1C;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,OAAO;IACxC,YAAY;IACZ,EAAE,EAAE,MAAM,CAAA;IACV,WAAW;IACX,KAAK,EAAE,CAAC,CAAA;IACR,UAAU;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU;IACV,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,WAAW;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS;IACT,QAAQ,EAAE,OAAO,CAAA;IACjB,SAAS;IACT,QAAQ,EAAE,OAAO,CAAA;IACjB,WAAW;IACX,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAA;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,aAAa;IACb,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa;IACb,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,mBAAmB;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,aAAa;IACb,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB,CAAC,CAAC;IACvC,WAAW;IACX,SAAS,EAAE,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACvC,aAAa;IACb,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACzB,aAAa;IACb,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,CAAA;IAC7B,aAAa;IACb,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,CAAA;IAC7B,WAAW;IACX,YAAY,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,aAAa,CAAC,CAAC,CAAC,CAAA;IAClF,WAAW;IACX,eAAe,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAA;IACxC,SAAS;IACT,IAAI,EAAE,MAAM,OAAO,CAAA;IACnB,SAAS;IACT,IAAI,EAAE,MAAM,OAAO,CAAA;IACnB,cAAc;IACd,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAA;IAChC,WAAW;IACX,cAAc,EAAE,MAAM,IAAI,CAAA;IAC1B,aAAa;IACb,OAAO,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,SAAS,EAAE,CAAA;IAClE,WAAW;IACX,eAAe,EAAE,MAAM,MAAM,CAAA;IAC7B,WAAW;IACX,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAA;CAC3C;AAmHD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EACzB,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,EAC5B,OAAO,GAAE,uBAA4B,GACpC,sBAAsB,CAAC,CAAC,CAAC,CAuO3B"}
@@ -0,0 +1,209 @@
1
+ /*!
2
+ * ***********************************
3
+ * @composy/store-vue v0.0.1 *
4
+ * Built with rollup *
5
+ * Build time: 2024-08-17 11:39:29 *
6
+ * Build mode: production *
7
+ * Minified: No *
8
+ * ***********************************
9
+ */
10
+ import { computed, onUnmounted, ref, watch } from "vue";
11
+ import { deepClone, deepEqual } from "@composy/store-core";
12
+ //#region src/composables/useStoreSnapshot.ts
13
+ function generateId() {
14
+ return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
15
+ }
16
+ function computeDiff(oldObj, newObj, path = "") {
17
+ const diffs = [];
18
+ if (typeof oldObj !== typeof newObj) {
19
+ diffs.push({
20
+ path: path || ".",
21
+ oldValue: oldObj,
22
+ newValue: newObj,
23
+ type: "change"
24
+ });
25
+ return diffs;
26
+ }
27
+ if (typeof oldObj !== "object" || oldObj === null || newObj === null) {
28
+ if (!Object.is(oldObj, newObj)) diffs.push({
29
+ path: path || ".",
30
+ oldValue: oldObj,
31
+ newValue: newObj,
32
+ type: "change"
33
+ });
34
+ return diffs;
35
+ }
36
+ if (Array.isArray(oldObj) && Array.isArray(newObj)) {
37
+ const maxLen = Math.max(oldObj.length, newObj.length);
38
+ for (let i = 0; i < maxLen; i++) {
39
+ const itemPath = path ? `${path}[${i}]` : `[${i}]`;
40
+ if (i >= oldObj.length) diffs.push({
41
+ path: itemPath,
42
+ oldValue: void 0,
43
+ newValue: newObj[i],
44
+ type: "add"
45
+ });
46
+ else if (i >= newObj.length) diffs.push({
47
+ path: itemPath,
48
+ oldValue: oldObj[i],
49
+ newValue: void 0,
50
+ type: "remove"
51
+ });
52
+ else diffs.push(...computeDiff(oldObj[i], newObj[i], itemPath));
53
+ }
54
+ return diffs;
55
+ }
56
+ const oldKeys = new Set(Object.keys(oldObj));
57
+ const newKeys = new Set(Object.keys(newObj));
58
+ for (const key of newKeys) if (!oldKeys.has(key)) diffs.push({
59
+ path: path ? `${path}.${key}` : key,
60
+ oldValue: void 0,
61
+ newValue: newObj[key],
62
+ type: "add"
63
+ });
64
+ for (const key of oldKeys) if (!newKeys.has(key)) diffs.push({
65
+ path: path ? `${path}.${key}` : key,
66
+ oldValue: oldObj[key],
67
+ newValue: void 0,
68
+ type: "remove"
69
+ });
70
+ for (const key of oldKeys) if (newKeys.has(key)) diffs.push(...computeDiff(oldObj[key], newObj[key], path ? `${path}.${key}` : key));
71
+ return diffs;
72
+ }
73
+ function useStoreSnapshot(state, setState, options = {}) {
74
+ const { maxSnapshots = 100, autoRecord = false, debounceMs = 300, deep = true } = options;
75
+ const snapshots = ref([]);
76
+ const currentIndex = ref(-1);
77
+ let debounceTimer;
78
+ let isRestoring = false;
79
+ const getState = () => {
80
+ return typeof state === "function" ? state() : state.value;
81
+ };
82
+ const canUndo = computed(() => currentIndex.value > 0);
83
+ const canRedo = computed(() => currentIndex.value < snapshots.value.length - 1);
84
+ const takeSnapshot = (label, meta) => {
85
+ const currentState = getState();
86
+ const snapshot = {
87
+ id: generateId(),
88
+ state: deepClone(currentState),
89
+ timestamp: Date.now(),
90
+ label,
91
+ meta
92
+ };
93
+ if (currentIndex.value < snapshots.value.length - 1) snapshots.value = snapshots.value.slice(0, currentIndex.value + 1);
94
+ snapshots.value.push(snapshot);
95
+ currentIndex.value = snapshots.value.length - 1;
96
+ if (snapshots.value.length > maxSnapshots) {
97
+ snapshots.value.shift();
98
+ currentIndex.value--;
99
+ }
100
+ return snapshot;
101
+ };
102
+ const restoreSnapshot = (id) => {
103
+ const index = snapshots.value.findIndex((s) => s.id === id);
104
+ if (index === -1) return false;
105
+ isRestoring = true;
106
+ try {
107
+ setState(deepClone(snapshots.value[index].state));
108
+ currentIndex.value = index;
109
+ return true;
110
+ } finally {
111
+ isRestoring = false;
112
+ }
113
+ };
114
+ const undo = () => {
115
+ if (!canUndo.value) return false;
116
+ currentIndex.value--;
117
+ isRestoring = true;
118
+ try {
119
+ setState(deepClone(snapshots.value[currentIndex.value].state));
120
+ return true;
121
+ } finally {
122
+ isRestoring = false;
123
+ }
124
+ };
125
+ const redo = () => {
126
+ if (!canRedo.value) return false;
127
+ currentIndex.value++;
128
+ isRestoring = true;
129
+ try {
130
+ setState(deepClone(snapshots.value[currentIndex.value].state));
131
+ return true;
132
+ } finally {
133
+ isRestoring = false;
134
+ }
135
+ };
136
+ const goto = (index) => {
137
+ if (index < 0 || index >= snapshots.value.length) return false;
138
+ currentIndex.value = index;
139
+ isRestoring = true;
140
+ try {
141
+ setState(deepClone(snapshots.value[index].state));
142
+ return true;
143
+ } finally {
144
+ isRestoring = false;
145
+ }
146
+ };
147
+ const clearSnapshots = () => {
148
+ snapshots.value = [];
149
+ currentIndex.value = -1;
150
+ };
151
+ const getDiff = (snapshotId1, snapshotId2) => {
152
+ const snapshot1 = snapshots.value.find((s) => s.id === snapshotId1);
153
+ const snapshot2 = snapshots.value.find((s) => s.id === snapshotId2);
154
+ if (!snapshot1 || !snapshot2) return [];
155
+ return computeDiff(snapshot1.state, snapshot2.state);
156
+ };
157
+ const exportSnapshots = () => {
158
+ return JSON.stringify({
159
+ snapshots: snapshots.value,
160
+ currentIndex: currentIndex.value,
161
+ exportedAt: Date.now()
162
+ });
163
+ };
164
+ const importSnapshots = (data) => {
165
+ try {
166
+ const parsed = JSON.parse(data);
167
+ if (!Array.isArray(parsed.snapshots)) return false;
168
+ snapshots.value = parsed.snapshots;
169
+ currentIndex.value = Math.min(parsed.currentIndex ?? snapshots.value.length - 1, snapshots.value.length - 1);
170
+ return true;
171
+ } catch {
172
+ return false;
173
+ }
174
+ };
175
+ if (autoRecord) {
176
+ const stopWatch = watch(typeof state === "function" ? computed(state) : state, (newState, oldState) => {
177
+ if (isRestoring) return;
178
+ if (deepEqual(newState, oldState)) return;
179
+ if (debounceTimer) clearTimeout(debounceTimer);
180
+ debounceTimer = setTimeout(() => {
181
+ takeSnapshot();
182
+ }, debounceMs);
183
+ }, { deep });
184
+ takeSnapshot("初始状态");
185
+ onUnmounted(() => {
186
+ stopWatch();
187
+ if (debounceTimer) clearTimeout(debounceTimer);
188
+ });
189
+ }
190
+ return {
191
+ snapshots,
192
+ currentIndex,
193
+ canUndo,
194
+ canRedo,
195
+ takeSnapshot,
196
+ restoreSnapshot,
197
+ undo,
198
+ redo,
199
+ goto,
200
+ clearSnapshots,
201
+ getDiff,
202
+ exportSnapshots,
203
+ importSnapshots
204
+ };
205
+ }
206
+ //#endregion
207
+ export { useStoreSnapshot };
208
+ /*! End of @composy/store-vue | Powered by @composy/builder */
209
+ //# sourceMappingURL=useStoreSnapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStoreSnapshot.js","names":[],"sources":["../../src/composables/useStoreSnapshot.ts"],"sourcesContent":["/**\n * useStoreSnapshot - Store 状态快照工具\n *\n * 提供状态快照、历史记录和调试功能\n * @module composables/useStoreSnapshot\n */\n\nimport type {ComputedRef, Ref} from 'vue';\nimport { deepClone, deepEqual } from '@composy/store-core'\nimport { computed, onUnmounted, ref, watch } from 'vue'\n\n/**\n * 状态快照\n */\nexport interface StateSnapshot<S = unknown> {\n /** 快照 ID */\n id: string\n /** 状态数据 */\n state: S\n /** 时间戳 */\n timestamp: number\n /** 快照标签 */\n label?: string\n /** 元数据 */\n meta?: Record<string, unknown>\n}\n\n/**\n * 状态差异\n */\nexport interface StateDiff {\n /** 差异路径 */\n path: string\n /** 旧值 */\n oldValue: unknown\n /** 新值 */\n newValue: unknown\n /** 差异类型 */\n type: 'add' | 'remove' | 'change'\n}\n\n/**\n * useStoreSnapshot 选项\n */\nexport interface UseStoreSnapshotOptions {\n /** 最大快照数量 */\n maxSnapshots?: number\n /** 是否自动记录 */\n autoRecord?: boolean\n /** 自动记录防抖延迟(毫秒) */\n debounceMs?: number\n /** 是否深度监听 */\n deep?: boolean\n}\n\n/**\n * useStoreSnapshot 返回值\n */\nexport interface UseStoreSnapshotReturn<S> {\n /** 快照列表 */\n snapshots: Ref<Array<StateSnapshot<S>>>\n /** 当前快照索引 */\n currentIndex: Ref<number>\n /** 是否可以撤销 */\n canUndo: ComputedRef<boolean>\n /** 是否可以重做 */\n canRedo: ComputedRef<boolean>\n /** 创建快照 */\n takeSnapshot: (label?: string, meta?: Record<string, unknown>) => StateSnapshot<S>\n /** 恢复快照 */\n restoreSnapshot: (id: string) => boolean\n /** 撤销 */\n undo: () => boolean\n /** 重做 */\n redo: () => boolean\n /** 跳转到指定快照 */\n goto: (index: number) => boolean\n /** 清空快照 */\n clearSnapshots: () => void\n /** 获取状态差异 */\n getDiff: (snapshotId1: string, snapshotId2: string) => StateDiff[]\n /** 导出快照 */\n exportSnapshots: () => string\n /** 导入快照 */\n importSnapshots: (data: string) => boolean\n}\n\n/**\n * 生成唯一 ID\n */\nfunction generateId(): string {\n return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`\n}\n\n/**\n * 计算两个对象的差异\n */\nfunction computeDiff(\n oldObj: unknown,\n newObj: unknown,\n path = '',\n): StateDiff[] {\n const diffs: StateDiff[] = []\n\n // 类型不同\n if (typeof oldObj !== typeof newObj) {\n diffs.push({\n path: path || '.',\n oldValue: oldObj,\n newValue: newObj,\n type: 'change',\n })\n return diffs\n }\n\n // 基础类型比较\n if (typeof oldObj !== 'object' || oldObj === null || newObj === null) {\n if (!Object.is(oldObj, newObj)) {\n diffs.push({\n path: path || '.',\n oldValue: oldObj,\n newValue: newObj,\n type: 'change',\n })\n }\n return diffs\n }\n\n // 数组比较\n if (Array.isArray(oldObj) && Array.isArray(newObj)) {\n const maxLen = Math.max(oldObj.length, newObj.length)\n for (let i = 0; i < maxLen; i++) {\n const itemPath = path ? `${path}[${i}]` : `[${i}]`\n if (i >= oldObj.length) {\n diffs.push({\n path: itemPath,\n oldValue: undefined,\n newValue: newObj[i],\n type: 'add',\n })\n }\n else if (i >= newObj.length) {\n diffs.push({\n path: itemPath,\n oldValue: oldObj[i],\n newValue: undefined,\n type: 'remove',\n })\n }\n else {\n diffs.push(...computeDiff(oldObj[i], newObj[i], itemPath))\n }\n }\n return diffs\n }\n\n // 对象比较\n const oldKeys = new Set(Object.keys(oldObj as Record<string, unknown>))\n const newKeys = new Set(Object.keys(newObj as Record<string, unknown>))\n\n // 检查新增的键\n for (const key of newKeys) {\n if (!oldKeys.has(key)) {\n diffs.push({\n path: path ? `${path}.${key}` : key,\n oldValue: undefined,\n newValue: (newObj as Record<string, unknown>)[key],\n type: 'add',\n })\n }\n }\n\n // 检查删除的键\n for (const key of oldKeys) {\n if (!newKeys.has(key)) {\n diffs.push({\n path: path ? `${path}.${key}` : key,\n oldValue: (oldObj as Record<string, unknown>)[key],\n newValue: undefined,\n type: 'remove',\n })\n }\n }\n\n // 检查修改的键\n for (const key of oldKeys) {\n if (newKeys.has(key)) {\n diffs.push(\n ...computeDiff(\n (oldObj as Record<string, unknown>)[key],\n (newObj as Record<string, unknown>)[key],\n path ? `${path}.${key}` : key,\n ),\n )\n }\n }\n\n return diffs\n}\n\n/**\n * Store 状态快照 Hook\n *\n * 提供状态快照、撤销/重做和调试功能\n *\n * @template S - 状态类型\n * @param state - 响应式状态\n * @param setState - 状态设置函数\n * @param options - 配置选项\n * @returns 快照操作对象\n *\n * @example\n * ```typescript\n * const store = useCounterStore()\n *\n * const {\n * snapshots,\n * canUndo,\n * canRedo,\n * takeSnapshot,\n * undo,\n * redo,\n * getDiff\n * } = useStoreSnapshot(\n * () => store.$state,\n * (state) => store.$patch(state),\n * { maxSnapshots: 50, autoRecord: true }\n * )\n *\n * // 手动创建快照\n * takeSnapshot('保存点 1')\n *\n * // 撤销操作\n * if (canUndo.value) {\n * undo()\n * }\n *\n * // 获取状态差异\n * const diff = getDiff(snapshots.value[0].id, snapshots.value[1].id)\n * ```\n */\nexport function useStoreSnapshot<S>(\n state: Ref<S> | (() => S),\n setState: (state: S) => void,\n options: UseStoreSnapshotOptions = {},\n): UseStoreSnapshotReturn<S> {\n const {\n maxSnapshots = 100,\n autoRecord = false,\n debounceMs = 300,\n deep = true,\n } = options\n\n const snapshots = ref<Array<StateSnapshot<S>>>([]) as Ref<Array<StateSnapshot<S>>>\n const currentIndex = ref(-1)\n let debounceTimer: ReturnType<typeof setTimeout> | undefined\n let isRestoring = false\n\n // 获取当前状态\n const getState = (): S => {\n return typeof state === 'function' ? state() : state.value\n }\n\n // 是否可以撤销\n const canUndo = computed(() => currentIndex.value > 0)\n\n // 是否可以重做\n const canRedo = computed(() => currentIndex.value < snapshots.value.length - 1)\n\n /**\n * 创建快照\n */\n const takeSnapshot = (label?: string, meta?: Record<string, unknown>): StateSnapshot<S> => {\n const currentState = getState()\n const snapshot: StateSnapshot<S> = {\n id: generateId(),\n state: deepClone(currentState),\n timestamp: Date.now(),\n label,\n meta,\n }\n\n // 如果当前不在最新位置,删除后面的快照\n if (currentIndex.value < snapshots.value.length - 1) {\n snapshots.value = snapshots.value.slice(0, currentIndex.value + 1)\n }\n\n // 添加新快照\n snapshots.value.push(snapshot)\n currentIndex.value = snapshots.value.length - 1\n\n // 限制快照数量\n if (snapshots.value.length > maxSnapshots) {\n snapshots.value.shift()\n currentIndex.value--\n }\n\n return snapshot\n }\n\n /**\n * 恢复快照\n */\n const restoreSnapshot = (id: string): boolean => {\n const index = snapshots.value.findIndex(s => s.id === id)\n if (index === -1) return false\n\n isRestoring = true\n try {\n setState(deepClone(snapshots.value[index].state))\n currentIndex.value = index\n return true\n }\n finally {\n isRestoring = false\n }\n }\n\n /**\n * 撤销\n */\n const undo = (): boolean => {\n if (!canUndo.value) return false\n\n currentIndex.value--\n isRestoring = true\n try {\n setState(deepClone(snapshots.value[currentIndex.value].state))\n return true\n }\n finally {\n isRestoring = false\n }\n }\n\n /**\n * 重做\n */\n const redo = (): boolean => {\n if (!canRedo.value) return false\n\n currentIndex.value++\n isRestoring = true\n try {\n setState(deepClone(snapshots.value[currentIndex.value].state))\n return true\n }\n finally {\n isRestoring = false\n }\n }\n\n /**\n * 跳转到指定快照\n */\n const goto = (index: number): boolean => {\n if (index < 0 || index >= snapshots.value.length) return false\n\n currentIndex.value = index\n isRestoring = true\n try {\n setState(deepClone(snapshots.value[index].state))\n return true\n }\n finally {\n isRestoring = false\n }\n }\n\n /**\n * 清空快照\n */\n const clearSnapshots = (): void => {\n snapshots.value = []\n currentIndex.value = -1\n }\n\n /**\n * 获取状态差异\n */\n const getDiff = (snapshotId1: string, snapshotId2: string): StateDiff[] => {\n const snapshot1 = snapshots.value.find(s => s.id === snapshotId1)\n const snapshot2 = snapshots.value.find(s => s.id === snapshotId2)\n\n if (!snapshot1 || !snapshot2) return []\n\n return computeDiff(snapshot1.state, snapshot2.state)\n }\n\n /**\n * 导出快照\n */\n const exportSnapshots = (): string => {\n return JSON.stringify({\n snapshots: snapshots.value,\n currentIndex: currentIndex.value,\n exportedAt: Date.now(),\n })\n }\n\n /**\n * 导入快照\n */\n const importSnapshots = (data: string): boolean => {\n try {\n const parsed = JSON.parse(data) as {\n snapshots: Array<StateSnapshot<S>>\n currentIndex: number\n }\n\n if (!Array.isArray(parsed.snapshots)) return false\n\n snapshots.value = parsed.snapshots\n currentIndex.value = Math.min(\n parsed.currentIndex ?? snapshots.value.length - 1,\n snapshots.value.length - 1,\n )\n\n return true\n }\n catch {\n return false\n }\n }\n\n // 自动记录\n if (autoRecord) {\n const stateRef = typeof state === 'function' ? computed(state) : state\n\n const stopWatch = watch(\n stateRef,\n (newState, oldState) => {\n // 如果是恢复操作,不记录\n if (isRestoring) return\n\n // 如果状态未变化,不记录\n if (deepEqual(newState, oldState)) return\n\n // 防抖记录\n if (debounceTimer) {\n clearTimeout(debounceTimer)\n }\n\n debounceTimer = setTimeout(() => {\n takeSnapshot()\n }, debounceMs)\n },\n { deep },\n )\n\n // 初始快照\n takeSnapshot('初始状态')\n\n onUnmounted(() => {\n stopWatch()\n if (debounceTimer) {\n clearTimeout(debounceTimer)\n }\n })\n }\n\n return {\n snapshots,\n currentIndex,\n canUndo,\n canRedo,\n takeSnapshot,\n restoreSnapshot,\n undo,\n redo,\n goto,\n clearSnapshots,\n getDiff,\n exportSnapshots,\n importSnapshots,\n }\n}\n\n"],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * useSubscribe Composable
3
+ *
4
+ * 提供 Store 订阅功能
5
+ * @module composables/useSubscribe
6
+ */
7
+ import type { Ref, WatchStopHandle } from 'vue';
8
+ import type { MutationInfo, SubscribeOptions } from '../types';
9
+ /**
10
+ * 订阅 Store 状态变化
11
+ *
12
+ * @template S - 状态类型
13
+ * @param store - Pinia Store 实例
14
+ * @param callback - 回调函数
15
+ * @param options - 订阅选项
16
+ * @returns 取消订阅函数
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * const store = useCounterStore()
21
+ *
22
+ * // 订阅状态变化
23
+ * const unsubscribe = useSubscribe(store, (mutation, state) => {
24
+ * console.log('State changed:', mutation.type, state)
25
+ * })
26
+ *
27
+ * // 取消订阅
28
+ * unsubscribe()
29
+ * ```
30
+ */
31
+ export declare function useSubscribe<S extends Record<string, unknown>>(store: S & {
32
+ $subscribe?: (callback: (mutation: MutationInfo<S>, state: S) => void, options?: {
33
+ detached?: boolean;
34
+ }) => () => void;
35
+ }, callback: (mutation: MutationInfo<S>, state: S) => void, options?: SubscribeOptions): () => void;
36
+ /**
37
+ * 订阅 Store Action 调用
38
+ *
39
+ * @template S - Store 类型
40
+ * @param store - Pinia Store 实例
41
+ * @param callback - 回调函数
42
+ * @returns 取消订阅函数
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * const store = useCounterStore()
47
+ *
48
+ * // 订阅 Action 调用
49
+ * useOnAction(store, ({ name, args, after, onError }) => {
50
+ * console.log(`Action ${name} called with:`, args)
51
+ *
52
+ * after((result) => {
53
+ * console.log(`Action ${name} finished with:`, result)
54
+ * })
55
+ *
56
+ * onError((error) => {
57
+ * console.error(`Action ${name} failed:`, error)
58
+ * })
59
+ * })
60
+ * ```
61
+ */
62
+ export declare function useOnAction<S extends Record<string, unknown>>(store: S & {
63
+ $onAction?: (callback: (context: ActionContext) => void, detached?: boolean) => () => void;
64
+ }, callback: (context: ActionContext) => void, detached?: boolean): () => void;
65
+ /**
66
+ * Action 上下文
67
+ */
68
+ export interface ActionContext {
69
+ /** Action 名称 */
70
+ name: string;
71
+ /** Store 实例 */
72
+ store: unknown;
73
+ /** Action 参数 */
74
+ args: unknown[];
75
+ /** Action 完成后回调 */
76
+ after: (callback: (result: unknown) => void) => void;
77
+ /** Action 错误回调 */
78
+ onError: (callback: (error: unknown) => void) => void;
79
+ }
80
+ /**
81
+ * 监听 ref 变化
82
+ *
83
+ * @template T - 值类型
84
+ * @param source - 监听源
85
+ * @param callback - 回调函数
86
+ * @param options - 监听选项
87
+ * @returns 停止监听函数
88
+ */
89
+ export declare function useWatch<T>(source: Ref<T>, callback: (newValue: T, oldValue: T | undefined) => void, options?: SubscribeOptions): WatchStopHandle;
90
+ //# sourceMappingURL=useSubscribe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSubscribe.d.ts","sourceRoot":"","sources":["../../src/composables/useSubscribe.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,eAAe,EAAE,MAAM,KAAK,CAAA;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAG9D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5D,KAAK,EAAE,CAAC,GAAG;IAAE,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,MAAM,IAAI,CAAA;CAAE,EACrI,QAAQ,EAAE,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,EACvD,OAAO,GAAE,gBAAqB,GAC7B,MAAM,IAAI,CAyBZ;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC3D,KAAK,EAAE,CAAC,GAAG;IAAE,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,EAAE,QAAQ,CAAC,EAAE,OAAO,KAAK,MAAM,IAAI,CAAA;CAAE,EACzG,QAAQ,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,EAC1C,QAAQ,UAAQ,GACf,MAAM,IAAI,CAeZ;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,gBAAgB;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,eAAe;IACf,KAAK,EAAE,OAAO,CAAA;IACd,gBAAgB;IAChB,IAAI,EAAE,OAAO,EAAE,CAAA;IACf,mBAAmB;IACnB,KAAK,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,KAAK,IAAI,CAAA;IACpD,kBAAkB;IAClB,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,KAAK,IAAI,CAAA;CACtD;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EACxB,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,EACd,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,SAAS,KAAK,IAAI,EACxD,OAAO,GAAE,gBAAqB,GAC7B,eAAe,CAkBjB"}