@composy/store-core 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 (300) hide show
  1. package/CHANGELOG.md +64 -3
  2. package/README.md +196 -172
  3. package/dist/index.js +1331 -1115
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.min.js +578 -417
  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/core/async-action.d.ts +1 -71
  10. package/es/core/async-action.js +83 -35
  11. package/es/core/async-action.js.map +1 -1
  12. package/es/core/base-store.d.ts +27 -62
  13. package/es/core/base-store.js +174 -74
  14. package/es/core/base-store.js.map +1 -1
  15. package/es/core/batch-manager.d.ts +0 -1
  16. package/es/core/batch-manager.js +15 -2
  17. package/es/core/batch-manager.js.map +1 -1
  18. package/es/core/create-store.d.ts +3 -3
  19. package/es/core/create-store.js +3 -3
  20. package/es/core/create-store.js.map +1 -1
  21. package/es/core/event-bus.d.ts +0 -1
  22. package/es/core/event-bus.js +1 -1
  23. package/es/core/event-bus.js.map +1 -1
  24. package/es/core/index.d.ts +1 -2
  25. package/es/core/index.js +2 -2
  26. package/es/core/pub-sub.d.ts +0 -1
  27. package/es/core/pub-sub.js +1 -1
  28. package/es/core/pub-sub.js.map +1 -1
  29. package/es/engine/index.d.ts +0 -1
  30. package/es/engine/index.js +1 -1
  31. package/es/engine/plugin.d.ts +0 -1
  32. package/es/engine/plugin.js +11 -2
  33. package/es/engine/plugin.js.map +1 -1
  34. package/es/engine/types.d.ts +0 -1
  35. package/es/engine/types.js +1 -1
  36. package/es/errors/index.d.ts +0 -1
  37. package/es/errors/index.js +17 -1
  38. package/es/errors/index.js.map +1 -1
  39. package/es/index.d.ts +3 -4
  40. package/es/index.js +8 -8
  41. package/es/index.js.map +1 -1
  42. package/es/middleware/index.d.ts +3 -4
  43. package/es/middleware/index.js +2 -2
  44. package/es/middleware/logger.d.ts +0 -1
  45. package/es/middleware/logger.js +2 -2
  46. package/es/middleware/logger.js.map +1 -1
  47. package/es/middleware/middleware-manager.d.ts +0 -1
  48. package/es/middleware/middleware-manager.js +5 -2
  49. package/es/middleware/middleware-manager.js.map +1 -1
  50. package/es/middleware/persist.d.ts +0 -1
  51. package/es/middleware/persist.js +3 -3
  52. package/es/middleware/persist.js.map +1 -1
  53. package/es/middleware/time-travel.d.ts +0 -1
  54. package/es/middleware/time-travel.js +1 -1
  55. package/es/middleware/time-travel.js.map +1 -1
  56. package/es/middleware/validation.d.ts +0 -1
  57. package/es/middleware/validation.js +2 -2
  58. package/es/middleware/validation.js.map +1 -1
  59. package/es/plugins/define-plugin.d.ts +1 -2
  60. package/es/plugins/define-plugin.js +2 -2
  61. package/es/plugins/define-plugin.js.map +1 -1
  62. package/es/plugins/index.d.ts +0 -1
  63. package/es/plugins/index.js +2 -2
  64. package/es/plugins/plugin-manager.d.ts +1 -31
  65. package/es/plugins/plugin-manager.js +58 -27
  66. package/es/plugins/plugin-manager.js.map +1 -1
  67. package/es/types/action.d.ts +2 -0
  68. package/es/types/action.js +10 -0
  69. package/es/types/batch.d.ts +2 -0
  70. package/es/types/batch.js +10 -0
  71. package/es/types/event.d.ts +2 -0
  72. package/es/types/event.js +10 -0
  73. package/es/types/index.d.ts +2 -3
  74. package/es/types/index.js +1 -1
  75. package/es/types/middleware.d.ts +10 -2
  76. package/es/types/middleware.js +1 -1
  77. package/es/types/mutation.d.ts +2 -0
  78. package/es/types/mutation.js +10 -0
  79. package/es/types/plugin.d.ts +4 -1
  80. package/es/types/plugin.js +1 -1
  81. package/es/types/state.d.ts +2 -0
  82. package/es/types/state.js +10 -0
  83. package/es/types/store.d.ts +19 -1
  84. package/es/types/store.js +1 -1
  85. package/es/types/subscription.d.ts +7 -2
  86. package/es/types/subscription.js +1 -1
  87. package/es/types/time-travel.d.ts +2 -0
  88. package/es/types/time-travel.js +10 -0
  89. package/es/types/utility.d.ts +3 -4
  90. package/es/types/utility.js +1 -1
  91. package/es/utils/debounce-throttle.d.ts +0 -1
  92. package/es/utils/debounce-throttle.js +1 -1
  93. package/es/utils/debounce-throttle.js.map +1 -1
  94. package/es/utils/deep-clone.d.ts +0 -1
  95. package/es/utils/deep-clone.js +1 -1
  96. package/es/utils/deep-clone.js.map +1 -1
  97. package/es/utils/index.d.ts +4 -5
  98. package/es/utils/index.js +1 -1
  99. package/es/utils/selector.d.ts +0 -1
  100. package/es/utils/selector.js +1 -1
  101. package/es/utils/selector.js.map +1 -1
  102. package/esm/core/async-action.js +83 -35
  103. package/esm/core/async-action.js.map +1 -1
  104. package/esm/core/base-store.js +174 -74
  105. package/esm/core/base-store.js.map +1 -1
  106. package/esm/core/batch-manager.js +15 -2
  107. package/esm/core/batch-manager.js.map +1 -1
  108. package/esm/core/create-store.js +3 -3
  109. package/esm/core/create-store.js.map +1 -1
  110. package/esm/core/event-bus.js +1 -1
  111. package/esm/core/event-bus.js.map +1 -1
  112. package/esm/core/index.js +2 -2
  113. package/esm/core/pub-sub.js +1 -1
  114. package/esm/core/pub-sub.js.map +1 -1
  115. package/esm/engine/index.js +1 -1
  116. package/esm/engine/plugin.js +11 -2
  117. package/esm/engine/plugin.js.map +1 -1
  118. package/esm/errors/index.js +17 -1
  119. package/esm/errors/index.js.map +1 -1
  120. package/esm/index.js +8 -8
  121. package/esm/index.js.map +1 -1
  122. package/esm/middleware/logger.js +2 -2
  123. package/esm/middleware/logger.js.map +1 -1
  124. package/esm/middleware/middleware-manager.js +5 -2
  125. package/esm/middleware/middleware-manager.js.map +1 -1
  126. package/esm/middleware/persist.js +3 -3
  127. package/esm/middleware/persist.js.map +1 -1
  128. package/esm/middleware/time-travel.js +1 -1
  129. package/esm/middleware/time-travel.js.map +1 -1
  130. package/esm/middleware/validation.js +2 -2
  131. package/esm/middleware/validation.js.map +1 -1
  132. package/esm/plugins/define-plugin.js +2 -2
  133. package/esm/plugins/define-plugin.js.map +1 -1
  134. package/esm/plugins/plugin-manager.js +58 -27
  135. package/esm/plugins/plugin-manager.js.map +1 -1
  136. package/esm/utils/debounce-throttle.js +1 -1
  137. package/esm/utils/debounce-throttle.js.map +1 -1
  138. package/esm/utils/deep-clone.js +1 -1
  139. package/esm/utils/deep-clone.js.map +1 -1
  140. package/esm/utils/selector.js +1 -1
  141. package/esm/utils/selector.js.map +1 -1
  142. package/lib/core/async-action.cjs +83 -35
  143. package/lib/core/async-action.cjs.map +1 -1
  144. package/lib/core/async-action.d.cts +25 -0
  145. package/lib/core/base-store.cjs +174 -74
  146. package/lib/core/base-store.cjs.map +1 -1
  147. package/lib/core/base-store.d.cts +50 -0
  148. package/lib/core/batch-manager.cjs +15 -2
  149. package/lib/core/batch-manager.cjs.map +1 -1
  150. package/{esm/core/batch-manager.d.ts → lib/core/batch-manager.d.cts} +0 -1
  151. package/lib/core/create-store.cjs +3 -3
  152. package/lib/core/create-store.cjs.map +1 -1
  153. package/lib/core/{create-store.d.ts → create-store.d.cts} +3 -3
  154. package/lib/core/event-bus.cjs +1 -1
  155. package/lib/core/event-bus.cjs.map +1 -1
  156. package/lib/core/{event-bus.d.ts → event-bus.d.cts} +0 -1
  157. package/lib/core/index.cjs +2 -2
  158. package/{esm/core/index.d.ts → lib/core/index.d.cts} +1 -2
  159. package/lib/core/pub-sub.cjs +1 -1
  160. package/lib/core/pub-sub.cjs.map +1 -1
  161. package/lib/core/{pub-sub.d.ts → pub-sub.d.cts} +0 -1
  162. package/lib/engine/index.cjs +1 -1
  163. package/{esm/engine/index.d.ts → lib/engine/index.d.cts} +0 -1
  164. package/lib/engine/plugin.cjs +11 -2
  165. package/lib/engine/plugin.cjs.map +1 -1
  166. package/{esm/engine/plugin.d.ts → lib/engine/plugin.d.cts} +0 -1
  167. package/lib/engine/types.cjs +1 -1
  168. package/lib/engine/{types.d.ts → types.d.cts} +0 -1
  169. package/lib/errors/index.cjs +17 -1
  170. package/lib/errors/index.cjs.map +1 -1
  171. package/lib/errors/{index.d.ts → index.d.cts} +0 -1
  172. package/lib/index.cjs +8 -8
  173. package/lib/index.cjs.map +1 -1
  174. package/lib/{index.d.ts → index.d.cts} +3 -4
  175. package/lib/middleware/index.cjs +2 -2
  176. package/lib/middleware/{index.d.ts → index.d.cts} +3 -4
  177. package/lib/middleware/logger.cjs +2 -2
  178. package/lib/middleware/logger.cjs.map +1 -1
  179. package/lib/middleware/{logger.d.ts → logger.d.cts} +0 -1
  180. package/lib/middleware/middleware-manager.cjs +5 -2
  181. package/lib/middleware/middleware-manager.cjs.map +1 -1
  182. package/lib/middleware/{middleware-manager.d.ts → middleware-manager.d.cts} +0 -1
  183. package/lib/middleware/persist.cjs +3 -3
  184. package/lib/middleware/persist.cjs.map +1 -1
  185. package/{esm/middleware/persist.d.ts → lib/middleware/persist.d.cts} +0 -1
  186. package/lib/middleware/time-travel.cjs +1 -1
  187. package/lib/middleware/time-travel.cjs.map +1 -1
  188. package/{esm/middleware/time-travel.d.ts → lib/middleware/time-travel.d.cts} +0 -1
  189. package/lib/middleware/validation.cjs +2 -2
  190. package/lib/middleware/validation.cjs.map +1 -1
  191. package/{esm/middleware/validation.d.ts → lib/middleware/validation.d.cts} +0 -1
  192. package/lib/plugins/define-plugin.cjs +2 -2
  193. package/lib/plugins/define-plugin.cjs.map +1 -1
  194. package/{esm/plugins/define-plugin.d.ts → lib/plugins/define-plugin.d.cts} +1 -2
  195. package/lib/plugins/index.cjs +2 -2
  196. package/{esm/plugins/index.d.ts → lib/plugins/index.d.cts} +0 -1
  197. package/lib/plugins/plugin-manager.cjs +58 -27
  198. package/lib/plugins/plugin-manager.cjs.map +1 -1
  199. package/lib/plugins/plugin-manager.d.cts +5 -0
  200. package/lib/types/action.cjs +12 -0
  201. package/lib/types/action.d.cts +2 -0
  202. package/lib/types/batch.cjs +12 -0
  203. package/lib/types/batch.d.cts +2 -0
  204. package/lib/types/event.cjs +12 -0
  205. package/lib/types/event.d.cts +2 -0
  206. package/lib/types/index.cjs +1 -1
  207. package/{esm/types/index.d.ts → lib/types/index.d.cts} +2 -3
  208. package/lib/types/middleware.cjs +1 -1
  209. package/lib/types/{middleware.d.ts → middleware.d.cts} +10 -2
  210. package/lib/types/mutation.cjs +12 -0
  211. package/lib/types/mutation.d.cts +2 -0
  212. package/lib/types/plugin.cjs +1 -1
  213. package/lib/types/{plugin.d.ts → plugin.d.cts} +4 -1
  214. package/lib/types/state.cjs +12 -0
  215. package/lib/types/state.d.cts +2 -0
  216. package/lib/types/store.cjs +1 -1
  217. package/lib/types/{store.d.ts → store.d.cts} +19 -1
  218. package/lib/types/subscription.cjs +1 -1
  219. package/lib/types/{subscription.d.ts → subscription.d.cts} +7 -2
  220. package/lib/types/time-travel.cjs +12 -0
  221. package/lib/types/time-travel.d.cts +2 -0
  222. package/lib/types/utility.cjs +1 -1
  223. package/lib/types/{utility.d.ts → utility.d.cts} +3 -4
  224. package/lib/utils/debounce-throttle.cjs +1 -1
  225. package/lib/utils/debounce-throttle.cjs.map +1 -1
  226. package/{esm/utils/debounce-throttle.d.ts → lib/utils/debounce-throttle.d.cts} +0 -1
  227. package/lib/utils/deep-clone.cjs +1 -1
  228. package/lib/utils/deep-clone.cjs.map +1 -1
  229. package/lib/utils/{deep-clone.d.ts → deep-clone.d.cts} +0 -1
  230. package/lib/utils/index.cjs +1 -1
  231. package/lib/utils/{index.d.ts → index.d.cts} +4 -5
  232. package/lib/utils/selector.cjs +1 -1
  233. package/lib/utils/selector.cjs.map +1 -1
  234. package/lib/utils/{selector.d.ts → selector.d.cts} +0 -1
  235. package/package.json +14 -11
  236. package/es/core/async-action.d.ts.map +0 -1
  237. package/es/core/base-store.d.ts.map +0 -1
  238. package/es/core/batch-manager.d.ts.map +0 -1
  239. package/es/core/create-store.d.ts.map +0 -1
  240. package/es/core/event-bus.d.ts.map +0 -1
  241. package/es/core/index.d.ts.map +0 -1
  242. package/es/core/pub-sub.d.ts.map +0 -1
  243. package/es/engine/index.d.ts.map +0 -1
  244. package/es/engine/plugin.d.ts.map +0 -1
  245. package/es/engine/types.d.ts.map +0 -1
  246. package/es/errors/index.d.ts.map +0 -1
  247. package/es/index.d.ts.map +0 -1
  248. package/es/middleware/index.d.ts.map +0 -1
  249. package/es/middleware/logger.d.ts.map +0 -1
  250. package/es/middleware/middleware-manager.d.ts.map +0 -1
  251. package/es/middleware/persist.d.ts.map +0 -1
  252. package/es/middleware/time-travel.d.ts.map +0 -1
  253. package/es/middleware/validation.d.ts.map +0 -1
  254. package/es/plugins/define-plugin.d.ts.map +0 -1
  255. package/es/plugins/index.d.ts.map +0 -1
  256. package/es/plugins/plugin-manager.d.ts.map +0 -1
  257. package/es/types/index.d.ts.map +0 -1
  258. package/es/types/middleware.d.ts.map +0 -1
  259. package/es/types/plugin.d.ts.map +0 -1
  260. package/es/types/store.d.ts.map +0 -1
  261. package/es/types/subscription.d.ts.map +0 -1
  262. package/es/types/utility.d.ts.map +0 -1
  263. package/es/utils/debounce-throttle.d.ts.map +0 -1
  264. package/es/utils/deep-clone.d.ts.map +0 -1
  265. package/es/utils/index.d.ts.map +0 -1
  266. package/es/utils/selector.d.ts.map +0 -1
  267. package/esm/core/async-action.d.ts +0 -95
  268. package/esm/core/base-store.d.ts +0 -85
  269. package/esm/core/create-store.d.ts +0 -66
  270. package/esm/core/event-bus.d.ts +0 -34
  271. package/esm/core/pub-sub.d.ts +0 -41
  272. package/esm/engine/types.d.ts +0 -81
  273. package/esm/errors/index.d.ts +0 -208
  274. package/esm/index.d.ts +0 -27
  275. package/esm/middleware/index.d.ts +0 -13
  276. package/esm/middleware/logger.d.ts +0 -67
  277. package/esm/middleware/middleware-manager.d.ts +0 -40
  278. package/esm/plugins/plugin-manager.d.ts +0 -35
  279. package/esm/types/middleware.d.ts +0 -172
  280. package/esm/types/plugin.d.ts +0 -136
  281. package/esm/types/store.d.ts +0 -198
  282. package/esm/types/subscription.d.ts +0 -158
  283. package/esm/types/utility.d.ts +0 -312
  284. package/esm/utils/deep-clone.d.ts +0 -143
  285. package/esm/utils/index.d.ts +0 -13
  286. package/esm/utils/selector.d.ts +0 -213
  287. package/lib/core/async-action.d.ts +0 -95
  288. package/lib/core/base-store.d.ts +0 -85
  289. package/lib/core/batch-manager.d.ts +0 -46
  290. package/lib/core/index.d.ts +0 -14
  291. package/lib/engine/index.d.ts +0 -10
  292. package/lib/engine/plugin.d.ts +0 -20
  293. package/lib/middleware/persist.d.ts +0 -34
  294. package/lib/middleware/time-travel.d.ts +0 -30
  295. package/lib/middleware/validation.d.ts +0 -100
  296. package/lib/plugins/define-plugin.d.ts +0 -74
  297. package/lib/plugins/index.d.ts +0 -8
  298. package/lib/plugins/plugin-manager.d.ts +0 -35
  299. package/lib/types/index.d.ts +0 -12
  300. package/lib/utils/debounce-throttle.d.ts +0 -86
@@ -2,7 +2,7 @@
2
2
  * ***********************************
3
3
  * @composy/store-core v0.0.1 *
4
4
  * Built with rollup *
5
- * Build time: 2024-08-17 11:27:33 *
5
+ * Build time: 2024-10-12 17:23:58 *
6
6
  * Build mode: production *
7
7
  * Minified: No *
8
8
  * ***********************************
@@ -37,7 +37,10 @@ function createMiddlewareManager() {
37
37
  if (sorted.length === 0) return;
38
38
  const dispatch = async (index) => {
39
39
  const middleware = sorted[index];
40
- if (!middleware) return;
40
+ if (!middleware) {
41
+ context.meta?.commit?.();
42
+ return;
43
+ }
41
44
  let called = false;
42
45
  const next = async () => {
43
46
  if (called) throw new Error(`[Middleware] next() called multiple times in "${middleware.name}"`);
@@ -1 +1 @@
1
- {"version":3,"file":"middleware-manager.js","names":[],"sources":["../../src/middleware/middleware-manager.ts"],"sourcesContent":["/**\n * 中间件管理器\n *\n * @module middleware/middleware-manager\n */\n\nimport type { Middleware, MiddlewareContext, MiddlewareManager } from '../types'\n\n/**\n * 创建中间件管理器\n *\n * @returns 中间件管理器实例\n *\n * @example\n * ```typescript\n * const manager = createMiddlewareManager()\n *\n * // 添加日志中间件\n * manager.use({\n * name: 'logger',\n * priority: 1,\n * handler: async (ctx, next) => {\n * console.log('Before:', ctx.type)\n * await next()\n * console.log('After:', ctx.type)\n * }\n * })\n *\n * // 执行中间件链\n * await manager.execute({ storeId: 'test', state: {}, type: 'state:patch' })\n * ```\n */\nexport function createMiddlewareManager(): MiddlewareManager {\n /** 中间件列表 */\n const middlewares = new Map<string, Middleware>()\n\n /** 已排序的中间件列表缓存 */\n let sortedMiddlewares: Middleware[] | null = null\n\n /**\n * 获取排序后的中间件列表\n */\n const getSortedMiddlewares = (): Middleware[] => {\n if (sortedMiddlewares === null) {\n sortedMiddlewares = Array.from(middlewares.values()).sort(\n (a, b) => (a.priority ?? 100) - (b.priority ?? 100),\n )\n }\n return sortedMiddlewares\n }\n\n /**\n * 使中间件缓存失效\n */\n const invalidateCache = (): void => {\n sortedMiddlewares = null\n }\n\n /**\n * 添加中间件\n */\n const use = (middleware: Middleware): void => {\n if (middlewares.has(middleware.name)) {\n console.warn(`[Middleware] 中间件 \"${middleware.name}\" 已存在,将被覆盖`)\n }\n middlewares.set(middleware.name, middleware)\n invalidateCache()\n }\n\n /**\n * 移除中间件\n */\n const remove = (name: string): void => {\n if (middlewares.delete(name)) {\n invalidateCache()\n }\n }\n\n /**\n * 获取中间件\n */\n const get = (name: string): Middleware | undefined => {\n return middlewares.get(name)\n }\n\n /**\n * 是否存在中间件\n */\n const has = (name: string): boolean => {\n return middlewares.has(name)\n }\n\n /**\n * 执行中间件链\n */\n const execute = async (context: MiddlewareContext): Promise<void> => {\n const sorted = getSortedMiddlewares()\n\n if (sorted.length === 0) {\n return\n }\n\n const dispatch = async (index: number): Promise<void> => {\n const middleware = sorted[index]\n if (!middleware) {\n return\n }\n\n let called = false\n const next = async (): Promise<void> => {\n if (called) {\n throw new Error(`[Middleware] next() called multiple times in \"${middleware.name}\"`)\n }\n\n called = true\n await dispatch(index + 1)\n }\n\n await middleware.handler(context, next)\n }\n\n await dispatch(0)\n }\n\n /**\n * 获取所有中间件\n */\n const getAll = (): Middleware[] => {\n return getSortedMiddlewares()\n }\n\n /**\n * 清空所有中间件\n */\n const clear = (): void => {\n middlewares.clear()\n invalidateCache()\n }\n\n return {\n use,\n remove,\n get,\n has,\n execute,\n getAll,\n clear,\n }\n}\n\n/**\n * 全局中间件管理器\n */\nlet globalMiddlewareManager: MiddlewareManager | null = null\n\n/**\n * 获取全局中间件管理器\n */\nexport function getGlobalMiddlewareManager(): MiddlewareManager {\n if (!globalMiddlewareManager) {\n globalMiddlewareManager = createMiddlewareManager()\n }\n return globalMiddlewareManager\n}\n\n/**\n * 设置全局中间件管理器\n */\nexport function setGlobalMiddlewareManager(manager: MiddlewareManager): void {\n globalMiddlewareManager = manager\n}\n\n"],"mappings":";;;;;;;;;;AAgCO,SAAS,0BAA6C;CAE3D,MAAM,8BAAc,IAAI,IAAwB;CAGhD,IAAI,oBAAyC;CAK7C,MAAM,6BAA2C;EAC/C,IAAI,sBAAsB,MACxB,oBAAoB,MAAM,KAAK,YAAY,OAAO,CAAC,CAAA,CAAE,MAClD,GAAG,OAAO,EAAE,YAAY,QAAQ,EAAE,YAAY,IACjD;EAEF,OAAO;CACT;CAKA,MAAM,wBAA8B;EAClC,oBAAoB;CACtB;CAKA,MAAM,OAAO,eAAiC;EAC5C,IAAI,YAAY,IAAI,WAAW,IAAI,GACjC,QAAQ,KAAK,oCAAqB,WAAW,KAAI,mDAAY;EAE/D,YAAY,IAAI,WAAW,MAAM,UAAU;EAC3C,gBAAgB;CAClB;CAKA,MAAM,UAAU,SAAuB;EACrC,IAAI,YAAY,OAAO,IAAI,GACzB,gBAAgB;CAEpB;CAKA,MAAM,OAAO,SAAyC;EACpD,OAAO,YAAY,IAAI,IAAI;CAC7B;CAKA,MAAM,OAAO,SAA0B;EACrC,OAAO,YAAY,IAAI,IAAI;CAC7B;CAKA,MAAM,UAAU,OAAO,YAA8C;EACnE,MAAM,SAAS,qBAAqB;EAEpC,IAAI,OAAO,WAAW,GACpB;EAGF,MAAM,WAAW,OAAO,UAAiC;GACvD,MAAM,aAAa,OAAO;GAC1B,IAAI,CAAC,YACH;GAGF,IAAI,SAAS;GACb,MAAM,OAAO,YAA2B;IACtC,IAAI,QACF,MAAM,IAAI,MAAM,iDAAiD,WAAW,KAAI,EAAG;IAGrF,SAAS;IACT,MAAM,SAAS,QAAQ,CAAC;GAC1B;GAEA,MAAM,WAAW,QAAQ,SAAS,IAAI;EACxC;EAEA,MAAM,SAAS,CAAC;CAClB;CAKA,MAAM,eAA6B;EACjC,OAAO,qBAAqB;CAC9B;CAKA,MAAM,cAAoB;EACxB,YAAY,MAAM;EAClB,gBAAgB;CAClB;CAEA,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF;AAKA,IAAI,0BAAoD;AAKjD,SAAS,6BAAgD;CAC9D,IAAI,CAAC,yBACH,0BAA0B,wBAAwB;CAEpD,OAAO;AACT;AAKO,SAAS,2BAA2B,SAAkC;CAC3E,0BAA0B;AAC5B"}
1
+ {"version":3,"file":"middleware-manager.js","names":[],"sources":["../../src/middleware/middleware-manager.ts"],"sourcesContent":["/**\r\n * 中间件管理器\r\n *\r\n * @module middleware/middleware-manager\r\n */\r\n\r\nimport type { Middleware, MiddlewareContext, MiddlewareManager } from '../types'\r\n\r\n/**\r\n * 创建中间件管理器\r\n *\r\n * @returns 中间件管理器实例\r\n *\r\n * @example\r\n * ```typescript\r\n * const manager = createMiddlewareManager()\r\n *\r\n * // 添加日志中间件\r\n * manager.use({\r\n * name: 'logger',\r\n * priority: 1,\r\n * handler: async (ctx, next) => {\r\n * console.log('Before:', ctx.type)\r\n * await next()\r\n * console.log('After:', ctx.type)\r\n * }\r\n * })\r\n *\r\n * // 执行中间件链\r\n * await manager.execute({ storeId: 'test', state: {}, type: 'state:patch' })\r\n * ```\r\n */\r\nexport function createMiddlewareManager(): MiddlewareManager {\r\n /** 中间件列表 */\r\n const middlewares = new Map<string, Middleware>()\r\n\r\n /** 已排序的中间件列表缓存 */\r\n let sortedMiddlewares: Middleware[] | null = null\r\n\r\n /**\r\n * 获取排序后的中间件列表\r\n */\r\n const getSortedMiddlewares = (): Middleware[] => {\r\n if (sortedMiddlewares === null) {\r\n sortedMiddlewares = Array.from(middlewares.values()).sort(\r\n (a, b) => (a.priority ?? 100) - (b.priority ?? 100)\r\n )\r\n }\r\n return sortedMiddlewares\r\n }\r\n\r\n /**\r\n * 使中间件缓存失效\r\n */\r\n const invalidateCache = (): void => {\r\n sortedMiddlewares = null\r\n }\r\n\r\n /**\r\n * 添加中间件\r\n */\r\n const use = (middleware: Middleware): void => {\r\n if (middlewares.has(middleware.name)) {\r\n console.warn(`[Middleware] 中间件 \"${middleware.name}\" 已存在,将被覆盖`)\r\n }\r\n middlewares.set(middleware.name, middleware)\r\n invalidateCache()\r\n }\r\n\r\n /**\r\n * 移除中间件\r\n */\r\n const remove = (name: string): void => {\r\n if (middlewares.delete(name)) {\r\n invalidateCache()\r\n }\r\n }\r\n\r\n /**\r\n * 获取中间件\r\n */\r\n const get = (name: string): Middleware | undefined => {\r\n return middlewares.get(name)\r\n }\r\n\r\n /**\r\n * 是否存在中间件\r\n */\r\n const has = (name: string): boolean => {\r\n return middlewares.has(name)\r\n }\r\n\r\n /**\r\n * 执行中间件链\r\n */\r\n const execute = async (context: MiddlewareContext): Promise<void> => {\r\n const sorted = getSortedMiddlewares()\r\n\r\n if (sorted.length === 0) {\r\n return\r\n }\r\n\r\n const dispatch = async (index: number): Promise<void> => {\r\n const middleware = sorted[index]\r\n if (!middleware) {\r\n context.meta?.commit?.()\r\n return\r\n }\r\n\r\n let called = false\r\n const next = async (): Promise<void> => {\r\n if (called) {\r\n throw new Error(\r\n `[Middleware] next() called multiple times in \"${middleware.name}\"`\r\n )\r\n }\r\n\r\n called = true\r\n await dispatch(index + 1)\r\n }\r\n\r\n await middleware.handler(context, next)\r\n }\r\n\r\n await dispatch(0)\r\n }\r\n\r\n /**\r\n * 获取所有中间件\r\n */\r\n const getAll = (): Middleware[] => {\r\n return getSortedMiddlewares()\r\n }\r\n\r\n /**\r\n * 清空所有中间件\r\n */\r\n const clear = (): void => {\r\n middlewares.clear()\r\n invalidateCache()\r\n }\r\n\r\n return {\r\n use,\r\n remove,\r\n get,\r\n has,\r\n execute,\r\n getAll,\r\n clear,\r\n }\r\n}\r\n\r\n/**\r\n * 全局中间件管理器\r\n */\r\nlet globalMiddlewareManager: MiddlewareManager | null = null\r\n\r\n/**\r\n * 获取全局中间件管理器\r\n */\r\nexport function getGlobalMiddlewareManager(): MiddlewareManager {\r\n if (!globalMiddlewareManager) {\r\n globalMiddlewareManager = createMiddlewareManager()\r\n }\r\n return globalMiddlewareManager\r\n}\r\n\r\n/**\r\n * 设置全局中间件管理器\r\n */\r\nexport function setGlobalMiddlewareManager(manager: MiddlewareManager): void {\r\n globalMiddlewareManager = manager\r\n}\r\n"],"mappings":";;;;;;;;;;AAgCO,SAAS,0BAA6C;CAE3D,MAAM,8BAAc,IAAI,IAAwB;CAGhD,IAAI,oBAAyC;CAK7C,MAAM,6BAA2C;EAC/C,IAAI,sBAAsB,MACxB,oBAAoB,MAAM,KAAK,YAAY,OAAO,CAAC,CAAA,CAAE,MAClD,GAAG,OAAO,EAAE,YAAY,QAAQ,EAAE,YAAY,IACjD;EAEF,OAAO;CACT;CAKA,MAAM,wBAA8B;EAClC,oBAAoB;CACtB;CAKA,MAAM,OAAO,eAAiC;EAC5C,IAAI,YAAY,IAAI,WAAW,IAAI,GACjC,QAAQ,KAAK,oCAAqB,WAAW,KAAI,mDAAY;EAE/D,YAAY,IAAI,WAAW,MAAM,UAAU;EAC3C,gBAAgB;CAClB;CAKA,MAAM,UAAU,SAAuB;EACrC,IAAI,YAAY,OAAO,IAAI,GACzB,gBAAgB;CAEpB;CAKA,MAAM,OAAO,SAAyC;EACpD,OAAO,YAAY,IAAI,IAAI;CAC7B;CAKA,MAAM,OAAO,SAA0B;EACrC,OAAO,YAAY,IAAI,IAAI;CAC7B;CAKA,MAAM,UAAU,OAAO,YAA8C;EACnE,MAAM,SAAS,qBAAqB;EAEpC,IAAI,OAAO,WAAW,GACpB;EAGF,MAAM,WAAW,OAAO,UAAiC;GACvD,MAAM,aAAa,OAAO;GAC1B,IAAI,CAAC,YAAY;IACf,QAAQ,MAAM,SAAS;IACvB;GACF;GAEA,IAAI,SAAS;GACb,MAAM,OAAO,YAA2B;IACtC,IAAI,QACF,MAAM,IAAI,MACR,iDAAiD,WAAW,KAAI,EAClE;IAGF,SAAS;IACT,MAAM,SAAS,QAAQ,CAAC;GAC1B;GAEA,MAAM,WAAW,QAAQ,SAAS,IAAI;EACxC;EAEA,MAAM,SAAS,CAAC;CAClB;CAKA,MAAM,eAA6B;EACjC,OAAO,qBAAqB;CAC9B;CAKA,MAAM,cAAoB;EACxB,YAAY,MAAM;EAClB,gBAAgB;CAClB;CAEA,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF;AAKA,IAAI,0BAAoD;AAKjD,SAAS,6BAAgD;CAC9D,IAAI,CAAC,yBACH,0BAA0B,wBAAwB;CAEpD,OAAO;AACT;AAKO,SAAS,2BAA2B,SAAkC;CAC3E,0BAA0B;AAC5B"}
@@ -2,7 +2,7 @@
2
2
  * ***********************************
3
3
  * @composy/store-core v0.0.1 *
4
4
  * Built with rollup *
5
- * Build time: 2024-08-17 11:27:33 *
5
+ * Build time: 2024-10-12 17:23:58 *
6
6
  * Build mode: production *
7
7
  * Minified: No *
8
8
  * ***********************************
@@ -13,8 +13,8 @@ const defaultOptions = {
13
13
  keyPrefix: "ldesign-store:",
14
14
  storage: "localStorage",
15
15
  debounce: 100,
16
- serialize: JSON.stringify,
17
- deserialize: JSON.parse
16
+ serialize: (value) => JSON.stringify(value),
17
+ deserialize: (value) => JSON.parse(value)
18
18
  };
19
19
  function resolveOptions(options) {
20
20
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"persist.js","names":[],"sources":["../../src/middleware/persist.ts"],"sourcesContent":["/**\n * 持久化中间件\n *\n * 提供状态持久化功能\n * @module middleware/persist\n */\n\nimport type { Middleware, MiddlewareContext, PersistMiddlewareOptions, StateTree, StoreId } from '../types'\nimport { debounce } from '../utils/debounce-throttle'\n\ntype ResolvedPersistMiddlewareOptions = Required<\n Pick<PersistMiddlewareOptions, 'debounce' | 'deserialize' | 'keyPrefix' | 'serialize' | 'storage'>\n> & Omit<PersistMiddlewareOptions, 'debounce' | 'deserialize' | 'keyPrefix' | 'serialize' | 'storage'>\n\n/**\n * 默认持久化选项\n */\nconst defaultOptions: ResolvedPersistMiddlewareOptions = {\n keyPrefix: 'ldesign-store:',\n storage: 'localStorage',\n debounce: 100,\n serialize: JSON.stringify,\n deserialize: JSON.parse,\n}\n\nfunction resolveOptions(options: PersistMiddlewareOptions): ResolvedPersistMiddlewareOptions {\n return { ...defaultOptions, ...options }\n}\n\n/**\n * 获取存储对象\n */\nfunction getStorage(type: 'localStorage' | 'sessionStorage'): Storage | null {\n if (typeof window === 'undefined') {\n return null\n }\n return type === 'localStorage' ? localStorage : sessionStorage\n}\n\n/**\n * 创建持久化中间件\n *\n * @param options - 持久化选项\n * @returns 持久化中间件\n *\n * @example\n * ```typescript\n * const persist = createPersistMiddleware({\n * storage: 'localStorage',\n * stores: ['user', 'settings'],\n * debounce: 200,\n * })\n *\n * middlewareManager.use(persist)\n * ```\n */\nexport function createPersistMiddleware(\n options: PersistMiddlewareOptions = {},\n): Middleware {\n const opts = resolveOptions(options)\n const storage = getStorage(opts.storage)\n\n /** 保存状态的防抖函数映射 */\n const debouncedSave = new Map<StoreId, (state: StateTree) => void>()\n\n /**\n * 获取存储键名\n */\n const getKey = (storeId: StoreId): string => {\n return `${opts.keyPrefix}${storeId}`\n }\n\n /**\n * 筛选需要持久化的状态路径\n */\n const filterState = (storeId: StoreId, state: StateTree): StateTree => {\n const paths = opts.paths?.[storeId]\n if (!paths || paths.length === 0) {\n return state\n }\n\n const filtered: StateTree = {}\n for (const path of paths) {\n const keys = path.split('.')\n let source: unknown = state\n let target: StateTree = filtered\n\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i]\n if (i === keys.length - 1) {\n target[key] = (source as StateTree)?.[key]\n }\n else {\n target[key] = target[key] || {}\n target = target[key] as StateTree\n source = (source as StateTree)?.[key]\n }\n }\n }\n\n return filtered\n }\n\n /**\n * 保存状态到存储\n */\n const saveState = (storeId: StoreId, state: StateTree): void => {\n if (!storage) return\n\n try {\n const filteredState = filterState(storeId, state)\n const serialized = opts.serialize(filteredState)\n storage.setItem(getKey(storeId), serialized)\n }\n catch (error) {\n console.error(`[Persist] 保存状态失败 (${storeId}):`, error)\n }\n }\n\n /**\n * 获取或创建防抖保存函数\n */\n const getDebouncedSave = (storeId: StoreId): (state: StateTree) => void => {\n let fn = debouncedSave.get(storeId)\n if (!fn) {\n fn = debounce((state: StateTree) => saveState(storeId, state), opts.debounce)\n debouncedSave.set(storeId, fn)\n }\n return fn\n }\n\n return {\n name: 'persist',\n priority: 100, // 最后执行\n\n handler: async (context: MiddlewareContext, next: () => void | Promise<void>) => {\n await next()\n\n const { storeId, type, state } = context\n\n // 只在状态变化时持久化\n if (!type.startsWith('state:')) {\n return\n }\n\n // 检查是否需要持久化此 Store\n if (opts.stores && !opts.stores.includes(storeId)) {\n return\n }\n\n // 使用防抖保存\n getDebouncedSave(storeId)(state)\n },\n }\n}\n\n/**\n * 从存储恢复状态\n *\n * @param storeId - Store ID\n * @param options - 持久化选项\n * @returns 恢复的状态或 null\n */\nexport function restoreState<S extends StateTree>(\n storeId: StoreId,\n options: PersistMiddlewareOptions = {},\n): S | null {\n const opts = resolveOptions(options)\n const storage = getStorage(opts.storage)\n\n if (!storage) return null\n\n try {\n const key = `${opts.keyPrefix}${storeId}`\n const data = storage.getItem(key)\n if (data) {\n return opts.deserialize(data) as S\n }\n }\n catch (error) {\n console.error(`[Persist] 恢复状态失败 (${storeId}):`, error)\n }\n\n return null\n}\n\n"],"mappings":";;;;;;;;;;;AAiBA,MAAM,iBAAmD;CACvD,WAAW;CACX,SAAS;CACT,UAAU;CACV,WAAW,KAAK;CAChB,aAAa,KAAK;AACpB;AAEA,SAAS,eAAe,SAAqE;CAC3F,OAAO;EAAE,GAAG;EAAgB,GAAG;CAAQ;AACzC;AAKA,SAAS,WAAW,MAAyD;CAC3E,IAAI,OAAO,WAAW,aACpB,OAAO;CAET,OAAO,SAAS,iBAAiB,eAAe;AAClD;AAmBO,SAAS,wBACd,UAAoC,CAAC,GACzB;CACZ,MAAM,OAAO,eAAe,OAAO;CACnC,MAAM,UAAU,WAAW,KAAK,OAAO;CAGvC,MAAM,gCAAgB,IAAI,IAAyC;CAKnE,MAAM,UAAU,YAA6B;EAC3C,OAAO,GAAG,KAAK,YAAY;CAC7B;CAKA,MAAM,eAAe,SAAkB,UAAgC;EACrE,MAAM,QAAQ,KAAK,QAAQ;EAC3B,IAAI,CAAC,SAAS,MAAM,WAAW,GAC7B,OAAO;EAGT,MAAM,WAAsB,CAAC;EAC7B,KAAA,MAAW,QAAQ,OAAO;GACxB,MAAM,OAAO,KAAK,MAAM,GAAG;GAC3B,IAAI,SAAkB;GACtB,IAAI,SAAoB;GAExB,KAAA,IAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;IACpC,MAAM,MAAM,KAAK;IACjB,IAAI,MAAM,KAAK,SAAS,GACtB,OAAO,OAAQ,SAAuB;SAEnC;KACH,OAAO,OAAO,OAAO,QAAQ,CAAC;KAC9B,SAAS,OAAO;KAChB,SAAU,SAAuB;IACnC;GACF;EACF;EAEA,OAAO;CACT;CAKA,MAAM,aAAa,SAAkB,UAA2B;EAC9D,IAAI,CAAC,SAAS;EAEd,IAAI;GACF,MAAM,gBAAgB,YAAY,SAAS,KAAK;GAChD,MAAM,aAAa,KAAK,UAAU,aAAa;GAC/C,QAAQ,QAAQ,OAAO,OAAO,GAAG,UAAU;EAC7C,SACO,OAAO;GACZ,QAAQ,MAAM,mDAAqB,QAAO,KAAM,KAAK;EACvD;CACF;CAKA,MAAM,oBAAoB,YAAiD;EACzE,IAAI,KAAK,cAAc,IAAI,OAAO;EAClC,IAAI,CAAC,IAAI;GACP,KAAK,UAAU,UAAqB,UAAU,SAAS,KAAK,GAAG,KAAK,QAAQ;GAC5E,cAAc,IAAI,SAAS,EAAE;EAC/B;EACA,OAAO;CACT;CAEA,OAAO;EACL,MAAM;EACN,UAAU;EAEV,SAAS,OAAO,SAA4B,SAAqC;GAC/E,MAAM,KAAK;GAEX,MAAM,EAAE,SAAS,MAAM,UAAU;GAGjC,IAAI,CAAC,KAAK,WAAW,QAAQ,GAC3B;GAIF,IAAI,KAAK,UAAU,CAAC,KAAK,OAAO,SAAS,OAAO,GAC9C;GAIF,iBAAiB,OAAO,CAAA,CAAE,KAAK;EACjC;CACF;AACF;AASO,SAAS,aACd,SACA,UAAoC,CAAC,GAC3B;CACV,MAAM,OAAO,eAAe,OAAO;CACnC,MAAM,UAAU,WAAW,KAAK,OAAO;CAEvC,IAAI,CAAC,SAAS,OAAO;CAErB,IAAI;EACF,MAAM,MAAM,GAAG,KAAK,YAAY;EAChC,MAAM,OAAO,QAAQ,QAAQ,GAAG;EAChC,IAAI,MACF,OAAO,KAAK,YAAY,IAAI;CAEhC,SACO,OAAO;EACZ,QAAQ,MAAM,mDAAqB,QAAO,KAAM,KAAK;CACvD;CAEA,OAAO;AACT"}
1
+ {"version":3,"file":"persist.js","names":[],"sources":["../../src/middleware/persist.ts"],"sourcesContent":["/**\r\n * 持久化中间件\r\n *\r\n * 提供状态持久化功能\r\n * @module middleware/persist\r\n */\r\n\r\nimport type {\r\n Middleware,\r\n MiddlewareContext,\r\n PersistMiddlewareOptions,\r\n StateTree,\r\n StoreId,\r\n} from '../types'\r\nimport { debounce } from '../utils/debounce-throttle'\r\n\r\ntype ResolvedPersistMiddlewareOptions = Required<\r\n Pick<\r\n PersistMiddlewareOptions,\r\n 'debounce' | 'deserialize' | 'keyPrefix' | 'serialize' | 'storage'\r\n >\r\n> &\r\n Omit<\r\n PersistMiddlewareOptions,\r\n 'debounce' | 'deserialize' | 'keyPrefix' | 'serialize' | 'storage'\r\n >\r\n\r\n/**\r\n * 默认持久化选项\r\n */\r\nconst defaultOptions: ResolvedPersistMiddlewareOptions = {\r\n keyPrefix: 'ldesign-store:',\r\n storage: 'localStorage',\r\n debounce: 100,\r\n serialize: (value: unknown) => JSON.stringify(value),\r\n deserialize: (value: string) => JSON.parse(value) as unknown,\r\n}\r\n\r\nfunction resolveOptions(\r\n options: PersistMiddlewareOptions\r\n): ResolvedPersistMiddlewareOptions {\r\n return { ...defaultOptions, ...options }\r\n}\r\n\r\n/**\r\n * 获取存储对象\r\n */\r\nfunction getStorage(type: 'localStorage' | 'sessionStorage'): Storage | null {\r\n if (typeof window === 'undefined') {\r\n return null\r\n }\r\n return type === 'localStorage' ? localStorage : sessionStorage\r\n}\r\n\r\n/**\r\n * 创建持久化中间件\r\n *\r\n * @param options - 持久化选项\r\n * @returns 持久化中间件\r\n *\r\n * @example\r\n * ```typescript\r\n * const persist = createPersistMiddleware({\r\n * storage: 'localStorage',\r\n * stores: ['user', 'settings'],\r\n * debounce: 200,\r\n * })\r\n *\r\n * middlewareManager.use(persist)\r\n * ```\r\n */\r\nexport function createPersistMiddleware(\r\n options: PersistMiddlewareOptions = {}\r\n): Middleware {\r\n const opts = resolveOptions(options)\r\n const storage = getStorage(opts.storage)\r\n\r\n /** 保存状态的防抖函数映射 */\r\n const debouncedSave = new Map<StoreId, (state: StateTree) => void>()\r\n\r\n /**\r\n * 获取存储键名\r\n */\r\n const getKey = (storeId: StoreId): string => {\r\n return `${opts.keyPrefix}${storeId}`\r\n }\r\n\r\n /**\r\n * 筛选需要持久化的状态路径\r\n */\r\n const filterState = (storeId: StoreId, state: StateTree): StateTree => {\r\n const paths = opts.paths?.[storeId]\r\n if (!paths || paths.length === 0) {\r\n return state\r\n }\r\n\r\n const filtered: StateTree = {}\r\n for (const path of paths) {\r\n const keys = path.split('.')\r\n let source: unknown = state\r\n let target: StateTree = filtered\r\n\r\n for (let i = 0; i < keys.length; i++) {\r\n const key = keys[i]\r\n if (i === keys.length - 1) {\r\n target[key] = (source as StateTree)?.[key]\r\n } else {\r\n target[key] = target[key] || {}\r\n target = target[key] as StateTree\r\n source = (source as StateTree)?.[key]\r\n }\r\n }\r\n }\r\n\r\n return filtered\r\n }\r\n\r\n /**\r\n * 保存状态到存储\r\n */\r\n const saveState = (storeId: StoreId, state: StateTree): void => {\r\n if (!storage) return\r\n\r\n try {\r\n const filteredState = filterState(storeId, state)\r\n const serialized = opts.serialize(filteredState)\r\n storage.setItem(getKey(storeId), serialized)\r\n } catch (error) {\r\n console.error(`[Persist] 保存状态失败 (${storeId}):`, error)\r\n }\r\n }\r\n\r\n /**\r\n * 获取或创建防抖保存函数\r\n */\r\n const getDebouncedSave = (storeId: StoreId): ((state: StateTree) => void) => {\r\n let fn = debouncedSave.get(storeId)\r\n if (!fn) {\r\n fn = debounce(\r\n (state: StateTree) => saveState(storeId, state),\r\n opts.debounce\r\n )\r\n debouncedSave.set(storeId, fn)\r\n }\r\n return fn\r\n }\r\n\r\n return {\r\n name: 'persist',\r\n priority: 100, // 最后执行\r\n\r\n handler: async (\r\n context: MiddlewareContext,\r\n next: () => void | Promise<void>\r\n ) => {\r\n await next()\r\n\r\n const { storeId, type, state } = context\r\n\r\n // 只在状态变化时持久化\r\n if (!type.startsWith('state:')) {\r\n return\r\n }\r\n\r\n // 检查是否需要持久化此 Store\r\n if (opts.stores && !opts.stores.includes(storeId)) {\r\n return\r\n }\r\n\r\n // 使用防抖保存\r\n getDebouncedSave(storeId)(state)\r\n },\r\n }\r\n}\r\n\r\n/**\r\n * 从存储恢复状态\r\n *\r\n * @param storeId - Store ID\r\n * @param options - 持久化选项\r\n * @returns 恢复的状态或 null\r\n */\r\nexport function restoreState<S extends StateTree>(\r\n storeId: StoreId,\r\n options: PersistMiddlewareOptions = {}\r\n): S | null {\r\n const opts = resolveOptions(options)\r\n const storage = getStorage(opts.storage)\r\n\r\n if (!storage) return null\r\n\r\n try {\r\n const key = `${opts.keyPrefix}${storeId}`\r\n const data = storage.getItem(key)\r\n if (data) {\r\n return opts.deserialize(data) as S\r\n }\r\n } catch (error) {\r\n console.error(`[Persist] 恢复状态失败 (${storeId}):`, error)\r\n }\r\n\r\n return null\r\n}\r\n"],"mappings":";;;;;;;;;;;AA8BA,MAAM,iBAAmD;CACvD,WAAW;CACX,SAAS;CACT,UAAU;CACV,YAAY,UAAmB,KAAK,UAAU,KAAK;CACnD,cAAc,UAAkB,KAAK,MAAM,KAAK;AAClD;AAEA,SAAS,eACP,SACkC;CAClC,OAAO;EAAE,GAAG;EAAgB,GAAG;CAAQ;AACzC;AAKA,SAAS,WAAW,MAAyD;CAC3E,IAAI,OAAO,WAAW,aACpB,OAAO;CAET,OAAO,SAAS,iBAAiB,eAAe;AAClD;AAmBO,SAAS,wBACd,UAAoC,CAAC,GACzB;CACZ,MAAM,OAAO,eAAe,OAAO;CACnC,MAAM,UAAU,WAAW,KAAK,OAAO;CAGvC,MAAM,gCAAgB,IAAI,IAAyC;CAKnE,MAAM,UAAU,YAA6B;EAC3C,OAAO,GAAG,KAAK,YAAY;CAC7B;CAKA,MAAM,eAAe,SAAkB,UAAgC;EACrE,MAAM,QAAQ,KAAK,QAAQ;EAC3B,IAAI,CAAC,SAAS,MAAM,WAAW,GAC7B,OAAO;EAGT,MAAM,WAAsB,CAAC;EAC7B,KAAA,MAAW,QAAQ,OAAO;GACxB,MAAM,OAAO,KAAK,MAAM,GAAG;GAC3B,IAAI,SAAkB;GACtB,IAAI,SAAoB;GAExB,KAAA,IAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;IACpC,MAAM,MAAM,KAAK;IACjB,IAAI,MAAM,KAAK,SAAS,GACtB,OAAO,OAAQ,SAAuB;SACjC;KACL,OAAO,OAAO,OAAO,QAAQ,CAAC;KAC9B,SAAS,OAAO;KAChB,SAAU,SAAuB;IACnC;GACF;EACF;EAEA,OAAO;CACT;CAKA,MAAM,aAAa,SAAkB,UAA2B;EAC9D,IAAI,CAAC,SAAS;EAEd,IAAI;GACF,MAAM,gBAAgB,YAAY,SAAS,KAAK;GAChD,MAAM,aAAa,KAAK,UAAU,aAAa;GAC/C,QAAQ,QAAQ,OAAO,OAAO,GAAG,UAAU;EAC7C,SAAS,OAAO;GACd,QAAQ,MAAM,mDAAqB,QAAO,KAAM,KAAK;EACvD;CACF;CAKA,MAAM,oBAAoB,YAAmD;EAC3E,IAAI,KAAK,cAAc,IAAI,OAAO;EAClC,IAAI,CAAC,IAAI;GACP,KAAK,UACF,UAAqB,UAAU,SAAS,KAAK,GAC9C,KAAK,QACP;GACA,cAAc,IAAI,SAAS,EAAE;EAC/B;EACA,OAAO;CACT;CAEA,OAAO;EACL,MAAM;EACN,UAAU;EAEV,SAAS,OACP,SACA,SACG;GACH,MAAM,KAAK;GAEX,MAAM,EAAE,SAAS,MAAM,UAAU;GAGjC,IAAI,CAAC,KAAK,WAAW,QAAQ,GAC3B;GAIF,IAAI,KAAK,UAAU,CAAC,KAAK,OAAO,SAAS,OAAO,GAC9C;GAIF,iBAAiB,OAAO,CAAA,CAAE,KAAK;EACjC;CACF;AACF;AASO,SAAS,aACd,SACA,UAAoC,CAAC,GAC3B;CACV,MAAM,OAAO,eAAe,OAAO;CACnC,MAAM,UAAU,WAAW,KAAK,OAAO;CAEvC,IAAI,CAAC,SAAS,OAAO;CAErB,IAAI;EACF,MAAM,MAAM,GAAG,KAAK,YAAY;EAChC,MAAM,OAAO,QAAQ,QAAQ,GAAG;EAChC,IAAI,MACF,OAAO,KAAK,YAAY,IAAI;CAEhC,SAAS,OAAO;EACd,QAAQ,MAAM,mDAAqB,QAAO,KAAM,KAAK;CACvD;CAEA,OAAO;AACT"}
@@ -2,7 +2,7 @@
2
2
  * ***********************************
3
3
  * @composy/store-core v0.0.1 *
4
4
  * Built with rollup *
5
- * Build time: 2024-08-17 11:27:33 *
5
+ * Build time: 2024-10-12 17:23:58 *
6
6
  * Build mode: production *
7
7
  * Minified: No *
8
8
  * ***********************************
@@ -1 +1 @@
1
- {"version":3,"file":"time-travel.js","names":[],"sources":["../../src/middleware/time-travel.ts"],"sourcesContent":["/* ============================================================\n * time-travel.ts\n * 时间旅行中间件\n * 提供状态快照历史记录、撤销(undo)、重做(redo)、跳转(goto)等能力\n * 用于实现 Store 状态的可回溯调试与操作历史管理\n * ============================================================ */\n\n/* 从类型文件导入中间件、上下文、快照、状态树等核心类型 */\nimport type {\n Middleware, // 中间件接口\n MiddlewareContext, // 中间件执行上下文接口\n StateSnapshot, // 状态快照接口\n StateTree, // 状态树类型\n StoreId, // Store 标识类型\n TimeTravelController, // 时间旅行控制器接口\n TimeTravelMiddlewareOptions, // 时间旅行中间件配置选项接口\n} from '../types'\n/* 从工具库导入深拷贝函数,用于快照的隔离存储 */\nimport { deepClone } from '../utils/deep-clone'\n\n/* ── 内部类型定义 ── */\n\n/**\n * 恢复回调函数类型\n * 当执行 undo/redo/goto 操作时,通过此回调将历史快照状态应用到对应 Store\n * @param storeId - 目标 Store 的标识\n * @param state - 要恢复的状态树(已深拷贝,可安全修改)\n */\ntype RestoreCallback = (storeId: StoreId, state: StateTree) => void\n\n/**\n * 带有内部恢复回调设置器的控制器扩展类型\n * 在 TimeTravelController 基础上增加 __setRestoreCallback 内部方法\n * 用于在创建后注入实际的恢复回调(由 Store 运行时提供)\n */\ntype TimeTravelControllerWithRestoreSetter = TimeTravelController & {\n __setRestoreCallback?: (callback: RestoreCallback) => void\n}\n\n/* ── 默认配置 ── */\n\n/** 中间件默认选项:最多保留 100 条历史记录,功能默认启用 */\nconst defaultOptions: TimeTravelMiddlewareOptions = {\n maxHistory: 100,\n enabled: true,\n}\n\n/**\n * 创建时间旅行中间件\n *\n * 返回一个中间件函数和一个控制器对象:\n * - 中间件负责拦截 state: 类型的操作,在操作前后记录状态快照\n * - 控制器提供 undo/redo/goto/clear 等方法,用于在历史快照之间跳转\n *\n * @param options - 中间件配置选项(可选,与默认值合并)\n * @returns 包含 middleware(中间件)和 controller(控制器)的对象\n */\nexport function createTimeTravelMiddleware(\n options: TimeTravelMiddlewareOptions = {},\n): {\n middleware: Middleware\n controller: TimeTravelController\n} {\n /* 将用户选项与默认选项合并 */\n const opts = { ...defaultOptions, ...options }\n /* 最大历史记录条数,确保至少为 1 */\n const maxHistory = opts.maxHistory ?? defaultOptions.maxHistory ?? 100\n /* 历史快照数组,存储所有状态变更的快照 */\n const history: StateSnapshot[] = []\n\n /* 当前快照指针,指向 history 数组中的当前位置,-1 表示无快照 */\n let currentIndex = -1\n /* 标记是否正在进行时间旅行(undo/redo/goto),防止在恢复过程中重复记录快照 */\n let isTraveling = false\n /* 恢复回调函数,初始为空函数,后续通过 __setRestoreCallback 注入实际实现 */\n let restoreCallback: RestoreCallback = () => {}\n\n /**\n * 添加新的状态快照到历史记录\n * 业务处理过程:\n * 1. 如果中间件未启用或正在时间旅行中,则跳过\n * 2. 如果当前指针不在末尾(即之前执行过 undo),则丢弃指针之后的快照(分支覆盖)\n * 3. 推入新快照并更新指针\n * 4. 如果超过最大历史条数,移除最早的快照并调整指针\n *\n * @param snapshot - 要添加的状态快照\n */\n const addSnapshot = (snapshot: StateSnapshot): void => {\n /* 中间件未启用或正在时间旅行中,不记录快照 */\n if (!opts.enabled || isTraveling) {\n return\n }\n\n /* 如果当前指针不在历史末尾(之前执行过 undo),丢弃后续快照(创建新分支) */\n if (currentIndex < history.length - 1) {\n history.splice(currentIndex + 1)\n }\n\n /* 将新快照推入历史数组 */\n history.push(snapshot)\n /* 更新指针到最新快照 */\n currentIndex = history.length - 1\n\n /* 如果历史记录超过上限,移除最早的快照 */\n if (history.length > maxHistory) {\n history.shift()\n /* 移除头部元素后指针需要前移一位 */\n currentIndex--\n }\n }\n\n /**\n * 时间旅行控制器\n * 提供 undo(撤销)、redo(重做)、goto(跳转)、clear(清除)等操作\n * 所有恢复操作都通过 restoreCallback 将历史快照应用到 Store\n */\n const controller: TimeTravelControllerWithRestoreSetter = {\n /**\n * 撤销操作\n * 将当前指针前移一步,恢复到上一个历史快照状态\n */\n undo: () => {\n /* 无法撤销(已到最早快照)则跳过 */\n if (!controller.canUndo()) {\n return\n }\n\n /* 标记进入时间旅行模式,防止恢复过程触发新的快照记录 */\n isTraveling = true\n /* 指针前移 */\n currentIndex--\n /* 获取目标快照 */\n const snapshot = history[currentIndex]\n /* 通过恢复回调将快照状态(深拷贝)应用到 Store,避免污染历史记录 */\n restoreCallback(snapshot.storeId, deepClone(snapshot.state))\n /* 退出时间旅行模式 */\n isTraveling = false\n },\n\n /**\n * 重做操作\n * 将当前指针后移一步,恢复到下一个历史快照状态\n */\n redo: () => {\n /* 无法重做(已到最新快照)则跳过 */\n if (!controller.canRedo()) {\n return\n }\n\n /* 标记进入时间旅行模式 */\n isTraveling = true\n /* 指针后移 */\n currentIndex++\n /* 获取目标快照 */\n const snapshot = history[currentIndex]\n /* 恢复快照状态(深拷贝) */\n restoreCallback(snapshot.storeId, deepClone(snapshot.state))\n /* 退出时间旅行模式 */\n isTraveling = false\n },\n\n /**\n * 跳转到指定历史索引\n * 将当前指针直接移动到指定位置,恢复对应的快照状态\n *\n * @param index - 目标历史索引(0-based)\n */\n goto: (index: number) => {\n /* 索引越界检查 */\n if (index < 0 || index >= history.length) {\n return\n }\n\n /* 标记进入时间旅行模式 */\n isTraveling = true\n /* 直接设置指针到目标索引 */\n currentIndex = index\n /* 获取目标快照 */\n const snapshot = history[currentIndex]\n /* 恢复快照状态(深拷贝) */\n restoreCallback(snapshot.storeId, deepClone(snapshot.state))\n /* 退出时间旅行模式 */\n isTraveling = false\n },\n\n /**\n * 获取完整的快照历史(返回深拷贝,防止外部修改内部历史记录)\n * @returns 历史快照数组的深拷贝\n */\n getHistory: () => deepClone(history),\n\n /**\n * 获取当前快照指针索引\n * @returns 当前索引值,-1 表示无快照\n */\n getCurrentIndex: () => currentIndex,\n\n /**\n * 判断是否可以撤销\n * 当前索引大于 0 时,说明前面还有历史快照\n * @returns 是否可以执行 undo 操作\n */\n canUndo: () => currentIndex > 0,\n\n /**\n * 判断是否可以重做\n * 当前索引小于历史长度 - 1 时,说明后面还有快照\n * @returns 是否可以执行 redo 操作\n */\n canRedo: () => currentIndex < history.length - 1,\n\n /**\n * 清除所有历史快照并重置指针\n * 通常在 Store 销毁或需要重置历史时调用\n */\n clear: () => {\n /* 清空历史数组 */\n history.length = 0\n /* 重置指针到初始状态 */\n currentIndex = -1\n },\n }\n\n /**\n * 在控制器上挂载内部恢复回调设置器\n * 允许 Store 运行时在初始化时注入实际的状态恢复逻辑\n * 使用 __ 前缀表示这是内部方法,不建议外部直接调用\n */\n controller.__setRestoreCallback = (callback: RestoreCallback) => {\n restoreCallback = callback\n }\n\n /**\n * 时间旅行中间件\n * 拦截所有 \"state:\" 前缀的操作(如 state:update),在操作执行前后\n * 记录状态快照,从而构建可回溯的状态历史\n */\n const middleware: Middleware = {\n /* 中间件名称,用于调试和日志 */\n name: 'time-travel',\n /* 中间件优先级,50 为中等优先级(数值越小越先执行) */\n priority: 50,\n /**\n * 中间件处理函数\n * 只拦截 \"state:\" 类型的操作(状态变更操作),其他类型直接放行\n * 正在时间旅行时也不记录快照,避免循环\n *\n * @param context - 中间件上下文,包含 storeId、操作类型、状态等信息\n * @param next - 调用下一个中间件或最终操作的函数\n */\n handler: async (context: MiddlewareContext, next: () => void | Promise<void>) => {\n /* 解构上下文:Store 标识、操作类型、当前状态 */\n const { storeId, type, state } = context\n\n /* 非状态变更操作(不以 \"state:\" 开头)或正在时间旅行中,直接执行后续操作 */\n if (!type.startsWith('state:') || isTraveling) {\n await next()\n return\n }\n\n /* 在执行操作前,创建当前状态的快照(before snapshot) */\n const snapshot: StateSnapshot = {\n timestamp: Date.now(), /* 快照时间戳 */\n state: deepClone(state), /* 深拷贝当前状态,隔离引用 */\n type, /* 操作类型 */\n storeId, /* Store 标识 */\n }\n\n /* 执行后续中间件或最终操作 */\n await next()\n\n /* 操作执行完成后,将快照添加到历史记录 */\n addSnapshot(snapshot)\n },\n }\n\n /* 返回中间件和控制器 */\n return {\n middleware,\n controller,\n }\n}\n\n/**\n * 外部设置恢复回调的辅助函数\n * 将外部提供的状态恢复函数注入到时间旅行控制器中\n *\n * 使用场景:Store 运行时初始化时调用此函数,将控制器与 Store 的状态恢复逻辑连接\n *\n * @param controller - 时间旅行控制器实例\n * @param callback - 恢复回调函数,接收 storeId 和已深拷贝的状态树\n */\nexport function setRestoreCallback(\n controller: TimeTravelController,\n callback: (storeId: StoreId, state: StateTree) => void,\n): void {\n /* 将通用控制器类型断言为带内部设置器的扩展类型 */\n const controllerWithSetter = controller as TimeTravelControllerWithRestoreSetter\n /* 检查控制器是否支持 __setRestoreCallback 方法 */\n if (typeof controllerWithSetter.__setRestoreCallback === 'function') {\n /* 注入恢复回调 */\n controllerWithSetter.__setRestoreCallback(callback)\n return\n }\n\n /* 如果控制器不支持,输出警告(说明传入的不是 createTimeTravelMiddleware 创建的控制器) */\n console.warn('[TimeTravel] 请使用 createTimeTravelMiddleware 返回的 controller')\n}\n"],"mappings":";;;;;;;;;;;AA0CA,MAAM,iBAA8C;CAClD,YAAY;CACZ,SAAS;AACX;AAYO,SAAS,2BACd,UAAuC,CAAC,GAIxC;CAEA,MAAM,OAAO;EAAE,GAAG;EAAgB,GAAG;CAAQ;CAE7C,MAAM,aAAa,KAAK,cAAc,eAAe,cAAc;CAEnE,MAAM,UAA2B,CAAC;CAGlC,IAAI,eAAe;CAEnB,IAAI,cAAc;CAElB,IAAI,wBAAyC,CAAC;CAY9C,MAAM,eAAe,aAAkC;EAErD,IAAI,CAAC,KAAK,WAAW,aACnB;EAIF,IAAI,eAAe,QAAQ,SAAS,GAClC,QAAQ,OAAO,eAAe,CAAC;EAIjC,QAAQ,KAAK,QAAQ;EAErB,eAAe,QAAQ,SAAS;EAGhC,IAAI,QAAQ,SAAS,YAAY;GAC/B,QAAQ,MAAM;GAEd;EACF;CACF;CAOA,MAAM,aAAoD;;;;;EAKxD,YAAY;GAEV,IAAI,CAAC,WAAW,QAAQ,GACtB;GAIF,cAAc;GAEd;GAEA,MAAM,WAAW,QAAQ;GAEzB,gBAAgB,SAAS,SAAS,UAAU,SAAS,KAAK,CAAC;GAE3D,cAAc;EAChB;;;;;EAMA,YAAY;GAEV,IAAI,CAAC,WAAW,QAAQ,GACtB;GAIF,cAAc;GAEd;GAEA,MAAM,WAAW,QAAQ;GAEzB,gBAAgB,SAAS,SAAS,UAAU,SAAS,KAAK,CAAC;GAE3D,cAAc;EAChB;;;;;;;EAQA,OAAO,UAAkB;GAEvB,IAAI,QAAQ,KAAK,SAAS,QAAQ,QAChC;GAIF,cAAc;GAEd,eAAe;GAEf,MAAM,WAAW,QAAQ;GAEzB,gBAAgB,SAAS,SAAS,UAAU,SAAS,KAAK,CAAC;GAE3D,cAAc;EAChB;;;;;EAMA,kBAAkB,UAAU,OAAO;;;;;EAMnC,uBAAuB;;;;;;EAOvB,eAAe,eAAe;;;;;;EAO9B,eAAe,eAAe,QAAQ,SAAS;;;;;EAM/C,aAAa;GAEX,QAAQ,SAAS;GAEjB,eAAe;EACjB;CACF;CAOA,WAAW,wBAAwB,aAA8B;EAC/D,kBAAkB;CACpB;CA+CA,OAAO;EACL,YAAA;GAvCA,MAAM;GAEN,UAAU;;;;;;;;;GASV,SAAS,OAAO,SAA4B,SAAqC;IAE/E,MAAM,EAAE,SAAS,MAAM,UAAU;IAGjC,IAAI,CAAC,KAAK,WAAW,QAAQ,KAAK,aAAa;KAC7C,MAAM,KAAK;KACX;IACF;IAGA,MAAM,WAA0B;KAC9B,WAAW,KAAK,IAAI;KACpB,OAAO,UAAU,KAAK;KACtB;KACA;IACF;IAGA,MAAM,KAAK;IAGX,YAAY,QAAQ;GACtB;EAKA;EACA;CACF;AACF;AAWO,SAAS,mBACd,YACA,UACM;CAEN,MAAM,uBAAuB;CAE7B,IAAI,OAAO,qBAAqB,yBAAyB,YAAY;EAEnE,qBAAqB,qBAAqB,QAAQ;EAClD;CACF;CAGA,QAAQ,KAAK,4DAA4D;AAC3E"}
1
+ {"version":3,"file":"time-travel.js","names":[],"sources":["../../src/middleware/time-travel.ts"],"sourcesContent":["/* ============================================================\r\n * time-travel.ts\r\n * 时间旅行中间件\r\n * 提供状态快照历史记录、撤销(undo)、重做(redo)、跳转(goto)等能力\r\n * 用于实现 Store 状态的可回溯调试与操作历史管理\r\n * ============================================================ */\r\n\r\n/* 从类型文件导入中间件、上下文、快照、状态树等核心类型 */\r\nimport type {\r\n Middleware, // 中间件接口\r\n MiddlewareContext, // 中间件执行上下文接口\r\n StateSnapshot, // 状态快照接口\r\n StateTree, // 状态树类型\r\n StoreId, // Store 标识类型\r\n TimeTravelController, // 时间旅行控制器接口\r\n TimeTravelMiddlewareOptions, // 时间旅行中间件配置选项接口\r\n} from '../types'\r\n/* 从工具库导入深拷贝函数,用于快照的隔离存储 */\r\nimport { deepClone } from '../utils/deep-clone'\r\n\r\n/* ── 内部类型定义 ── */\r\n\r\n/**\r\n * 恢复回调函数类型\r\n * 当执行 undo/redo/goto 操作时,通过此回调将历史快照状态应用到对应 Store\r\n * @param storeId - 目标 Store 的标识\r\n * @param state - 要恢复的状态树(已深拷贝,可安全修改)\r\n */\r\ntype RestoreCallback = (storeId: StoreId, state: StateTree) => void\r\n\r\n/**\r\n * 带有内部恢复回调设置器的控制器扩展类型\r\n * 在 TimeTravelController 基础上增加 __setRestoreCallback 内部方法\r\n * 用于在创建后注入实际的恢复回调(由 Store 运行时提供)\r\n */\r\ntype TimeTravelControllerWithRestoreSetter = TimeTravelController & {\r\n __setRestoreCallback?: (callback: RestoreCallback) => void\r\n}\r\n\r\n/* ── 默认配置 ── */\r\n\r\n/** 中间件默认选项:最多保留 100 条历史记录,功能默认启用 */\r\nconst defaultOptions: TimeTravelMiddlewareOptions = {\r\n maxHistory: 100,\r\n enabled: true,\r\n}\r\n\r\n/**\r\n * 创建时间旅行中间件\r\n *\r\n * 返回一个中间件函数和一个控制器对象:\r\n * - 中间件负责拦截 state: 类型的操作,在操作前后记录状态快照\r\n * - 控制器提供 undo/redo/goto/clear 等方法,用于在历史快照之间跳转\r\n *\r\n * @param options - 中间件配置选项(可选,与默认值合并)\r\n * @returns 包含 middleware(中间件)和 controller(控制器)的对象\r\n */\r\nexport function createTimeTravelMiddleware(\r\n options: TimeTravelMiddlewareOptions = {}\r\n): {\r\n middleware: Middleware\r\n controller: TimeTravelController\r\n} {\r\n /* 将用户选项与默认选项合并 */\r\n const opts = { ...defaultOptions, ...options }\r\n /* 最大历史记录条数,确保至少为 1 */\r\n const maxHistory = opts.maxHistory ?? defaultOptions.maxHistory ?? 100\r\n /* 历史快照数组,存储所有状态变更的快照 */\r\n const history: StateSnapshot[] = []\r\n\r\n /* 当前快照指针,指向 history 数组中的当前位置,-1 表示无快照 */\r\n let currentIndex = -1\r\n /* 标记是否正在进行时间旅行(undo/redo/goto),防止在恢复过程中重复记录快照 */\r\n let isTraveling = false\r\n /* 恢复回调函数,初始为空函数,后续通过 __setRestoreCallback 注入实际实现 */\r\n let restoreCallback: RestoreCallback = () => {}\r\n\r\n /**\r\n * 添加新的状态快照到历史记录\r\n * 业务处理过程:\r\n * 1. 如果中间件未启用或正在时间旅行中,则跳过\r\n * 2. 如果当前指针不在末尾(即之前执行过 undo),则丢弃指针之后的快照(分支覆盖)\r\n * 3. 推入新快照并更新指针\r\n * 4. 如果超过最大历史条数,移除最早的快照并调整指针\r\n *\r\n * @param snapshot - 要添加的状态快照\r\n */\r\n const addSnapshot = (snapshot: StateSnapshot): void => {\r\n /* 中间件未启用或正在时间旅行中,不记录快照 */\r\n if (!opts.enabled || isTraveling) {\r\n return\r\n }\r\n\r\n /* 如果当前指针不在历史末尾(之前执行过 undo),丢弃后续快照(创建新分支) */\r\n if (currentIndex < history.length - 1) {\r\n history.splice(currentIndex + 1)\r\n }\r\n\r\n /* 将新快照推入历史数组 */\r\n history.push(snapshot)\r\n /* 更新指针到最新快照 */\r\n currentIndex = history.length - 1\r\n\r\n /* 如果历史记录超过上限,移除最早的快照 */\r\n if (history.length > maxHistory) {\r\n history.shift()\r\n /* 移除头部元素后指针需要前移一位 */\r\n currentIndex--\r\n }\r\n }\r\n\r\n /**\r\n * 时间旅行控制器\r\n * 提供 undo(撤销)、redo(重做)、goto(跳转)、clear(清除)等操作\r\n * 所有恢复操作都通过 restoreCallback 将历史快照应用到 Store\r\n */\r\n const controller: TimeTravelControllerWithRestoreSetter = {\r\n /**\r\n * 撤销操作\r\n * 将当前指针前移一步,恢复到上一个历史快照状态\r\n */\r\n undo: () => {\r\n /* 无法撤销(已到最早快照)则跳过 */\r\n if (!controller.canUndo()) {\r\n return\r\n }\r\n\r\n /* 标记进入时间旅行模式,防止恢复过程触发新的快照记录 */\r\n isTraveling = true\r\n /* 指针前移 */\r\n currentIndex--\r\n /* 获取目标快照 */\r\n const snapshot = history[currentIndex]\r\n /* 通过恢复回调将快照状态(深拷贝)应用到 Store,避免污染历史记录 */\r\n restoreCallback(snapshot.storeId, deepClone(snapshot.state))\r\n /* 退出时间旅行模式 */\r\n isTraveling = false\r\n },\r\n\r\n /**\r\n * 重做操作\r\n * 将当前指针后移一步,恢复到下一个历史快照状态\r\n */\r\n redo: () => {\r\n /* 无法重做(已到最新快照)则跳过 */\r\n if (!controller.canRedo()) {\r\n return\r\n }\r\n\r\n /* 标记进入时间旅行模式 */\r\n isTraveling = true\r\n /* 指针后移 */\r\n currentIndex++\r\n /* 获取目标快照 */\r\n const snapshot = history[currentIndex]\r\n /* 恢复快照状态(深拷贝) */\r\n restoreCallback(snapshot.storeId, deepClone(snapshot.state))\r\n /* 退出时间旅行模式 */\r\n isTraveling = false\r\n },\r\n\r\n /**\r\n * 跳转到指定历史索引\r\n * 将当前指针直接移动到指定位置,恢复对应的快照状态\r\n *\r\n * @param index - 目标历史索引(0-based)\r\n */\r\n goto: (index: number) => {\r\n /* 索引越界检查 */\r\n if (index < 0 || index >= history.length) {\r\n return\r\n }\r\n\r\n /* 标记进入时间旅行模式 */\r\n isTraveling = true\r\n /* 直接设置指针到目标索引 */\r\n currentIndex = index\r\n /* 获取目标快照 */\r\n const snapshot = history[currentIndex]\r\n /* 恢复快照状态(深拷贝) */\r\n restoreCallback(snapshot.storeId, deepClone(snapshot.state))\r\n /* 退出时间旅行模式 */\r\n isTraveling = false\r\n },\r\n\r\n /**\r\n * 获取完整的快照历史(返回深拷贝,防止外部修改内部历史记录)\r\n * @returns 历史快照数组的深拷贝\r\n */\r\n getHistory: () => deepClone(history),\r\n\r\n /**\r\n * 获取当前快照指针索引\r\n * @returns 当前索引值,-1 表示无快照\r\n */\r\n getCurrentIndex: () => currentIndex,\r\n\r\n /**\r\n * 判断是否可以撤销\r\n * 当前索引大于 0 时,说明前面还有历史快照\r\n * @returns 是否可以执行 undo 操作\r\n */\r\n canUndo: () => currentIndex > 0,\r\n\r\n /**\r\n * 判断是否可以重做\r\n * 当前索引小于历史长度 - 1 时,说明后面还有快照\r\n * @returns 是否可以执行 redo 操作\r\n */\r\n canRedo: () => currentIndex < history.length - 1,\r\n\r\n /**\r\n * 清除所有历史快照并重置指针\r\n * 通常在 Store 销毁或需要重置历史时调用\r\n */\r\n clear: () => {\r\n /* 清空历史数组 */\r\n history.length = 0\r\n /* 重置指针到初始状态 */\r\n currentIndex = -1\r\n },\r\n }\r\n\r\n /**\r\n * 在控制器上挂载内部恢复回调设置器\r\n * 允许 Store 运行时在初始化时注入实际的状态恢复逻辑\r\n * 使用 __ 前缀表示这是内部方法,不建议外部直接调用\r\n */\r\n controller.__setRestoreCallback = (callback: RestoreCallback) => {\r\n restoreCallback = callback\r\n }\r\n\r\n /**\r\n * 时间旅行中间件\r\n * 拦截所有 \"state:\" 前缀的操作(如 state:update),在操作执行前后\r\n * 记录状态快照,从而构建可回溯的状态历史\r\n */\r\n const middleware: Middleware = {\r\n /* 中间件名称,用于调试和日志 */\r\n name: 'time-travel',\r\n /* 中间件优先级,50 为中等优先级(数值越小越先执行) */\r\n priority: 50,\r\n /**\r\n * 中间件处理函数\r\n * 只拦截 \"state:\" 类型的操作(状态变更操作),其他类型直接放行\r\n * 正在时间旅行时也不记录快照,避免循环\r\n *\r\n * @param context - 中间件上下文,包含 storeId、操作类型、状态等信息\r\n * @param next - 调用下一个中间件或最终操作的函数\r\n */\r\n handler: async (\r\n context: MiddlewareContext,\r\n next: () => void | Promise<void>\r\n ) => {\r\n /* 解构上下文:Store 标识、操作类型、当前状态 */\r\n const { storeId, type, state } = context\r\n\r\n /* 非状态变更操作(不以 \"state:\" 开头)或正在时间旅行中,直接执行后续操作 */\r\n if (!type.startsWith('state:') || isTraveling) {\r\n await next()\r\n return\r\n }\r\n\r\n /* 在执行操作前,创建当前状态的快照(before snapshot) */\r\n const snapshot: StateSnapshot = {\r\n timestamp: Date.now() /* 快照时间戳 */,\r\n state: deepClone(state) /* 深拷贝当前状态,隔离引用 */,\r\n type /* 操作类型 */,\r\n storeId /* Store 标识 */,\r\n }\r\n\r\n /* 执行后续中间件或最终操作 */\r\n await next()\r\n\r\n /* 操作执行完成后,将快照添加到历史记录 */\r\n addSnapshot(snapshot)\r\n },\r\n }\r\n\r\n /* 返回中间件和控制器 */\r\n return {\r\n middleware,\r\n controller,\r\n }\r\n}\r\n\r\n/**\r\n * 外部设置恢复回调的辅助函数\r\n * 将外部提供的状态恢复函数注入到时间旅行控制器中\r\n *\r\n * 使用场景:Store 运行时初始化时调用此函数,将控制器与 Store 的状态恢复逻辑连接\r\n *\r\n * @param controller - 时间旅行控制器实例\r\n * @param callback - 恢复回调函数,接收 storeId 和已深拷贝的状态树\r\n */\r\nexport function setRestoreCallback(\r\n controller: TimeTravelController,\r\n callback: (storeId: StoreId, state: StateTree) => void\r\n): void {\r\n /* 将通用控制器类型断言为带内部设置器的扩展类型 */\r\n const controllerWithSetter =\r\n controller as TimeTravelControllerWithRestoreSetter\r\n /* 检查控制器是否支持 __setRestoreCallback 方法 */\r\n if (typeof controllerWithSetter.__setRestoreCallback === 'function') {\r\n /* 注入恢复回调 */\r\n controllerWithSetter.__setRestoreCallback(callback)\r\n return\r\n }\r\n\r\n /* 如果控制器不支持,输出警告(说明传入的不是 createTimeTravelMiddleware 创建的控制器) */\r\n console.warn(\r\n '[TimeTravel] 请使用 createTimeTravelMiddleware 返回的 controller'\r\n )\r\n}\r\n"],"mappings":";;;;;;;;;;;AA0CA,MAAM,iBAA8C;CAClD,YAAY;CACZ,SAAS;AACX;AAYO,SAAS,2BACd,UAAuC,CAAC,GAIxC;CAEA,MAAM,OAAO;EAAE,GAAG;EAAgB,GAAG;CAAQ;CAE7C,MAAM,aAAa,KAAK,cAAc,eAAe,cAAc;CAEnE,MAAM,UAA2B,CAAC;CAGlC,IAAI,eAAe;CAEnB,IAAI,cAAc;CAElB,IAAI,wBAAyC,CAAC;CAY9C,MAAM,eAAe,aAAkC;EAErD,IAAI,CAAC,KAAK,WAAW,aACnB;EAIF,IAAI,eAAe,QAAQ,SAAS,GAClC,QAAQ,OAAO,eAAe,CAAC;EAIjC,QAAQ,KAAK,QAAQ;EAErB,eAAe,QAAQ,SAAS;EAGhC,IAAI,QAAQ,SAAS,YAAY;GAC/B,QAAQ,MAAM;GAEd;EACF;CACF;CAOA,MAAM,aAAoD;;;;;EAKxD,YAAY;GAEV,IAAI,CAAC,WAAW,QAAQ,GACtB;GAIF,cAAc;GAEd;GAEA,MAAM,WAAW,QAAQ;GAEzB,gBAAgB,SAAS,SAAS,UAAU,SAAS,KAAK,CAAC;GAE3D,cAAc;EAChB;;;;;EAMA,YAAY;GAEV,IAAI,CAAC,WAAW,QAAQ,GACtB;GAIF,cAAc;GAEd;GAEA,MAAM,WAAW,QAAQ;GAEzB,gBAAgB,SAAS,SAAS,UAAU,SAAS,KAAK,CAAC;GAE3D,cAAc;EAChB;;;;;;;EAQA,OAAO,UAAkB;GAEvB,IAAI,QAAQ,KAAK,SAAS,QAAQ,QAChC;GAIF,cAAc;GAEd,eAAe;GAEf,MAAM,WAAW,QAAQ;GAEzB,gBAAgB,SAAS,SAAS,UAAU,SAAS,KAAK,CAAC;GAE3D,cAAc;EAChB;;;;;EAMA,kBAAkB,UAAU,OAAO;;;;;EAMnC,uBAAuB;;;;;;EAOvB,eAAe,eAAe;;;;;;EAO9B,eAAe,eAAe,QAAQ,SAAS;;;;;EAM/C,aAAa;GAEX,QAAQ,SAAS;GAEjB,eAAe;EACjB;CACF;CAOA,WAAW,wBAAwB,aAA8B;EAC/D,kBAAkB;CACpB;CAkDA,OAAO;EACL,YAAA;GA1CA,MAAM;GAEN,UAAU;;;;;;;;;GASV,SAAS,OACP,SACA,SACG;IAEH,MAAM,EAAE,SAAS,MAAM,UAAU;IAGjC,IAAI,CAAC,KAAK,WAAW,QAAQ,KAAK,aAAa;KAC7C,MAAM,KAAK;KACX;IACF;IAGA,MAAM,WAA0B;KAC9B,WAAW,KAAK,IAAI;KACpB,OAAO,UAAU,KAAK;KACtB;KACA;IACF;IAGA,MAAM,KAAK;IAGX,YAAY,QAAQ;GACtB;EAKA;EACA;CACF;AACF;AAWO,SAAS,mBACd,YACA,UACM;CAEN,MAAM,uBACJ;CAEF,IAAI,OAAO,qBAAqB,yBAAyB,YAAY;EAEnE,qBAAqB,qBAAqB,QAAQ;EAClD;CACF;CAGA,QAAQ,KACN,4DACF;AACF"}
@@ -2,7 +2,7 @@
2
2
  * ***********************************
3
3
  * @composy/store-core v0.0.1 *
4
4
  * Built with rollup *
5
- * Build time: 2024-08-17 11:27:33 *
5
+ * Build time: 2024-10-12 17:23:58 *
6
6
  * Build mode: production *
7
7
  * Minified: No *
8
8
  * ***********************************
@@ -52,13 +52,13 @@ function createValidationMiddleware(options) {
52
52
  await next();
53
53
  return;
54
54
  }
55
- await next();
56
55
  const result = await validateState(storeId, state);
57
56
  if (!result.valid) {
58
57
  lastErrors = result.errors;
59
58
  onValidationError?.(result);
60
59
  if (blocking) throw new Error(`[Validation] ${storeId}: ${result.errors.map((e) => e.message).join("; ")}`);
61
60
  } else lastErrors = lastErrors.filter((e) => e.storeId !== storeId);
61
+ await next();
62
62
  }
63
63
  },
64
64
  validate: validateState,
@@ -1 +1 @@
1
- {"version":3,"file":"validation.js","names":[],"sources":["../../src/middleware/validation.ts"],"sourcesContent":["/**\n * 验证中间件\n *\n * 对状态变化进行规则校验,支持同步/异步校验器\n * @module middleware/validation\n */\n\nimport type { Middleware, MiddlewareContext, StateTree, StoreId } from '../types'\n\n/**\n * 单个字段校验规则\n */\nexport interface ValidationRule<T = unknown> {\n /** 校验函数,返回 true 表示通过 */\n validate: (value: T, state: StateTree) => boolean | Promise<boolean>\n /** 校验失败时的错误信息 */\n message: string\n}\n\n/**\n * Store 校验规则集\n */\nexport type StoreValidationRules = Record<string, ValidationRule | ValidationRule[]>\n\n/**\n * 校验错误\n */\nexport interface ValidationError {\n /** Store ID */\n storeId: StoreId\n /** 字段路径 */\n field: string\n /** 错误信息 */\n message: string\n /** 字段值 */\n value: unknown\n}\n\n/**\n * 校验结果\n */\nexport interface ValidationResult {\n /** 是否全部通过 */\n valid: boolean\n /** 错误列表 */\n errors: ValidationError[]\n}\n\n/**\n * 验证中间件选项\n */\nexport interface ValidationMiddlewareOptions {\n /** 按 Store ID 配置的校验规则 */\n rules: Record<StoreId, StoreValidationRules>\n /** 校验失败时的回调 */\n onValidationError?: (result: ValidationResult) => void\n /** 校验失败是否阻止状态变化 (默认 false,仅报告) */\n blocking?: boolean\n /** 是否只在 state:patch 时校验 (默认 false,所有 state: 前缀均校验) */\n patchOnly?: boolean\n}\n\n/**\n * 创建验证中间件\n *\n * 对状态变化进行规则校验,可选择阻止无效变化或仅报告错误\n *\n * @param options - 验证配置\n * @returns 中间件实例和校验辅助 API\n *\n * @example\n * ```typescript\n * const { middleware, validate, getErrors, clearErrors } = createValidationMiddleware({\n * rules: {\n * 'user-form': {\n * name: {\n * validate: (v) => typeof v === 'string' && v.length >= 2,\n * message: 'Name must be at least 2 characters',\n * },\n * age: [\n * { validate: (v) => typeof v === 'number', message: 'Age must be a number' },\n * { validate: (v) => (v as number) >= 0 && (v as number) <= 150, message: 'Age must be 0-150' },\n * ],\n * email: {\n * validate: (v) => /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(String(v)),\n * message: 'Invalid email format',\n * },\n * },\n * },\n * onValidationError: (result) => {\n * console.warn('Validation failed:', result.errors)\n * },\n * })\n *\n * manager.use(middleware)\n * ```\n */\nexport function createValidationMiddleware(options: ValidationMiddlewareOptions): {\n middleware: Middleware\n /** 手动校验某个 store 的当前状态 */\n validate: (storeId: StoreId, state: StateTree) => Promise<ValidationResult>\n /** 获取最近一次的校验错误 */\n getErrors: () => ValidationError[]\n /** 清空错误 */\n clearErrors: () => void\n} {\n const {\n rules,\n onValidationError,\n blocking = false,\n patchOnly = false,\n } = options\n\n let lastErrors: ValidationError[] = []\n\n /**\n * 校验单个 store 状态\n */\n async function validateState(storeId: StoreId, state: StateTree): Promise<ValidationResult> {\n const storeRules = rules[storeId]\n if (!storeRules) return { valid: true, errors: [] }\n\n const errors: ValidationError[] = []\n\n for (const [field, fieldRules] of Object.entries(storeRules)) {\n const ruleList = Array.isArray(fieldRules) ? fieldRules : [fieldRules]\n const value = state[field]\n\n for (const rule of ruleList) {\n try {\n const isValid = await rule.validate(value, state)\n if (!isValid) {\n errors.push({\n storeId,\n field,\n message: rule.message,\n value,\n })\n }\n }\n catch {\n errors.push({\n storeId,\n field,\n message: rule.message || `Validation error on field \"${field}\"`,\n value,\n })\n }\n }\n }\n\n return { valid: errors.length === 0, errors }\n }\n\n const middleware: Middleware = {\n name: 'validation',\n priority: 5, // 在 logger (0) 之后、大多数业务中间件之前\n\n handler: async (context: MiddlewareContext, next: () => void | Promise<void>) => {\n const { storeId, type, state } = context\n\n // 检查是否需要校验\n const shouldValidate = patchOnly\n ? type === 'state:patch'\n : type.startsWith('state:')\n\n if (!shouldValidate || !rules[storeId]) {\n await next()\n return\n }\n\n // 先执行状态变化\n await next()\n\n // 校验变化后的状态\n const result = await validateState(storeId, state)\n\n if (!result.valid) {\n lastErrors = result.errors\n onValidationError?.(result)\n\n if (blocking) {\n throw new Error(\n `[Validation] ${storeId}: ${result.errors.map(e => e.message).join('; ')}`,\n )\n }\n }\n else {\n // 校验通过,清除该 store 的错误\n lastErrors = lastErrors.filter(e => e.storeId !== storeId)\n }\n },\n }\n\n return {\n middleware,\n validate: validateState,\n getErrors: () => [...lastErrors],\n clearErrors: () => { lastErrors = [] },\n }\n}\n"],"mappings":";;;;;;;;;;AAiGO,SAAS,2BAA2B,SAQzC;CACA,MAAM,EACJ,OACA,mBACA,WAAW,OACX,YAAY,UACV;CAEJ,IAAI,aAAgC,CAAC;CAKrC,eAAe,cAAc,SAAkB,OAA6C;EAC1F,MAAM,aAAa,MAAM;EACzB,IAAI,CAAC,YAAY,OAAO;GAAE,OAAO;GAAM,QAAQ,CAAC;EAAE;EAElD,MAAM,SAA4B,CAAC;EAEnC,KAAA,MAAW,CAAC,OAAO,eAAe,OAAO,QAAQ,UAAU,GAAG;GAC5D,MAAM,WAAW,MAAM,QAAQ,UAAU,IAAI,aAAa,CAAC,UAAU;GACrE,MAAM,QAAQ,MAAM;GAEpB,KAAA,MAAW,QAAQ,UACjB,IAAI;IAEF,IAAI,CAAC,MADiB,KAAK,SAAS,OAAO,KAAK,GAE9C,OAAO,KAAK;KACV;KACA;KACA,SAAS,KAAK;KACd;IACF,CAAC;GAEL,QACM;IACJ,OAAO,KAAK;KACV;KACA;KACA,SAAS,KAAK,WAAW,8BAA8B,MAAK;KAC5D;IACF,CAAC;GACH;EAEJ;EAEA,OAAO;GAAE,OAAO,OAAO,WAAW;GAAG;EAAO;CAC9C;CA0CA,OAAO;EACL,YAAA;GAxCA,MAAM;GACN,UAAU;GAEV,SAAS,OAAO,SAA4B,SAAqC;IAC/E,MAAM,EAAE,SAAS,MAAM,UAAU;IAOjC,IAAI,EAJmB,YACnB,SAAS,gBACT,KAAK,WAAW,QAAQ,MAEL,CAAC,MAAM,UAAU;KACtC,MAAM,KAAK;KACX;IACF;IAGA,MAAM,KAAK;IAGX,MAAM,SAAS,MAAM,cAAc,SAAS,KAAK;IAEjD,IAAI,CAAC,OAAO,OAAO;KACjB,aAAa,OAAO;KACpB,oBAAoB,MAAM;KAE1B,IAAI,UACF,MAAM,IAAI,MACR,gBAAgB,QAAO,IAAK,OAAO,OAAO,KAAI,MAAK,EAAE,OAAO,CAAA,CAAE,KAAK,IAAI,GACzE;IAEJ,OAGE,aAAa,WAAW,QAAO,MAAK,EAAE,YAAY,OAAO;GAE7D;EAIA;EACA,UAAU;EACV,iBAAiB,CAAC,GAAG,UAAU;EAC/B,mBAAmB;GAAE,aAAa,CAAC;EAAE;CACvC;AACF"}
1
+ {"version":3,"file":"validation.js","names":[],"sources":["../../src/middleware/validation.ts"],"sourcesContent":["/**\r\n * 验证中间件\r\n *\r\n * 对状态变化进行规则校验,支持同步/异步校验器\r\n * @module middleware/validation\r\n */\r\n\r\nimport type {\r\n Middleware,\r\n MiddlewareContext,\r\n StateTree,\r\n StoreId,\r\n} from '../types'\r\n\r\n/**\r\n * 单个字段校验规则\r\n */\r\nexport interface ValidationRule<T = unknown> {\r\n /** 校验函数,返回 true 表示通过 */\r\n validate: (value: T, state: StateTree) => boolean | Promise<boolean>\r\n /** 校验失败时的错误信息 */\r\n message: string\r\n}\r\n\r\n/**\r\n * Store 校验规则集\r\n */\r\nexport type StoreValidationRules = Record<\r\n string,\r\n ValidationRule | ValidationRule[]\r\n>\r\n\r\n/**\r\n * 校验错误\r\n */\r\nexport interface ValidationError {\r\n /** Store ID */\r\n storeId: StoreId\r\n /** 字段路径 */\r\n field: string\r\n /** 错误信息 */\r\n message: string\r\n /** 字段值 */\r\n value: unknown\r\n}\r\n\r\n/**\r\n * 校验结果\r\n */\r\nexport interface ValidationResult {\r\n /** 是否全部通过 */\r\n valid: boolean\r\n /** 错误列表 */\r\n errors: ValidationError[]\r\n}\r\n\r\n/**\r\n * 验证中间件选项\r\n */\r\nexport interface ValidationMiddlewareOptions {\r\n /** 按 Store ID 配置的校验规则 */\r\n rules: Record<StoreId, StoreValidationRules>\r\n /** 校验失败时的回调 */\r\n onValidationError?: (result: ValidationResult) => void\r\n /** 校验失败是否阻止状态变化 (默认 false,仅报告) */\r\n blocking?: boolean\r\n /** 是否只在 state:patch 时校验 (默认 false,所有 state: 前缀均校验) */\r\n patchOnly?: boolean\r\n}\r\n\r\n/**\r\n * 创建验证中间件\r\n *\r\n * 对状态变化进行规则校验,可选择阻止无效变化或仅报告错误\r\n *\r\n * @param options - 验证配置\r\n * @returns 中间件实例和校验辅助 API\r\n *\r\n * @example\r\n * ```typescript\r\n * const { middleware, validate, getErrors, clearErrors } = createValidationMiddleware({\r\n * rules: {\r\n * 'user-form': {\r\n * name: {\r\n * validate: (v) => typeof v === 'string' && v.length >= 2,\r\n * message: 'Name must be at least 2 characters',\r\n * },\r\n * age: [\r\n * { validate: (v) => typeof v === 'number', message: 'Age must be a number' },\r\n * { validate: (v) => (v as number) >= 0 && (v as number) <= 150, message: 'Age must be 0-150' },\r\n * ],\r\n * email: {\r\n * validate: (v) => /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(String(v)),\r\n * message: 'Invalid email format',\r\n * },\r\n * },\r\n * },\r\n * onValidationError: (result) => {\r\n * console.warn('Validation failed:', result.errors)\r\n * },\r\n * })\r\n *\r\n * manager.use(middleware)\r\n * ```\r\n */\r\nexport function createValidationMiddleware(\r\n options: ValidationMiddlewareOptions\r\n): {\r\n middleware: Middleware\r\n /** 手动校验某个 store 的当前状态 */\r\n validate: (storeId: StoreId, state: StateTree) => Promise<ValidationResult>\r\n /** 获取最近一次的校验错误 */\r\n getErrors: () => ValidationError[]\r\n /** 清空错误 */\r\n clearErrors: () => void\r\n} {\r\n const {\r\n rules,\r\n onValidationError,\r\n blocking = false,\r\n patchOnly = false,\r\n } = options\r\n\r\n let lastErrors: ValidationError[] = []\r\n\r\n /**\r\n * 校验单个 store 状态\r\n */\r\n async function validateState(\r\n storeId: StoreId,\r\n state: StateTree\r\n ): Promise<ValidationResult> {\r\n const storeRules = rules[storeId]\r\n if (!storeRules) return { valid: true, errors: [] }\r\n\r\n const errors: ValidationError[] = []\r\n\r\n for (const [field, fieldRules] of Object.entries(storeRules)) {\r\n const ruleList = Array.isArray(fieldRules) ? fieldRules : [fieldRules]\r\n const value = state[field]\r\n\r\n for (const rule of ruleList) {\r\n try {\r\n const isValid = await rule.validate(value, state)\r\n if (!isValid) {\r\n errors.push({\r\n storeId,\r\n field,\r\n message: rule.message,\r\n value,\r\n })\r\n }\r\n } catch {\r\n errors.push({\r\n storeId,\r\n field,\r\n message: rule.message || `Validation error on field \"${field}\"`,\r\n value,\r\n })\r\n }\r\n }\r\n }\r\n\r\n return { valid: errors.length === 0, errors }\r\n }\r\n\r\n const middleware: Middleware = {\r\n name: 'validation',\r\n priority: 5, // 在 logger (0) 之后、大多数业务中间件之前\r\n\r\n handler: async (\r\n context: MiddlewareContext,\r\n next: () => void | Promise<void>\r\n ) => {\r\n const { storeId, type, state } = context\r\n\r\n // 检查是否需要校验\r\n const shouldValidate = patchOnly\r\n ? type === 'state:patch'\r\n : type.startsWith('state:')\r\n\r\n if (!shouldValidate || !rules[storeId]) {\r\n await next()\r\n return\r\n }\r\n\r\n // 先执行状态变化\r\n const result = await validateState(storeId, state)\r\n\r\n if (!result.valid) {\r\n lastErrors = result.errors\r\n onValidationError?.(result)\r\n\r\n if (blocking) {\r\n throw new Error(\r\n `[Validation] ${storeId}: ${result.errors.map(e => e.message).join('; ')}`\r\n )\r\n }\r\n } else {\r\n // 校验通过,清除该 store 的错误\r\n lastErrors = lastErrors.filter(e => e.storeId !== storeId)\r\n }\r\n\r\n await next()\r\n },\r\n }\r\n\r\n return {\r\n middleware,\r\n validate: validateState,\r\n getErrors: () => [...lastErrors],\r\n clearErrors: () => {\r\n lastErrors = []\r\n },\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;AAyGO,SAAS,2BACd,SASA;CACA,MAAM,EACJ,OACA,mBACA,WAAW,OACX,YAAY,UACV;CAEJ,IAAI,aAAgC,CAAC;CAKrC,eAAe,cACb,SACA,OAC2B;EAC3B,MAAM,aAAa,MAAM;EACzB,IAAI,CAAC,YAAY,OAAO;GAAE,OAAO;GAAM,QAAQ,CAAC;EAAE;EAElD,MAAM,SAA4B,CAAC;EAEnC,KAAA,MAAW,CAAC,OAAO,eAAe,OAAO,QAAQ,UAAU,GAAG;GAC5D,MAAM,WAAW,MAAM,QAAQ,UAAU,IAAI,aAAa,CAAC,UAAU;GACrE,MAAM,QAAQ,MAAM;GAEpB,KAAA,MAAW,QAAQ,UACjB,IAAI;IAEF,IAAI,CAAC,MADiB,KAAK,SAAS,OAAO,KAAK,GAE9C,OAAO,KAAK;KACV;KACA;KACA,SAAS,KAAK;KACd;IACF,CAAC;GAEL,QAAQ;IACN,OAAO,KAAK;KACV;KACA;KACA,SAAS,KAAK,WAAW,8BAA8B,MAAK;KAC5D;IACF,CAAC;GACH;EAEJ;EAEA,OAAO;GAAE,OAAO,OAAO,WAAW;GAAG;EAAO;CAC9C;CA2CA,OAAO;EACL,YAAA;GAzCA,MAAM;GACN,UAAU;GAEV,SAAS,OACP,SACA,SACG;IACH,MAAM,EAAE,SAAS,MAAM,UAAU;IAOjC,IAAI,EAJmB,YACnB,SAAS,gBACT,KAAK,WAAW,QAAQ,MAEL,CAAC,MAAM,UAAU;KACtC,MAAM,KAAK;KACX;IACF;IAGA,MAAM,SAAS,MAAM,cAAc,SAAS,KAAK;IAEjD,IAAI,CAAC,OAAO,OAAO;KACjB,aAAa,OAAO;KACpB,oBAAoB,MAAM;KAE1B,IAAI,UACF,MAAM,IAAI,MACR,gBAAgB,QAAO,IAAK,OAAO,OAAO,KAAI,MAAK,EAAE,OAAO,CAAA,CAAE,KAAK,IAAI,GACzE;IAEJ,OAEE,aAAa,WAAW,QAAO,MAAK,EAAE,YAAY,OAAO;IAG3D,MAAM,KAAK;GACb;EAIA;EACA,UAAU;EACV,iBAAiB,CAAC,GAAG,UAAU;EAC/B,mBAAmB;GACjB,aAAa,CAAC;EAChB;CACF;AACF"}
@@ -2,7 +2,7 @@
2
2
  * ***********************************
3
3
  * @composy/store-core v0.0.1 *
4
4
  * Built with rollup *
5
- * Build time: 2024-08-17 11:27:33 *
5
+ * Build time: 2024-10-12 17:23:58 *
6
6
  * Build mode: production *
7
7
  * Minified: No *
8
8
  * ***********************************
@@ -28,7 +28,7 @@ function createPluginFactory(factory) {
28
28
  function composePlugins(plugins) {
29
29
  return {
30
30
  name: "composed-plugins",
31
- version: "1.0.0",
31
+ version: "0.0.1",
32
32
  async install(context, options) {
33
33
  for (const plugin of plugins) await plugin.install(context, options);
34
34
  },
@@ -1 +1 @@
1
- {"version":3,"file":"define-plugin.js","names":[],"sources":["../../src/plugins/define-plugin.ts"],"sourcesContent":["/**\n * 插件定义辅助函数\n *\n * @module plugins/define-plugin\n */\n\nimport type { DefinePluginOptions, PluginFactory, StorePlugin } from '../types'\n\n/**\n * 定义 Store 插件\n *\n * 提供类型安全的插件定义方式\n *\n * @template Options - 插件选项类型\n * @param options - 插件定义选项\n * @returns 插件实例\n *\n * @example\n * ```typescript\n * // 定义一个简单的日志插件\n * const loggerPlugin = defineStorePlugin({\n * name: 'logger',\n * version: '1.0.0',\n * install(context) {\n * console.log('Logger plugin installed')\n * },\n * onStateChange(storeId, state, oldState) {\n * console.log(`[${storeId}] State changed:`, state)\n * },\n * })\n * ```\n */\nexport function defineStorePlugin<Options = Record<string, unknown>>(\n options: DefinePluginOptions<Options>,\n): StorePlugin<Options> {\n return {\n name: options.name,\n version: options.version,\n description: options.description,\n install: options.install,\n uninstall: options.uninstall,\n onStoreCreated: options.onStoreCreated,\n onStoreDisposed: options.onStoreDisposed,\n onStateChange: options.onStateChange,\n }\n}\n\n/**\n * 创建插件工厂函数\n *\n * 用于创建可配置的插件\n *\n * @template Options - 插件选项类型\n * @param factory - 插件工厂函数\n * @returns 插件工厂\n *\n * @example\n * ```typescript\n * // 创建可配置的持久化插件\n * const createPersistPlugin = createPluginFactory<{ key: string }>(\n * (options) => ({\n * name: 'persist',\n * install(context) {\n * console.log('Persist key:', options?.key)\n * },\n * })\n * )\n *\n * // 使用\n * const plugin = createPersistPlugin({ key: 'my-store' })\n * ```\n */\nexport function createPluginFactory<Options = Record<string, unknown>>(\n factory: (options?: Options) => DefinePluginOptions<Options>,\n): PluginFactory<Options> {\n return (options?: Options): StorePlugin<Options> => {\n return defineStorePlugin(factory(options))\n }\n}\n\n/**\n * 组合多个插件\n *\n * @param plugins - 插件列表\n * @returns 组合后的插件\n *\n * @example\n * ```typescript\n * const combinedPlugin = composePlugins([\n * loggerPlugin,\n * persistPlugin,\n * devtoolsPlugin,\n * ])\n * ```\n */\nexport function composePlugins(\n plugins: StorePlugin[],\n): StorePlugin {\n return {\n name: 'composed-plugins',\n version: '1.0.0',\n\n async install(context, options) {\n for (const plugin of plugins) {\n await plugin.install(context, options)\n }\n },\n\n async uninstall(context) {\n // 逆序卸载\n for (let i = plugins.length - 1; i >= 0; i--) {\n await plugins[i].uninstall?.(context)\n }\n },\n\n onStoreCreated(store) {\n plugins.forEach(plugin => plugin.onStoreCreated?.(store))\n },\n\n onStoreDisposed(store) {\n plugins.forEach(plugin => plugin.onStoreDisposed?.(store))\n },\n\n onStateChange(storeId, state, oldState) {\n plugins.forEach(plugin => plugin.onStateChange?.(storeId, state, oldState))\n },\n }\n}\n\n"],"mappings":";;;;;;;;;;AAgCO,SAAS,kBACd,SACsB;CACtB,OAAO;EACL,MAAM,QAAQ;EACd,SAAS,QAAQ;EACjB,aAAa,QAAQ;EACrB,SAAS,QAAQ;EACjB,WAAW,QAAQ;EACnB,gBAAgB,QAAQ;EACxB,iBAAiB,QAAQ;EACzB,eAAe,QAAQ;CACzB;AACF;AA2BO,SAAS,oBACd,SACwB;CACxB,QAAQ,YAA4C;EAClD,OAAO,kBAAkB,QAAQ,OAAO,CAAC;CAC3C;AACF;AAiBO,SAAS,eACd,SACa;CACb,OAAO;EACL,MAAM;EACN,SAAS;EAET,MAAM,QAAQ,SAAS,SAAS;GAC9B,KAAA,MAAW,UAAU,SACnB,MAAM,OAAO,QAAQ,SAAS,OAAO;EAEzC;EAEA,MAAM,UAAU,SAAS;GAEvB,KAAA,IAAS,IAAI,QAAQ,SAAS,GAAG,KAAK,GAAG,KACvC,MAAM,QAAQ,EAAC,CAAE,YAAY,OAAO;EAExC;EAEA,eAAe,OAAO;GACpB,QAAQ,SAAQ,WAAU,OAAO,iBAAiB,KAAK,CAAC;EAC1D;EAEA,gBAAgB,OAAO;GACrB,QAAQ,SAAQ,WAAU,OAAO,kBAAkB,KAAK,CAAC;EAC3D;EAEA,cAAc,SAAS,OAAO,UAAU;GACtC,QAAQ,SAAQ,WAAU,OAAO,gBAAgB,SAAS,OAAO,QAAQ,CAAC;EAC5E;CACF;AACF"}
1
+ {"version":3,"file":"define-plugin.js","names":[],"sources":["../../src/plugins/define-plugin.ts"],"sourcesContent":["/**\r\n * 插件定义辅助函数\r\n *\r\n * @module plugins/define-plugin\r\n */\r\n\r\nimport type { DefinePluginOptions, PluginFactory, StorePlugin } from '../types'\r\n\r\n/**\r\n * 定义 Store 插件\r\n *\r\n * 提供类型安全的插件定义方式\r\n *\r\n * @template Options - 插件选项类型\r\n * @param options - 插件定义选项\r\n * @returns 插件实例\r\n *\r\n * @example\r\n * ```typescript\r\n * // 定义一个简单的日志插件\r\n * const loggerPlugin = defineStorePlugin({\r\n * name: 'logger',\r\n * version: '0.0.1',\r\n * install(context) {\r\n * console.log('Logger plugin installed')\r\n * },\r\n * onStateChange(storeId, state, oldState) {\r\n * console.log(`[${storeId}] State changed:`, state)\r\n * },\r\n * })\r\n * ```\r\n */\r\nexport function defineStorePlugin<Options = Record<string, unknown>>(\r\n options: DefinePluginOptions<Options>\r\n): StorePlugin<Options> {\r\n return {\r\n name: options.name,\r\n version: options.version,\r\n description: options.description,\r\n install: options.install,\r\n uninstall: options.uninstall,\r\n onStoreCreated: options.onStoreCreated,\r\n onStoreDisposed: options.onStoreDisposed,\r\n onStateChange: options.onStateChange,\r\n }\r\n}\r\n\r\n/**\r\n * 创建插件工厂函数\r\n *\r\n * 用于创建可配置的插件\r\n *\r\n * @template Options - 插件选项类型\r\n * @param factory - 插件工厂函数\r\n * @returns 插件工厂\r\n *\r\n * @example\r\n * ```typescript\r\n * // 创建可配置的持久化插件\r\n * const createPersistPlugin = createPluginFactory<{ key: string }>(\r\n * (options) => ({\r\n * name: 'persist',\r\n * install(context) {\r\n * console.log('Persist key:', options?.key)\r\n * },\r\n * })\r\n * )\r\n *\r\n * // 使用\r\n * const plugin = createPersistPlugin({ key: 'my-store' })\r\n * ```\r\n */\r\nexport function createPluginFactory<Options = Record<string, unknown>>(\r\n factory: (options?: Options) => DefinePluginOptions<Options>\r\n): PluginFactory<Options> {\r\n return (options?: Options): StorePlugin<Options> => {\r\n return defineStorePlugin(factory(options))\r\n }\r\n}\r\n\r\n/**\r\n * 组合多个插件\r\n *\r\n * @param plugins - 插件列表\r\n * @returns 组合后的插件\r\n *\r\n * @example\r\n * ```typescript\r\n * const combinedPlugin = composePlugins([\r\n * loggerPlugin,\r\n * persistPlugin,\r\n * devtoolsPlugin,\r\n * ])\r\n * ```\r\n */\r\nexport function composePlugins(plugins: StorePlugin[]): StorePlugin {\r\n return {\r\n name: 'composed-plugins',\r\n version: '0.0.1',\r\n\r\n async install(context, options) {\r\n for (const plugin of plugins) {\r\n await plugin.install(context, options)\r\n }\r\n },\r\n\r\n async uninstall(context) {\r\n // 逆序卸载\r\n for (let i = plugins.length - 1; i >= 0; i--) {\r\n await plugins[i].uninstall?.(context)\r\n }\r\n },\r\n\r\n onStoreCreated(store) {\r\n plugins.forEach(plugin => plugin.onStoreCreated?.(store))\r\n },\r\n\r\n onStoreDisposed(store) {\r\n plugins.forEach(plugin => plugin.onStoreDisposed?.(store))\r\n },\r\n\r\n onStateChange(storeId, state, oldState) {\r\n plugins.forEach(plugin =>\r\n plugin.onStateChange?.(storeId, state, oldState)\r\n )\r\n },\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;AAgCO,SAAS,kBACd,SACsB;CACtB,OAAO;EACL,MAAM,QAAQ;EACd,SAAS,QAAQ;EACjB,aAAa,QAAQ;EACrB,SAAS,QAAQ;EACjB,WAAW,QAAQ;EACnB,gBAAgB,QAAQ;EACxB,iBAAiB,QAAQ;EACzB,eAAe,QAAQ;CACzB;AACF;AA2BO,SAAS,oBACd,SACwB;CACxB,QAAQ,YAA4C;EAClD,OAAO,kBAAkB,QAAQ,OAAO,CAAC;CAC3C;AACF;AAiBO,SAAS,eAAe,SAAqC;CAClE,OAAO;EACL,MAAM;EACN,SAAS;EAET,MAAM,QAAQ,SAAS,SAAS;GAC9B,KAAA,MAAW,UAAU,SACnB,MAAM,OAAO,QAAQ,SAAS,OAAO;EAEzC;EAEA,MAAM,UAAU,SAAS;GAEvB,KAAA,IAAS,IAAI,QAAQ,SAAS,GAAG,KAAK,GAAG,KACvC,MAAM,QAAQ,EAAC,CAAE,YAAY,OAAO;EAExC;EAEA,eAAe,OAAO;GACpB,QAAQ,SAAQ,WAAU,OAAO,iBAAiB,KAAK,CAAC;EAC1D;EAEA,gBAAgB,OAAO;GACrB,QAAQ,SAAQ,WAAU,OAAO,kBAAkB,KAAK,CAAC;EAC3D;EAEA,cAAc,SAAS,OAAO,UAAU;GACtC,QAAQ,SAAQ,WACd,OAAO,gBAAgB,SAAS,OAAO,QAAQ,CACjD;EACF;CACF;AACF"}
@@ -2,57 +2,80 @@
2
2
  * ***********************************
3
3
  * @composy/store-core v0.0.1 *
4
4
  * Built with rollup *
5
- * Build time: 2024-08-17 11:27:33 *
5
+ * Build time: 2024-10-12 17:23:58 *
6
6
  * Build mode: production *
7
7
  * Minified: No *
8
8
  * ***********************************
9
9
  */
10
10
  //#region src/plugins/plugin-manager.ts
11
+ function reportPluginError(action, name, error) {
12
+ console.error(`[Plugin] ${action} failed for "${name}":`, error);
13
+ }
11
14
  function createPluginManager() {
12
15
  const plugins = /* @__PURE__ */ new Map();
13
16
  const contexts = /* @__PURE__ */ new Map();
17
+ const stores = /* @__PURE__ */ new Map();
18
+ const storeManager = {
19
+ getStore: (id) => stores.get(id),
20
+ hasStore: (id) => stores.has(id),
21
+ getStoreIds: () => Array.from(stores.keys())
22
+ };
23
+ const createContext = (options) => ({
24
+ storeManager,
25
+ storeId: "",
26
+ store: null,
27
+ options: options || {}
28
+ });
14
29
  const use = (plugin, options) => {
15
- if (plugins.has(plugin.name)) console.warn(`[Plugin] \u63D2\u4EF6 "${plugin.name}" \u5DF2\u5B58\u5728\uFF0C\u5C06\u88AB\u8986\u76D6`);
30
+ const previous = plugins.get(plugin.name);
31
+ const previousContext = contexts.get(plugin.name);
32
+ if (previous && previousContext) Promise.resolve(previous.uninstall?.(previousContext)).catch((error) => {
33
+ reportPluginError("uninstall", plugin.name, error);
34
+ });
35
+ const context = createContext(options);
16
36
  plugins.set(plugin.name, plugin);
17
- const context = {
18
- storeManager: {
19
- getStore: () => null,
20
- hasStore: () => false,
21
- getStoreIds: () => []
22
- },
23
- storeId: "",
24
- store: null,
25
- options: options || {}
26
- };
27
37
  contexts.set(plugin.name, context);
38
+ Promise.resolve(plugin.install(context, options)).catch((error) => {
39
+ reportPluginError("install", plugin.name, error);
40
+ });
41
+ stores.forEach((store) => plugin.onStoreCreated?.(store));
28
42
  };
29
43
  const remove = (name) => {
30
44
  const plugin = plugins.get(name);
31
45
  const context = contexts.get(name);
32
- if (plugin && context) plugin.uninstall?.(context);
46
+ if (plugin && context) Promise.resolve(plugin.uninstall?.(context)).catch((error) => {
47
+ reportPluginError("uninstall", name, error);
48
+ });
33
49
  plugins.delete(name);
34
50
  contexts.delete(name);
35
51
  };
36
- const get = (name) => {
37
- return plugins.get(name);
38
- };
39
- const has = (name) => {
40
- return plugins.has(name);
41
- };
42
- const getAll = () => {
43
- return new Map(plugins);
44
- };
45
- const size = () => {
46
- return plugins.size;
47
- };
52
+ const get = (name) => plugins.get(name);
53
+ const has = (name) => plugins.has(name);
54
+ const getAll = () => new Map(plugins);
55
+ const size = () => plugins.size;
48
56
  const clear = () => {
49
57
  plugins.forEach((plugin, name) => {
50
58
  const context = contexts.get(name);
51
- if (context) plugin.uninstall?.(context);
59
+ if (context) Promise.resolve(plugin.uninstall?.(context)).catch((error) => {
60
+ reportPluginError("uninstall", name, error);
61
+ });
52
62
  });
53
63
  plugins.clear();
54
64
  contexts.clear();
55
65
  };
66
+ const notifyStoreCreated = (store) => {
67
+ const id = readStoreId(store);
68
+ if (id) stores.set(id, store);
69
+ plugins.forEach((plugin) => plugin.onStoreCreated?.(store));
70
+ };
71
+ const notifyStoreDisposed = (store) => {
72
+ const id = readStoreId(store);
73
+ if (id) stores.delete(id);
74
+ plugins.forEach((plugin) => plugin.onStoreDisposed?.(store));
75
+ };
76
+ const notifyStateChange = (storeId, state, oldState) => {
77
+ plugins.forEach((plugin) => plugin.onStateChange?.(storeId, state, oldState));
78
+ };
56
79
  return {
57
80
  use,
58
81
  remove,
@@ -60,9 +83,17 @@ function createPluginManager() {
60
83
  has,
61
84
  getAll,
62
85
  size,
63
- clear
86
+ clear,
87
+ notifyStoreCreated,
88
+ notifyStoreDisposed,
89
+ notifyStateChange
64
90
  };
65
91
  }
92
+ function readStoreId(store) {
93
+ if (!store || typeof store !== "object") return void 0;
94
+ const id = store.$id;
95
+ return typeof id === "string" ? id : void 0;
96
+ }
66
97
  let globalPluginManager = null;
67
98
  function getGlobalPluginManager() {
68
99
  if (!globalPluginManager) globalPluginManager = createPluginManager();
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-manager.js","names":[],"sources":["../../src/plugins/plugin-manager.ts"],"sourcesContent":["/**\n * 插件管理器\n *\n * @module plugins/plugin-manager\n */\n\nimport type { PluginContext, PluginManager, StorePlugin } from '../types'\n\n/**\n * 创建插件管理器\n *\n * @returns 插件管理器实例\n *\n * @example\n * ```typescript\n * const manager = createPluginManager()\n *\n * // 注册插件\n * manager.use(myPlugin, { option: 'value' })\n *\n * // 获取插件\n * const plugin = manager.get('my-plugin')\n *\n * // 移除插件\n * manager.remove('my-plugin')\n * ```\n */\nexport function createPluginManager(): PluginManager {\n /** 已注册的插件 */\n const plugins = new Map<string, StorePlugin>()\n\n /** 插件上下文缓存 */\n const contexts = new Map<string, PluginContext>()\n\n /**\n * 注册插件\n */\n const use = <Options>(\n plugin: StorePlugin<Options>,\n options?: Options,\n ): void => {\n if (plugins.has(plugin.name)) {\n console.warn(`[Plugin] 插件 \"${plugin.name}\" 已存在,将被覆盖`)\n }\n\n plugins.set(plugin.name, plugin as StorePlugin)\n\n // 创建插件上下文\n const context: PluginContext = {\n storeManager: {\n getStore: () => null,\n hasStore: () => false,\n getStoreIds: () => [],\n },\n storeId: '',\n store: null,\n options: (options || {}) as Record<string, unknown>,\n }\n\n contexts.set(plugin.name, context)\n }\n\n /**\n * 移除插件\n */\n const remove = (name: string): void => {\n const plugin = plugins.get(name)\n const context = contexts.get(name)\n\n if (plugin && context) {\n // 调用卸载钩子\n plugin.uninstall?.(context)\n }\n\n plugins.delete(name)\n contexts.delete(name)\n }\n\n /**\n * 获取插件\n */\n const get = (name: string): StorePlugin | undefined => {\n return plugins.get(name)\n }\n\n /**\n * 是否已注册插件\n */\n const has = (name: string): boolean => {\n return plugins.has(name)\n }\n\n /**\n * 获取所有插件\n */\n const getAll = (): Map<string, StorePlugin> => {\n return new Map(plugins)\n }\n\n /**\n * 获取插件数量\n */\n const size = (): number => {\n return plugins.size\n }\n\n /**\n * 清空所有插件\n */\n const clear = (): void => {\n // 调用所有插件的卸载钩子\n plugins.forEach((plugin, name) => {\n const context = contexts.get(name)\n if (context) {\n plugin.uninstall?.(context)\n }\n })\n\n plugins.clear()\n contexts.clear()\n }\n\n return {\n use,\n remove,\n get,\n has,\n getAll,\n size,\n clear,\n }\n}\n\n/**\n * 全局插件管理器\n */\nlet globalPluginManager: PluginManager | null = null\n\n/**\n * 获取全局插件管理器\n */\nexport function getGlobalPluginManager(): PluginManager {\n if (!globalPluginManager) {\n globalPluginManager = createPluginManager()\n }\n return globalPluginManager\n}\n\n/**\n * 设置全局插件管理器\n */\nexport function setGlobalPluginManager(manager: PluginManager): void {\n globalPluginManager = manager\n}\n\n"],"mappings":";;;;;;;;;;AA2BO,SAAS,sBAAqC;CAEnD,MAAM,0BAAU,IAAI,IAAyB;CAG7C,MAAM,2BAAW,IAAI,IAA2B;CAKhD,MAAM,OACJ,QACA,YACS;EACT,IAAI,QAAQ,IAAI,OAAO,IAAI,GACzB,QAAQ,KAAK,0BAAgB,OAAO,KAAI,mDAAY;EAGtD,QAAQ,IAAI,OAAO,MAAM,MAAqB;EAG9C,MAAM,UAAyB;GAC7B,cAAc;IACZ,gBAAgB;IAChB,gBAAgB;IAChB,mBAAmB,CAAC;GACtB;GACA,SAAS;GACT,OAAO;GACP,SAAU,WAAW,CAAC;EACxB;EAEA,SAAS,IAAI,OAAO,MAAM,OAAO;CACnC;CAKA,MAAM,UAAU,SAAuB;EACrC,MAAM,SAAS,QAAQ,IAAI,IAAI;EAC/B,MAAM,UAAU,SAAS,IAAI,IAAI;EAEjC,IAAI,UAAU,SAEZ,OAAO,YAAY,OAAO;EAG5B,QAAQ,OAAO,IAAI;EACnB,SAAS,OAAO,IAAI;CACtB;CAKA,MAAM,OAAO,SAA0C;EACrD,OAAO,QAAQ,IAAI,IAAI;CACzB;CAKA,MAAM,OAAO,SAA0B;EACrC,OAAO,QAAQ,IAAI,IAAI;CACzB;CAKA,MAAM,eAAyC;EAC7C,OAAO,IAAI,IAAI,OAAO;CACxB;CAKA,MAAM,aAAqB;EACzB,OAAO,QAAQ;CACjB;CAKA,MAAM,cAAoB;EAExB,QAAQ,SAAS,QAAQ,SAAS;GAChC,MAAM,UAAU,SAAS,IAAI,IAAI;GACjC,IAAI,SACF,OAAO,YAAY,OAAO;EAE9B,CAAC;EAED,QAAQ,MAAM;EACd,SAAS,MAAM;CACjB;CAEA,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF;AAKA,IAAI,sBAA4C;AAKzC,SAAS,yBAAwC;CACtD,IAAI,CAAC,qBACH,sBAAsB,oBAAoB;CAE5C,OAAO;AACT;AAKO,SAAS,uBAAuB,SAA8B;CACnE,sBAAsB;AACxB"}
1
+ {"version":3,"file":"plugin-manager.js","names":[],"sources":["../../src/plugins/plugin-manager.ts"],"sourcesContent":["/** Store plugin registry and lifecycle host. */\n\nimport type {\n PluginContext,\n PluginManager,\n StateTree,\n StoreId,\n StorePlugin,\n} from '../types'\n\nfunction reportPluginError(action: string, name: string, error: unknown): void {\n console.error(`[Plugin] ${action} failed for \"${name}\":`, error)\n}\n\nexport function createPluginManager(): PluginManager {\n const plugins = new Map<string, StorePlugin>()\n const contexts = new Map<string, PluginContext>()\n const stores = new Map<StoreId, unknown>()\n\n const storeManager = {\n getStore: (id: StoreId): unknown => stores.get(id),\n hasStore: (id: StoreId): boolean => stores.has(id),\n getStoreIds: (): StoreId[] => Array.from(stores.keys()),\n }\n\n const createContext = <Options>(options?: Options): PluginContext => ({\n storeManager,\n storeId: '',\n store: null,\n options: (options || {}) as Record<string, unknown>,\n })\n\n const use = <Options>(\n plugin: StorePlugin<Options>,\n options?: Options\n ): void => {\n const previous = plugins.get(plugin.name)\n const previousContext = contexts.get(plugin.name)\n if (previous && previousContext) {\n void Promise.resolve(previous.uninstall?.(previousContext)).catch(\n error => {\n reportPluginError('uninstall', plugin.name, error)\n }\n )\n }\n\n const context = createContext(options)\n plugins.set(plugin.name, plugin as StorePlugin)\n contexts.set(plugin.name, context)\n\n void Promise.resolve(plugin.install(context, options)).catch(error => {\n reportPluginError('install', plugin.name, error)\n })\n\n stores.forEach(store => plugin.onStoreCreated?.(store))\n }\n\n const remove = (name: string): void => {\n const plugin = plugins.get(name)\n const context = contexts.get(name)\n if (plugin && context) {\n void Promise.resolve(plugin.uninstall?.(context)).catch(error => {\n reportPluginError('uninstall', name, error)\n })\n }\n plugins.delete(name)\n contexts.delete(name)\n }\n\n const get = (name: string): StorePlugin | undefined => plugins.get(name)\n const has = (name: string): boolean => plugins.has(name)\n const getAll = (): Map<string, StorePlugin> => new Map(plugins)\n const size = (): number => plugins.size\n\n const clear = (): void => {\n plugins.forEach((plugin, name) => {\n const context = contexts.get(name)\n if (context) {\n void Promise.resolve(plugin.uninstall?.(context)).catch(error => {\n reportPluginError('uninstall', name, error)\n })\n }\n })\n plugins.clear()\n contexts.clear()\n }\n\n const notifyStoreCreated = (store: unknown): void => {\n const id = readStoreId(store)\n if (id) stores.set(id, store)\n plugins.forEach(plugin => plugin.onStoreCreated?.(store))\n }\n\n const notifyStoreDisposed = (store: unknown): void => {\n const id = readStoreId(store)\n if (id) stores.delete(id)\n plugins.forEach(plugin => plugin.onStoreDisposed?.(store))\n }\n\n const notifyStateChange = <S extends StateTree>(\n storeId: StoreId,\n state: S,\n oldState: S\n ): void => {\n plugins.forEach(plugin => plugin.onStateChange?.(storeId, state, oldState))\n }\n\n return {\n use,\n remove,\n get,\n has,\n getAll,\n size,\n clear,\n notifyStoreCreated,\n notifyStoreDisposed,\n notifyStateChange,\n }\n}\n\nfunction readStoreId(store: unknown): StoreId | undefined {\n if (!store || typeof store !== 'object') return undefined\n const id = (store as { $id?: unknown }).$id\n return typeof id === 'string' ? id : undefined\n}\n\nlet globalPluginManager: PluginManager | null = null\n\nexport function getGlobalPluginManager(): PluginManager {\n if (!globalPluginManager) {\n globalPluginManager = createPluginManager()\n }\n return globalPluginManager\n}\n\nexport function setGlobalPluginManager(manager: PluginManager): void {\n globalPluginManager = manager\n}\n"],"mappings":";;;;;;;;;;AAUA,SAAS,kBAAkB,QAAgB,MAAc,OAAsB;CAC7E,QAAQ,MAAM,YAAY,OAAM,eAAgB,KAAI,KAAM,KAAK;AACjE;AAEO,SAAS,sBAAqC;CACnD,MAAM,0BAAU,IAAI,IAAyB;CAC7C,MAAM,2BAAW,IAAI,IAA2B;CAChD,MAAM,yBAAS,IAAI,IAAsB;CAEzC,MAAM,eAAe;EACnB,WAAW,OAAyB,OAAO,IAAI,EAAE;EACjD,WAAW,OAAyB,OAAO,IAAI,EAAE;EACjD,mBAA8B,MAAM,KAAK,OAAO,KAAK,CAAC;CACxD;CAEA,MAAM,iBAA0B,aAAsC;EACpE;EACA,SAAS;EACT,OAAO;EACP,SAAU,WAAW,CAAC;CACxB;CAEA,MAAM,OACJ,QACA,YACS;EACT,MAAM,WAAW,QAAQ,IAAI,OAAO,IAAI;EACxC,MAAM,kBAAkB,SAAS,IAAI,OAAO,IAAI;EAChD,IAAI,YAAY,iBACd,QAAa,QAAQ,SAAS,YAAY,eAAe,CAAC,CAAA,CAAE,OAC1D,UAAS;GACP,kBAAkB,aAAa,OAAO,MAAM,KAAK;EACnD,CACF;EAGF,MAAM,UAAU,cAAc,OAAO;EACrC,QAAQ,IAAI,OAAO,MAAM,MAAqB;EAC9C,SAAS,IAAI,OAAO,MAAM,OAAO;EAEjC,QAAa,QAAQ,OAAO,QAAQ,SAAS,OAAO,CAAC,CAAA,CAAE,OAAM,UAAS;GACpE,kBAAkB,WAAW,OAAO,MAAM,KAAK;EACjD,CAAC;EAED,OAAO,SAAQ,UAAS,OAAO,iBAAiB,KAAK,CAAC;CACxD;CAEA,MAAM,UAAU,SAAuB;EACrC,MAAM,SAAS,QAAQ,IAAI,IAAI;EAC/B,MAAM,UAAU,SAAS,IAAI,IAAI;EACjC,IAAI,UAAU,SACZ,QAAa,QAAQ,OAAO,YAAY,OAAO,CAAC,CAAA,CAAE,OAAM,UAAS;GAC/D,kBAAkB,aAAa,MAAM,KAAK;EAC5C,CAAC;EAEH,QAAQ,OAAO,IAAI;EACnB,SAAS,OAAO,IAAI;CACtB;CAEA,MAAM,OAAO,SAA0C,QAAQ,IAAI,IAAI;CACvE,MAAM,OAAO,SAA0B,QAAQ,IAAI,IAAI;CACvD,MAAM,eAAyC,IAAI,IAAI,OAAO;CAC9D,MAAM,aAAqB,QAAQ;CAEnC,MAAM,cAAoB;EACxB,QAAQ,SAAS,QAAQ,SAAS;GAChC,MAAM,UAAU,SAAS,IAAI,IAAI;GACjC,IAAI,SACF,QAAa,QAAQ,OAAO,YAAY,OAAO,CAAC,CAAA,CAAE,OAAM,UAAS;IAC/D,kBAAkB,aAAa,MAAM,KAAK;GAC5C,CAAC;EAEL,CAAC;EACD,QAAQ,MAAM;EACd,SAAS,MAAM;CACjB;CAEA,MAAM,sBAAsB,UAAyB;EACnD,MAAM,KAAK,YAAY,KAAK;EAC5B,IAAI,IAAI,OAAO,IAAI,IAAI,KAAK;EAC5B,QAAQ,SAAQ,WAAU,OAAO,iBAAiB,KAAK,CAAC;CAC1D;CAEA,MAAM,uBAAuB,UAAyB;EACpD,MAAM,KAAK,YAAY,KAAK;EAC5B,IAAI,IAAI,OAAO,OAAO,EAAE;EACxB,QAAQ,SAAQ,WAAU,OAAO,kBAAkB,KAAK,CAAC;CAC3D;CAEA,MAAM,qBACJ,SACA,OACA,aACS;EACT,QAAQ,SAAQ,WAAU,OAAO,gBAAgB,SAAS,OAAO,QAAQ,CAAC;CAC5E;CAEA,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF;AAEA,SAAS,YAAY,OAAqC;CACxD,IAAI,CAAC,SAAS,OAAO,UAAU,UAAU,OAAO,KAAA;CAChD,MAAM,KAAM,MAA4B;CACxC,OAAO,OAAO,OAAO,WAAW,KAAK,KAAA;AACvC;AAEA,IAAI,sBAA4C;AAEzC,SAAS,yBAAwC;CACtD,IAAI,CAAC,qBACH,sBAAsB,oBAAoB;CAE5C,OAAO;AACT;AAEO,SAAS,uBAAuB,SAA8B;CACnE,sBAAsB;AACxB"}
@@ -2,7 +2,7 @@
2
2
  * ***********************************
3
3
  * @composy/store-core v0.0.1 *
4
4
  * Built with rollup *
5
- * Build time: 2024-08-17 11:27:33 *
5
+ * Build time: 2024-10-12 17:23:58 *
6
6
  * Build mode: production *
7
7
  * Minified: No *
8
8
  * ***********************************
@@ -1 +1 @@
1
- {"version":3,"file":"debounce-throttle.js","names":[],"sources":["../../src/utils/debounce-throttle.ts"],"sourcesContent":["/**\n * 防抖和节流工具函数\n *\n * 提供性能优化的防抖、节流功能\n * @module utils/debounce-throttle\n */\n\n/**\n * 防抖函数返回类型\n */\nexport interface DebouncedFunction<T extends (...args: never[]) => void> {\n (...args: Parameters<T>): void\n /** 取消待执行的调用 */\n cancel: () => void\n /** 立即执行待处理的调用 */\n flush: () => void\n /** 是否有待处理的调用 */\n pending: () => boolean\n}\n\n/**\n * 节流函数返回类型\n */\nexport interface ThrottledFunction<T extends (...args: never[]) => void> {\n (...args: Parameters<T>): void\n /** 取消待执行的调用 */\n cancel: () => void\n}\n\n/**\n * 创建防抖函数\n *\n * 在连续调用停止后,延迟指定时间执行函数\n *\n * @template T - 函数类型\n * @param fn - 需要防抖的函数\n * @param delay - 延迟时间(毫秒)\n * @param immediate - 是否在首次调用时立即执行\n * @returns 防抖后的函数\n *\n * @example\n * ```typescript\n * const debouncedSearch = debounce((query: string) => {\n * fetchResults(query)\n * }, 300)\n *\n * // 连续调用只会在最后一次调用后 300ms 执行\n * debouncedSearch('a')\n * debouncedSearch('ab')\n * debouncedSearch('abc') // 只有这次会触发\n *\n * // 取消待执行的调用\n * debouncedSearch.cancel()\n * ```\n */\nexport function debounce<T extends (...args: never[]) => void>(\n fn: T,\n delay: number,\n immediate = false,\n): DebouncedFunction<T> {\n let timer: ReturnType<typeof setTimeout> | null = null\n let lastArgs: Parameters<T> | null = null\n\n const debounced = ((...args: Parameters<T>) => {\n lastArgs = args\n\n if (timer) {\n clearTimeout(timer)\n }\n\n if (immediate && !timer) {\n fn(...args)\n timer = setTimeout(() => {\n timer = null\n lastArgs = null\n }, delay)\n }\n else {\n timer = setTimeout(() => {\n fn(...args)\n timer = null\n lastArgs = null\n }, delay)\n }\n }) as DebouncedFunction<T>\n\n debounced.cancel = () => {\n if (timer) {\n clearTimeout(timer)\n timer = null\n lastArgs = null\n }\n }\n\n debounced.flush = () => {\n if (timer && lastArgs) {\n clearTimeout(timer)\n fn(...lastArgs)\n timer = null\n lastArgs = null\n }\n }\n\n debounced.pending = () => timer !== null\n\n return debounced\n}\n\n/**\n * 创建节流函数\n *\n * 在指定时间间隔内最多执行一次函数\n *\n * @template T - 函数类型\n * @param fn - 需要节流的函数\n * @param interval - 间隔时间(毫秒)\n * @param options - 节流选项\n * @param options.leading - 是否在时间窗开始时立即执行\n * @param options.trailing - 是否在时间窗结束时补执行最后一次调用\n * @returns 节流后的函数\n *\n * @example\n * ```typescript\n * const throttledUpdate = throttle((x: number, y: number) => {\n * updatePosition(x, y)\n * }, 100)\n *\n * // 在 100ms 内多次调用,只会执行一次\n * window.addEventListener('mousemove', (e) => {\n * throttledUpdate(e.clientX, e.clientY)\n * })\n *\n * // 取消\n * throttledUpdate.cancel()\n * ```\n */\nexport function throttle<T extends (...args: never[]) => void>(\n fn: T,\n interval: number,\n options: { leading?: boolean, trailing?: boolean } = {},\n): ThrottledFunction<T> {\n const { leading = true, trailing = true } = options\n let timer: ReturnType<typeof setTimeout> | null = null\n let lastTime = 0\n let lastArgs: Parameters<T> | null = null\n\n const throttled = ((...args: Parameters<T>) => {\n const now = Date.now()\n const remaining = interval - (now - lastTime)\n\n lastArgs = args\n\n if (remaining <= 0 || remaining > interval) {\n if (timer) {\n clearTimeout(timer)\n timer = null\n }\n lastTime = now\n if (leading || lastTime !== 0) {\n fn(...args)\n }\n lastArgs = null\n }\n else if (!timer && trailing) {\n timer = setTimeout(() => {\n lastTime = trailing ? Date.now() : 0\n timer = null\n if (lastArgs) {\n fn(...lastArgs)\n lastArgs = null\n }\n }, remaining)\n }\n }) as ThrottledFunction<T>\n\n throttled.cancel = () => {\n if (timer) {\n clearTimeout(timer)\n timer = null\n }\n lastTime = 0\n lastArgs = null\n }\n\n return throttled\n}\n"],"mappings":";;;;;;;;;;AAuDO,SAAS,SACd,IACA,OACA,YAAY,OACU;CACtB,IAAI,QAA8C;CAClD,IAAI,WAAiC;CAErC,MAAM,cAAa,GAAI,SAAwB;EAC7C,WAAW;EAEX,IAAI,OACF,aAAa,KAAK;EAGpB,IAAI,aAAa,CAAC,OAAO;GACvB,GAAG,GAAG,IAAI;GACV,QAAQ,iBAAiB;IACvB,QAAQ;IACR,WAAW;GACb,GAAG,KAAK;EACV,OAEE,QAAQ,iBAAiB;GACvB,GAAG,GAAG,IAAI;GACV,QAAQ;GACR,WAAW;EACb,GAAG,KAAK;CAEZ;CAEA,UAAU,eAAe;EACvB,IAAI,OAAO;GACT,aAAa,KAAK;GAClB,QAAQ;GACR,WAAW;EACb;CACF;CAEA,UAAU,cAAc;EACtB,IAAI,SAAS,UAAU;GACrB,aAAa,KAAK;GAClB,GAAG,GAAG,QAAQ;GACd,QAAQ;GACR,WAAW;EACb;CACF;CAEA,UAAU,gBAAgB,UAAU;CAEpC,OAAO;AACT;AA8BO,SAAS,SACd,IACA,UACA,UAAqD,CAAC,GAChC;CACtB,MAAM,EAAE,UAAU,MAAM,WAAW,SAAS;CAC5C,IAAI,QAA8C;CAClD,IAAI,WAAW;CACf,IAAI,WAAiC;CAErC,MAAM,cAAa,GAAI,SAAwB;EAC7C,MAAM,MAAM,KAAK,IAAI;EACrB,MAAM,YAAY,YAAY,MAAM;EAEpC,WAAW;EAEX,IAAI,aAAa,KAAK,YAAY,UAAU;GAC1C,IAAI,OAAO;IACT,aAAa,KAAK;IAClB,QAAQ;GACV;GACA,WAAW;GACX,IAAI,WAAW,aAAa,GAC1B,GAAG,GAAG,IAAI;GAEZ,WAAW;EACb,OAAA,IACS,CAAC,SAAS,UACjB,QAAQ,iBAAiB;GACvB,WAAW,WAAW,KAAK,IAAI,IAAI;GACnC,QAAQ;GACR,IAAI,UAAU;IACZ,GAAG,GAAG,QAAQ;IACd,WAAW;GACb;EACF,GAAG,SAAS;CAEhB;CAEA,UAAU,eAAe;EACvB,IAAI,OAAO;GACT,aAAa,KAAK;GAClB,QAAQ;EACV;EACA,WAAW;EACX,WAAW;CACb;CAEA,OAAO;AACT"}
1
+ {"version":3,"file":"debounce-throttle.js","names":[],"sources":["../../src/utils/debounce-throttle.ts"],"sourcesContent":["/**\r\n * 防抖和节流工具函数\r\n *\r\n * 提供性能优化的防抖、节流功能\r\n * @module utils/debounce-throttle\r\n */\r\n\r\n/**\r\n * 防抖函数返回类型\r\n */\r\nexport interface DebouncedFunction<T extends (...args: never[]) => void> {\r\n (...args: Parameters<T>): void\r\n /** 取消待执行的调用 */\r\n cancel: () => void\r\n /** 立即执行待处理的调用 */\r\n flush: () => void\r\n /** 是否有待处理的调用 */\r\n pending: () => boolean\r\n}\r\n\r\n/**\r\n * 节流函数返回类型\r\n */\r\nexport interface ThrottledFunction<T extends (...args: never[]) => void> {\r\n (...args: Parameters<T>): void\r\n /** 取消待执行的调用 */\r\n cancel: () => void\r\n}\r\n\r\n/**\r\n * 创建防抖函数\r\n *\r\n * 在连续调用停止后,延迟指定时间执行函数\r\n *\r\n * @template T - 函数类型\r\n * @param fn - 需要防抖的函数\r\n * @param delay - 延迟时间(毫秒)\r\n * @param immediate - 是否在首次调用时立即执行\r\n * @returns 防抖后的函数\r\n *\r\n * @example\r\n * ```typescript\r\n * const debouncedSearch = debounce((query: string) => {\r\n * fetchResults(query)\r\n * }, 300)\r\n *\r\n * // 连续调用只会在最后一次调用后 300ms 执行\r\n * debouncedSearch('a')\r\n * debouncedSearch('ab')\r\n * debouncedSearch('abc') // 只有这次会触发\r\n *\r\n * // 取消待执行的调用\r\n * debouncedSearch.cancel()\r\n * ```\r\n */\r\nexport function debounce<T extends (...args: never[]) => void>(\r\n fn: T,\r\n delay: number,\r\n immediate = false\r\n): DebouncedFunction<T> {\r\n let timer: ReturnType<typeof setTimeout> | null = null\r\n let lastArgs: Parameters<T> | null = null\r\n\r\n const debounced = ((...args: Parameters<T>) => {\r\n lastArgs = args\r\n\r\n if (timer) {\r\n clearTimeout(timer)\r\n }\r\n\r\n if (immediate && !timer) {\r\n fn(...args)\r\n timer = setTimeout(() => {\r\n timer = null\r\n lastArgs = null\r\n }, delay)\r\n } else {\r\n timer = setTimeout(() => {\r\n fn(...args)\r\n timer = null\r\n lastArgs = null\r\n }, delay)\r\n }\r\n }) as DebouncedFunction<T>\r\n\r\n debounced.cancel = () => {\r\n if (timer) {\r\n clearTimeout(timer)\r\n timer = null\r\n lastArgs = null\r\n }\r\n }\r\n\r\n debounced.flush = () => {\r\n if (timer && lastArgs) {\r\n clearTimeout(timer)\r\n fn(...lastArgs)\r\n timer = null\r\n lastArgs = null\r\n }\r\n }\r\n\r\n debounced.pending = () => timer !== null\r\n\r\n return debounced\r\n}\r\n\r\n/**\r\n * 创建节流函数\r\n *\r\n * 在指定时间间隔内最多执行一次函数\r\n *\r\n * @template T - 函数类型\r\n * @param fn - 需要节流的函数\r\n * @param interval - 间隔时间(毫秒)\r\n * @param options - 节流选项\r\n * @param options.leading - 是否在时间窗开始时立即执行\r\n * @param options.trailing - 是否在时间窗结束时补执行最后一次调用\r\n * @returns 节流后的函数\r\n *\r\n * @example\r\n * ```typescript\r\n * const throttledUpdate = throttle((x: number, y: number) => {\r\n * updatePosition(x, y)\r\n * }, 100)\r\n *\r\n * // 在 100ms 内多次调用,只会执行一次\r\n * window.addEventListener('mousemove', (e) => {\r\n * throttledUpdate(e.clientX, e.clientY)\r\n * })\r\n *\r\n * // 取消\r\n * throttledUpdate.cancel()\r\n * ```\r\n */\r\nexport function throttle<T extends (...args: never[]) => void>(\r\n fn: T,\r\n interval: number,\r\n options: { leading?: boolean; trailing?: boolean } = {}\r\n): ThrottledFunction<T> {\r\n const { leading = true, trailing = true } = options\r\n let timer: ReturnType<typeof setTimeout> | null = null\r\n let lastTime = 0\r\n let lastArgs: Parameters<T> | null = null\r\n\r\n const throttled = ((...args: Parameters<T>) => {\r\n const now = Date.now()\r\n const remaining = interval - (now - lastTime)\r\n\r\n lastArgs = args\r\n\r\n if (remaining <= 0 || remaining > interval) {\r\n if (timer) {\r\n clearTimeout(timer)\r\n timer = null\r\n }\r\n lastTime = now\r\n if (leading || lastTime !== 0) {\r\n fn(...args)\r\n }\r\n lastArgs = null\r\n } else if (!timer && trailing) {\r\n timer = setTimeout(() => {\r\n lastTime = trailing ? Date.now() : 0\r\n timer = null\r\n if (lastArgs) {\r\n fn(...lastArgs)\r\n lastArgs = null\r\n }\r\n }, remaining)\r\n }\r\n }) as ThrottledFunction<T>\r\n\r\n throttled.cancel = () => {\r\n if (timer) {\r\n clearTimeout(timer)\r\n timer = null\r\n }\r\n lastTime = 0\r\n lastArgs = null\r\n }\r\n\r\n return throttled\r\n}\r\n"],"mappings":";;;;;;;;;;AAuDO,SAAS,SACd,IACA,OACA,YAAY,OACU;CACtB,IAAI,QAA8C;CAClD,IAAI,WAAiC;CAErC,MAAM,cAAa,GAAI,SAAwB;EAC7C,WAAW;EAEX,IAAI,OACF,aAAa,KAAK;EAGpB,IAAI,aAAa,CAAC,OAAO;GACvB,GAAG,GAAG,IAAI;GACV,QAAQ,iBAAiB;IACvB,QAAQ;IACR,WAAW;GACb,GAAG,KAAK;EACV,OACE,QAAQ,iBAAiB;GACvB,GAAG,GAAG,IAAI;GACV,QAAQ;GACR,WAAW;EACb,GAAG,KAAK;CAEZ;CAEA,UAAU,eAAe;EACvB,IAAI,OAAO;GACT,aAAa,KAAK;GAClB,QAAQ;GACR,WAAW;EACb;CACF;CAEA,UAAU,cAAc;EACtB,IAAI,SAAS,UAAU;GACrB,aAAa,KAAK;GAClB,GAAG,GAAG,QAAQ;GACd,QAAQ;GACR,WAAW;EACb;CACF;CAEA,UAAU,gBAAgB,UAAU;CAEpC,OAAO;AACT;AA8BO,SAAS,SACd,IACA,UACA,UAAqD,CAAC,GAChC;CACtB,MAAM,EAAE,UAAU,MAAM,WAAW,SAAS;CAC5C,IAAI,QAA8C;CAClD,IAAI,WAAW;CACf,IAAI,WAAiC;CAErC,MAAM,cAAa,GAAI,SAAwB;EAC7C,MAAM,MAAM,KAAK,IAAI;EACrB,MAAM,YAAY,YAAY,MAAM;EAEpC,WAAW;EAEX,IAAI,aAAa,KAAK,YAAY,UAAU;GAC1C,IAAI,OAAO;IACT,aAAa,KAAK;IAClB,QAAQ;GACV;GACA,WAAW;GACX,IAAI,WAAW,aAAa,GAC1B,GAAG,GAAG,IAAI;GAEZ,WAAW;EACb,OAAA,IAAW,CAAC,SAAS,UACnB,QAAQ,iBAAiB;GACvB,WAAW,WAAW,KAAK,IAAI,IAAI;GACnC,QAAQ;GACR,IAAI,UAAU;IACZ,GAAG,GAAG,QAAQ;IACd,WAAW;GACb;EACF,GAAG,SAAS;CAEhB;CAEA,UAAU,eAAe;EACvB,IAAI,OAAO;GACT,aAAa,KAAK;GAClB,QAAQ;EACV;EACA,WAAW;EACX,WAAW;CACb;CAEA,OAAO;AACT"}
@@ -2,7 +2,7 @@
2
2
  * ***********************************
3
3
  * @composy/store-core v0.0.1 *
4
4
  * Built with rollup *
5
- * Build time: 2024-08-17 11:27:33 *
5
+ * Build time: 2024-10-12 17:23:58 *
6
6
  * Build mode: production *
7
7
  * Minified: No *
8
8
  * ***********************************