@composy/store-core 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +172 -0
  3. package/dist/index.js +1852 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/index.min.js +1082 -0
  6. package/dist/index.min.js.map +1 -0
  7. package/es/core/async-action.d.ts +95 -0
  8. package/es/core/async-action.d.ts.map +1 -0
  9. package/es/core/async-action.js +116 -0
  10. package/es/core/async-action.js.map +1 -0
  11. package/es/core/base-store.d.ts +85 -0
  12. package/es/core/base-store.d.ts.map +1 -0
  13. package/es/core/base-store.js +185 -0
  14. package/es/core/base-store.js.map +1 -0
  15. package/es/core/batch-manager.d.ts +46 -0
  16. package/es/core/batch-manager.d.ts.map +1 -0
  17. package/es/core/batch-manager.js +64 -0
  18. package/es/core/batch-manager.js.map +1 -0
  19. package/es/core/create-store.d.ts +66 -0
  20. package/es/core/create-store.d.ts.map +1 -0
  21. package/es/core/create-store.js +29 -0
  22. package/es/core/create-store.js.map +1 -0
  23. package/es/core/event-bus.d.ts +34 -0
  24. package/es/core/event-bus.d.ts.map +1 -0
  25. package/es/core/event-bus.js +71 -0
  26. package/es/core/event-bus.js.map +1 -0
  27. package/es/core/index.d.ts +14 -0
  28. package/es/core/index.d.ts.map +1 -0
  29. package/es/core/index.js +17 -0
  30. package/es/core/pub-sub.d.ts +41 -0
  31. package/es/core/pub-sub.d.ts.map +1 -0
  32. package/es/core/pub-sub.js +71 -0
  33. package/es/core/pub-sub.js.map +1 -0
  34. package/es/engine/index.d.ts +10 -0
  35. package/es/engine/index.d.ts.map +1 -0
  36. package/es/engine/index.js +12 -0
  37. package/es/engine/plugin.d.ts +20 -0
  38. package/es/engine/plugin.d.ts.map +1 -0
  39. package/es/engine/plugin.js +153 -0
  40. package/es/engine/plugin.js.map +1 -0
  41. package/es/engine/types.d.ts +81 -0
  42. package/es/engine/types.d.ts.map +1 -0
  43. package/es/engine/types.js +10 -0
  44. package/es/errors/index.d.ts +208 -0
  45. package/es/errors/index.d.ts.map +1 -0
  46. package/es/errors/index.js +217 -0
  47. package/es/errors/index.js.map +1 -0
  48. package/es/index.d.ts +27 -0
  49. package/es/index.d.ts.map +1 -0
  50. package/es/index.js +34 -0
  51. package/es/index.js.map +1 -0
  52. package/es/middleware/index.d.ts +13 -0
  53. package/es/middleware/index.d.ts.map +1 -0
  54. package/es/middleware/index.js +16 -0
  55. package/es/middleware/logger.d.ts +67 -0
  56. package/es/middleware/logger.d.ts.map +1 -0
  57. package/es/middleware/logger.js +136 -0
  58. package/es/middleware/logger.js.map +1 -0
  59. package/es/middleware/middleware-manager.d.ts +40 -0
  60. package/es/middleware/middleware-manager.d.ts.map +1 -0
  61. package/es/middleware/middleware-manager.js +79 -0
  62. package/es/middleware/middleware-manager.js.map +1 -0
  63. package/es/middleware/persist.d.ts +34 -0
  64. package/es/middleware/persist.d.ts.map +1 -0
  65. package/es/middleware/persist.js +102 -0
  66. package/es/middleware/persist.js.map +1 -0
  67. package/es/middleware/time-travel.d.ts +30 -0
  68. package/es/middleware/time-travel.d.ts.map +1 -0
  69. package/es/middleware/time-travel.js +151 -0
  70. package/es/middleware/time-travel.js.map +1 -0
  71. package/es/middleware/validation.d.ts +100 -0
  72. package/es/middleware/validation.d.ts.map +1 -0
  73. package/es/middleware/validation.js +74 -0
  74. package/es/middleware/validation.js.map +1 -0
  75. package/es/plugins/define-plugin.d.ts +74 -0
  76. package/es/plugins/define-plugin.d.ts.map +1 -0
  77. package/es/plugins/define-plugin.js +52 -0
  78. package/es/plugins/define-plugin.js.map +1 -0
  79. package/es/plugins/index.d.ts +8 -0
  80. package/es/plugins/index.d.ts.map +1 -0
  81. package/es/plugins/index.js +13 -0
  82. package/es/plugins/plugin-manager.d.ts +35 -0
  83. package/es/plugins/plugin-manager.d.ts.map +1 -0
  84. package/es/plugins/plugin-manager.js +77 -0
  85. package/es/plugins/plugin-manager.js.map +1 -0
  86. package/es/types/index.d.ts +12 -0
  87. package/es/types/index.d.ts.map +1 -0
  88. package/es/types/index.js +10 -0
  89. package/es/types/middleware.d.ts +172 -0
  90. package/es/types/middleware.d.ts.map +1 -0
  91. package/es/types/middleware.js +10 -0
  92. package/es/types/plugin.d.ts +136 -0
  93. package/es/types/plugin.d.ts.map +1 -0
  94. package/es/types/plugin.js +10 -0
  95. package/es/types/store.d.ts +198 -0
  96. package/es/types/store.d.ts.map +1 -0
  97. package/es/types/store.js +10 -0
  98. package/es/types/subscription.d.ts +158 -0
  99. package/es/types/subscription.d.ts.map +1 -0
  100. package/es/types/subscription.js +10 -0
  101. package/es/types/utility.d.ts +312 -0
  102. package/es/types/utility.d.ts.map +1 -0
  103. package/es/types/utility.js +10 -0
  104. package/es/utils/debounce-throttle.d.ts +86 -0
  105. package/es/utils/debounce-throttle.d.ts.map +1 -0
  106. package/es/utils/debounce-throttle.js +86 -0
  107. package/es/utils/debounce-throttle.js.map +1 -0
  108. package/es/utils/deep-clone.d.ts +143 -0
  109. package/es/utils/deep-clone.d.ts.map +1 -0
  110. package/es/utils/deep-clone.js +193 -0
  111. package/es/utils/deep-clone.js.map +1 -0
  112. package/es/utils/index.d.ts +13 -0
  113. package/es/utils/index.d.ts.map +1 -0
  114. package/es/utils/index.js +14 -0
  115. package/es/utils/selector.d.ts +213 -0
  116. package/es/utils/selector.d.ts.map +1 -0
  117. package/es/utils/selector.js +151 -0
  118. package/es/utils/selector.js.map +1 -0
  119. package/esm/core/async-action.d.ts +95 -0
  120. package/esm/core/async-action.js +116 -0
  121. package/esm/core/async-action.js.map +1 -0
  122. package/esm/core/base-store.d.ts +85 -0
  123. package/esm/core/base-store.js +185 -0
  124. package/esm/core/base-store.js.map +1 -0
  125. package/esm/core/batch-manager.d.ts +46 -0
  126. package/esm/core/batch-manager.js +64 -0
  127. package/esm/core/batch-manager.js.map +1 -0
  128. package/esm/core/create-store.d.ts +66 -0
  129. package/esm/core/create-store.js +29 -0
  130. package/esm/core/create-store.js.map +1 -0
  131. package/esm/core/event-bus.d.ts +34 -0
  132. package/esm/core/event-bus.js +71 -0
  133. package/esm/core/event-bus.js.map +1 -0
  134. package/esm/core/index.d.ts +14 -0
  135. package/esm/core/index.js +17 -0
  136. package/esm/core/pub-sub.d.ts +41 -0
  137. package/esm/core/pub-sub.js +71 -0
  138. package/esm/core/pub-sub.js.map +1 -0
  139. package/esm/engine/index.d.ts +10 -0
  140. package/esm/engine/index.js +12 -0
  141. package/esm/engine/plugin.d.ts +20 -0
  142. package/esm/engine/plugin.js +153 -0
  143. package/esm/engine/plugin.js.map +1 -0
  144. package/esm/engine/types.d.ts +81 -0
  145. package/esm/errors/index.d.ts +208 -0
  146. package/esm/errors/index.js +217 -0
  147. package/esm/errors/index.js.map +1 -0
  148. package/esm/index.d.ts +27 -0
  149. package/esm/index.js +36 -0
  150. package/esm/index.js.map +1 -0
  151. package/esm/middleware/index.d.ts +13 -0
  152. package/esm/middleware/logger.d.ts +67 -0
  153. package/esm/middleware/logger.js +119 -0
  154. package/esm/middleware/logger.js.map +1 -0
  155. package/esm/middleware/middleware-manager.d.ts +40 -0
  156. package/esm/middleware/middleware-manager.js +79 -0
  157. package/esm/middleware/middleware-manager.js.map +1 -0
  158. package/esm/middleware/persist.d.ts +34 -0
  159. package/esm/middleware/persist.js +102 -0
  160. package/esm/middleware/persist.js.map +1 -0
  161. package/esm/middleware/time-travel.d.ts +30 -0
  162. package/esm/middleware/time-travel.js +151 -0
  163. package/esm/middleware/time-travel.js.map +1 -0
  164. package/esm/middleware/validation.d.ts +100 -0
  165. package/esm/middleware/validation.js +74 -0
  166. package/esm/middleware/validation.js.map +1 -0
  167. package/esm/plugins/define-plugin.d.ts +74 -0
  168. package/esm/plugins/define-plugin.js +52 -0
  169. package/esm/plugins/define-plugin.js.map +1 -0
  170. package/esm/plugins/index.d.ts +8 -0
  171. package/esm/plugins/plugin-manager.d.ts +35 -0
  172. package/esm/plugins/plugin-manager.js +77 -0
  173. package/esm/plugins/plugin-manager.js.map +1 -0
  174. package/esm/types/index.d.ts +12 -0
  175. package/esm/types/middleware.d.ts +172 -0
  176. package/esm/types/plugin.d.ts +136 -0
  177. package/esm/types/store.d.ts +198 -0
  178. package/esm/types/subscription.d.ts +158 -0
  179. package/esm/types/utility.d.ts +312 -0
  180. package/esm/utils/debounce-throttle.d.ts +86 -0
  181. package/esm/utils/debounce-throttle.js +86 -0
  182. package/esm/utils/debounce-throttle.js.map +1 -0
  183. package/esm/utils/deep-clone.d.ts +143 -0
  184. package/esm/utils/deep-clone.js +193 -0
  185. package/esm/utils/deep-clone.js.map +1 -0
  186. package/esm/utils/index.d.ts +13 -0
  187. package/esm/utils/selector.d.ts +213 -0
  188. package/esm/utils/selector.js +151 -0
  189. package/esm/utils/selector.js.map +1 -0
  190. package/lib/core/async-action.cjs +118 -0
  191. package/lib/core/async-action.cjs.map +1 -0
  192. package/lib/core/async-action.d.ts +95 -0
  193. package/lib/core/base-store.cjs +187 -0
  194. package/lib/core/base-store.cjs.map +1 -0
  195. package/lib/core/base-store.d.ts +85 -0
  196. package/lib/core/batch-manager.cjs +69 -0
  197. package/lib/core/batch-manager.cjs.map +1 -0
  198. package/lib/core/batch-manager.d.ts +46 -0
  199. package/lib/core/create-store.cjs +31 -0
  200. package/lib/core/create-store.cjs.map +1 -0
  201. package/lib/core/create-store.d.ts +66 -0
  202. package/lib/core/event-bus.cjs +74 -0
  203. package/lib/core/event-bus.cjs.map +1 -0
  204. package/lib/core/event-bus.d.ts +34 -0
  205. package/lib/core/index.cjs +29 -0
  206. package/lib/core/index.d.ts +14 -0
  207. package/lib/core/pub-sub.cjs +74 -0
  208. package/lib/core/pub-sub.cjs.map +1 -0
  209. package/lib/core/pub-sub.d.ts +41 -0
  210. package/lib/engine/index.cjs +16 -0
  211. package/lib/engine/index.d.ts +10 -0
  212. package/lib/engine/plugin.cjs +157 -0
  213. package/lib/engine/plugin.cjs.map +1 -0
  214. package/lib/engine/plugin.d.ts +20 -0
  215. package/lib/engine/types.cjs +12 -0
  216. package/lib/engine/types.d.ts +81 -0
  217. package/lib/errors/index.cjs +233 -0
  218. package/lib/errors/index.cjs.map +1 -0
  219. package/lib/errors/index.d.ts +208 -0
  220. package/lib/index.cjs +101 -0
  221. package/lib/index.cjs.map +1 -0
  222. package/lib/index.d.ts +27 -0
  223. package/lib/middleware/index.cjs +28 -0
  224. package/lib/middleware/index.d.ts +13 -0
  225. package/lib/middleware/logger.cjs +140 -0
  226. package/lib/middleware/logger.cjs.map +1 -0
  227. package/lib/middleware/logger.d.ts +67 -0
  228. package/lib/middleware/middleware-manager.cjs +83 -0
  229. package/lib/middleware/middleware-manager.cjs.map +1 -0
  230. package/lib/middleware/middleware-manager.d.ts +40 -0
  231. package/lib/middleware/persist.cjs +105 -0
  232. package/lib/middleware/persist.cjs.map +1 -0
  233. package/lib/middleware/persist.d.ts +34 -0
  234. package/lib/middleware/time-travel.cjs +154 -0
  235. package/lib/middleware/time-travel.cjs.map +1 -0
  236. package/lib/middleware/time-travel.d.ts +30 -0
  237. package/lib/middleware/validation.cjs +76 -0
  238. package/lib/middleware/validation.cjs.map +1 -0
  239. package/lib/middleware/validation.d.ts +100 -0
  240. package/lib/package.json +3 -0
  241. package/lib/plugins/define-plugin.cjs +56 -0
  242. package/lib/plugins/define-plugin.cjs.map +1 -0
  243. package/lib/plugins/define-plugin.d.ts +74 -0
  244. package/lib/plugins/index.cjs +20 -0
  245. package/lib/plugins/index.d.ts +8 -0
  246. package/lib/plugins/plugin-manager.cjs +81 -0
  247. package/lib/plugins/plugin-manager.cjs.map +1 -0
  248. package/lib/plugins/plugin-manager.d.ts +35 -0
  249. package/lib/types/index.cjs +12 -0
  250. package/lib/types/index.d.ts +12 -0
  251. package/lib/types/middleware.cjs +12 -0
  252. package/lib/types/middleware.d.ts +172 -0
  253. package/lib/types/plugin.cjs +12 -0
  254. package/lib/types/plugin.d.ts +136 -0
  255. package/lib/types/store.cjs +12 -0
  256. package/lib/types/store.d.ts +198 -0
  257. package/lib/types/subscription.cjs +12 -0
  258. package/lib/types/subscription.d.ts +158 -0
  259. package/lib/types/utility.cjs +12 -0
  260. package/lib/types/utility.d.ts +312 -0
  261. package/lib/utils/debounce-throttle.cjs +89 -0
  262. package/lib/utils/debounce-throttle.cjs.map +1 -0
  263. package/lib/utils/debounce-throttle.d.ts +86 -0
  264. package/lib/utils/deep-clone.cjs +202 -0
  265. package/lib/utils/deep-clone.cjs.map +1 -0
  266. package/lib/utils/deep-clone.d.ts +143 -0
  267. package/lib/utils/index.cjs +34 -0
  268. package/lib/utils/index.d.ts +13 -0
  269. package/lib/utils/selector.cjs +161 -0
  270. package/lib/utils/selector.cjs.map +1 -0
  271. package/lib/utils/selector.d.ts +213 -0
  272. package/package.json +155 -0
@@ -0,0 +1,118 @@
1
+ /*!
2
+ * ***********************************
3
+ * @composy/store-core v0.0.1 *
4
+ * Built with rollup *
5
+ * Build time: 2024-08-17 11:27:33 *
6
+ * Build mode: production *
7
+ * Minified: No *
8
+ * ***********************************
9
+ */
10
+ "use strict";
11
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
12
+ const require_pub_sub = require("./pub-sub.cjs");
13
+ //#region src/core/async-action.ts
14
+ function delay(ms) {
15
+ return new Promise((resolve) => setTimeout(resolve, ms));
16
+ }
17
+ function createAsyncAction(fn, options = {}) {
18
+ const { retryCount = 0, retryDelay = 1e3, timeout = 0, resetOnExecute = true } = options;
19
+ const _state = {
20
+ data: null,
21
+ error: null,
22
+ loading: false,
23
+ executionCount: 0,
24
+ lastExecutedAt: null
25
+ };
26
+ const statePubSub = require_pub_sub.createPubSub();
27
+ const successPubSub = require_pub_sub.createPubSub();
28
+ const errorPubSub = require_pub_sub.createPubSub();
29
+ let abortController = null;
30
+ const notify = () => {
31
+ statePubSub.publish({ ..._state });
32
+ };
33
+ const executeWithRetry = async (args, retriesLeft) => {
34
+ try {
35
+ return await fn(...args);
36
+ } catch (error) {
37
+ if (retriesLeft > 0 && !abortController?.signal.aborted) {
38
+ await delay(retryDelay);
39
+ if (abortController?.signal.aborted) throw new Error("Aborted");
40
+ return executeWithRetry(args, retriesLeft - 1);
41
+ }
42
+ throw error;
43
+ }
44
+ };
45
+ const execute = async (...args) => {
46
+ if (abortController) abortController.abort();
47
+ abortController = new AbortController();
48
+ if (resetOnExecute) _state.error = null;
49
+ _state.loading = true;
50
+ _state.executionCount++;
51
+ _state.lastExecutedAt = Date.now();
52
+ notify();
53
+ try {
54
+ let result;
55
+ if (timeout > 0) {
56
+ const timeoutPromise = new Promise((_, reject) => {
57
+ setTimeout(() => reject(/* @__PURE__ */ new Error(`Timeout after ${timeout}ms`)), timeout);
58
+ });
59
+ result = await Promise.race([executeWithRetry(args, retryCount), timeoutPromise]);
60
+ } else result = await executeWithRetry(args, retryCount);
61
+ if (!abortController.signal.aborted) {
62
+ _state.data = result;
63
+ _state.error = null;
64
+ _state.loading = false;
65
+ notify();
66
+ successPubSub.publish(result);
67
+ }
68
+ return result;
69
+ } catch (error) {
70
+ if (!abortController.signal.aborted) {
71
+ const err = error instanceof Error ? error : new Error(String(error));
72
+ _state.error = err;
73
+ _state.loading = false;
74
+ notify();
75
+ errorPubSub.publish(err);
76
+ }
77
+ throw error;
78
+ }
79
+ };
80
+ const reset = () => {
81
+ if (abortController) {
82
+ abortController.abort();
83
+ abortController = null;
84
+ }
85
+ _state.data = null;
86
+ _state.error = null;
87
+ _state.loading = false;
88
+ _state.executionCount = 0;
89
+ _state.lastExecutedAt = null;
90
+ notify();
91
+ };
92
+ const abort = () => {
93
+ if (abortController) {
94
+ abortController.abort();
95
+ abortController = null;
96
+ }
97
+ if (_state.loading) {
98
+ _state.loading = false;
99
+ _state.error = /* @__PURE__ */ new Error("Aborted");
100
+ notify();
101
+ }
102
+ };
103
+ return {
104
+ get state() {
105
+ return { ..._state };
106
+ },
107
+ execute,
108
+ reset,
109
+ abort,
110
+ subscribe: (callback) => statePubSub.subscribe(callback),
111
+ onSuccess: (callback) => successPubSub.subscribe(callback),
112
+ onError: (callback) => errorPubSub.subscribe(callback)
113
+ };
114
+ }
115
+ //#endregion
116
+ exports.createAsyncAction = createAsyncAction;
117
+ /*! End of @composy/store-core | Powered by @composy/builder */
118
+ //# sourceMappingURL=async-action.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async-action.cjs","names":[],"sources":["../../src/core/async-action.ts"],"sourcesContent":["/**\n * 异步 Action 工具\n *\n * 提供框架无关的异步操作状态管理\n * @module core/async-action\n */\n\nimport type { Unsubscribe } from '../types'\nimport { createPubSub } from './pub-sub'\n\n/**\n * 异步 Action 配置\n */\nexport interface AsyncActionOptions {\n /** 重试次数 (默认 0) */\n retryCount?: number\n /** 重试间隔 (毫秒, 默认 1000) */\n retryDelay?: number\n /** 超时时间 (毫秒, 0=不限) */\n timeout?: number\n /** 执行前是否自动清除上次错误 */\n resetOnExecute?: boolean\n}\n\n/**\n * 异步 Action 状态\n */\nexport interface AsyncActionState<T> {\n /** 返回数据 */\n data: T | null\n /** 错误信息 */\n error: Error | null\n /** 是否加载中 */\n loading: boolean\n /** 执行次数 */\n executionCount: number\n /** 最后执行时间 */\n lastExecutedAt: number | null\n}\n\n/**\n * 异步 Action 实例\n */\nexport interface AsyncAction<T, Args extends unknown[]> {\n /** 当前状态 */\n readonly state: AsyncActionState<T>\n /** 执行异步操作 */\n execute: (...args: Args) => Promise<T>\n /** 重置状态 */\n reset: () => void\n /** 取消当前执行 */\n abort: () => void\n /** 订阅状态变化 */\n subscribe: (callback: (state: AsyncActionState<T>) => void) => Unsubscribe\n /** 设置成功回调 */\n onSuccess: (callback: (data: T) => void) => Unsubscribe\n /** 设置错误回调 */\n onError: (callback: (error: Error) => void) => Unsubscribe\n}\n\n/**\n * 延迟工具函数\n */\nfunction delay(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\n/**\n * 创建异步 Action\n *\n * 将异步函数包装为带状态追踪的 Action,自动管理 loading/data/error 状态\n *\n * @template T - 返回数据类型\n * @template Args - 参数类型\n * @param fn - 异步函数\n * @param options - 配置选项\n * @returns AsyncAction 实例\n *\n * @example\n * ```typescript\n * // 基本用法\n * const fetchUsers = createAsyncAction(async (page: number) => {\n * const res = await fetch(`/api/users?page=${page}`)\n * return res.json()\n * })\n *\n * await fetchUsers.execute(1)\n * console.log(fetchUsers.state.data) // 用户列表\n * console.log(fetchUsers.state.loading) // false\n *\n * // 带重试\n * const fetchWithRetry = createAsyncAction(\n * async () => fetch('/api/unstable').then(r => r.json()),\n * { retryCount: 3, retryDelay: 1000 }\n * )\n *\n * // 订阅状态变化\n * fetchUsers.subscribe((state) => {\n * console.log('loading:', state.loading, 'data:', state.data)\n * })\n *\n * // 成功/错误回调\n * fetchUsers.onSuccess((data) => console.log('Got:', data))\n * fetchUsers.onError((err) => console.error('Failed:', err))\n * ```\n */\nexport function createAsyncAction<T, Args extends unknown[] = []>(\n fn: (...args: Args) => Promise<T>,\n options: AsyncActionOptions = {},\n): AsyncAction<T, Args> {\n const {\n retryCount = 0,\n retryDelay = 1000,\n timeout = 0,\n resetOnExecute = true,\n } = options\n\n // 内部状态\n const _state: AsyncActionState<T> = {\n data: null,\n error: null,\n loading: false,\n executionCount: 0,\n lastExecutedAt: null,\n }\n\n // 发布/订阅\n const statePubSub = createPubSub<AsyncActionState<T>>()\n const successPubSub = createPubSub<T>()\n const errorPubSub = createPubSub<Error>()\n\n // 当前 AbortController\n let abortController: AbortController | null = null\n\n /** 通知状态变化 */\n const notify = (): void => {\n statePubSub.publish({ ..._state })\n }\n\n /** 执行带重试的异步函数 */\n const executeWithRetry = async (args: Args, retriesLeft: number): Promise<T> => {\n try {\n return await fn(...args)\n }\n catch (error) {\n if (retriesLeft > 0 && !abortController?.signal.aborted) {\n await delay(retryDelay)\n if (abortController?.signal.aborted) {\n throw new Error('Aborted')\n }\n return executeWithRetry(args, retriesLeft - 1)\n }\n throw error\n }\n }\n\n /** 执行 */\n const execute = async (...args: Args): Promise<T> => {\n // 取消上一次执行\n if (abortController) {\n abortController.abort()\n }\n abortController = new AbortController()\n\n if (resetOnExecute) {\n _state.error = null\n }\n\n _state.loading = true\n _state.executionCount++\n _state.lastExecutedAt = Date.now()\n notify()\n\n try {\n let result: T\n\n if (timeout > 0) {\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => reject(new Error(`Timeout after ${timeout}ms`)), timeout)\n })\n result = await Promise.race([\n executeWithRetry(args, retryCount),\n timeoutPromise,\n ])\n }\n else {\n result = await executeWithRetry(args, retryCount)\n }\n\n if (!abortController.signal.aborted) {\n _state.data = result\n _state.error = null\n _state.loading = false\n notify()\n successPubSub.publish(result)\n }\n\n return result\n }\n catch (error) {\n if (!abortController.signal.aborted) {\n const err = error instanceof Error ? error : new Error(String(error))\n _state.error = err\n _state.loading = false\n notify()\n errorPubSub.publish(err)\n }\n throw error\n }\n }\n\n /** 重置 */\n const reset = (): void => {\n if (abortController) {\n abortController.abort()\n abortController = null\n }\n _state.data = null\n _state.error = null\n _state.loading = false\n _state.executionCount = 0\n _state.lastExecutedAt = null\n notify()\n }\n\n /** 取消 */\n const abort = (): void => {\n if (abortController) {\n abortController.abort()\n abortController = null\n }\n if (_state.loading) {\n _state.loading = false\n _state.error = new Error('Aborted')\n notify()\n }\n }\n\n return {\n get state() { return { ..._state } },\n execute,\n reset,\n abort,\n subscribe: (callback) => statePubSub.subscribe(callback),\n onSuccess: (callback) => successPubSub.subscribe(callback),\n onError: (callback) => errorPubSub.subscribe(callback),\n }\n}\n"],"mappings":";;;;;;;;;;;;;AA+DA,SAAS,MAAM,IAA2B;CACxC,OAAO,IAAI,SAAQ,YAAW,WAAW,SAAS,EAAE,CAAC;AACvD;AAyCO,SAAS,kBACd,IACA,UAA8B,CAAC,GACT;CACtB,MAAM,EACJ,aAAa,GACb,aAAa,KACb,UAAU,GACV,iBAAiB,SACf;CAGJ,MAAM,SAA8B;EAClC,MAAM;EACN,OAAO;EACP,SAAS;EACT,gBAAgB;EAChB,gBAAgB;CAClB;CAGA,MAAM,cAAc,gBAAA,aAAkC;CACtD,MAAM,gBAAgB,gBAAA,aAAgB;CACtC,MAAM,cAAc,gBAAA,aAAoB;CAGxC,IAAI,kBAA0C;CAG9C,MAAM,eAAqB;EACzB,YAAY,QAAQ,EAAE,GAAG,OAAO,CAAC;CACnC;CAGA,MAAM,mBAAmB,OAAO,MAAY,gBAAoC;EAC9E,IAAI;GACF,OAAO,MAAM,GAAG,GAAG,IAAI;EACzB,SACO,OAAO;GACZ,IAAI,cAAc,KAAK,CAAC,iBAAiB,OAAO,SAAS;IACvD,MAAM,MAAM,UAAU;IACtB,IAAI,iBAAiB,OAAO,SAC1B,MAAM,IAAI,MAAM,SAAS;IAE3B,OAAO,iBAAiB,MAAM,cAAc,CAAC;GAC/C;GACA,MAAM;EACR;CACF;CAGA,MAAM,UAAU,OAAA,GAAU,SAA2B;EAEnD,IAAI,iBACF,gBAAgB,MAAM;EAExB,kBAAkB,IAAI,gBAAgB;EAEtC,IAAI,gBACF,OAAO,QAAQ;EAGjB,OAAO,UAAU;EACjB,OAAO;EACP,OAAO,iBAAiB,KAAK,IAAI;EACjC,OAAO;EAEP,IAAI;GACF,IAAI;GAEJ,IAAI,UAAU,GAAG;IACf,MAAM,iBAAiB,IAAI,SAAgB,GAAG,WAAW;KACvD,iBAAiB,uBAAO,IAAI,MAAM,iBAAiB,QAAO,GAAI,CAAC,GAAG,OAAO;IAC3E,CAAC;IACD,SAAS,MAAM,QAAQ,KAAK,CAC1B,iBAAiB,MAAM,UAAU,GACjC,cACF,CAAC;GACH,OAEE,SAAS,MAAM,iBAAiB,MAAM,UAAU;GAGlD,IAAI,CAAC,gBAAgB,OAAO,SAAS;IACnC,OAAO,OAAO;IACd,OAAO,QAAQ;IACf,OAAO,UAAU;IACjB,OAAO;IACP,cAAc,QAAQ,MAAM;GAC9B;GAEA,OAAO;EACT,SACO,OAAO;GACZ,IAAI,CAAC,gBAAgB,OAAO,SAAS;IACnC,MAAM,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;IACpE,OAAO,QAAQ;IACf,OAAO,UAAU;IACjB,OAAO;IACP,YAAY,QAAQ,GAAG;GACzB;GACA,MAAM;EACR;CACF;CAGA,MAAM,cAAoB;EACxB,IAAI,iBAAiB;GACnB,gBAAgB,MAAM;GACtB,kBAAkB;EACpB;EACA,OAAO,OAAO;EACd,OAAO,QAAQ;EACf,OAAO,UAAU;EACjB,OAAO,iBAAiB;EACxB,OAAO,iBAAiB;EACxB,OAAO;CACT;CAGA,MAAM,cAAoB;EACxB,IAAI,iBAAiB;GACnB,gBAAgB,MAAM;GACtB,kBAAkB;EACpB;EACA,IAAI,OAAO,SAAS;GAClB,OAAO,UAAU;GACjB,OAAO,wBAAQ,IAAI,MAAM,SAAS;GAClC,OAAO;EACT;CACF;CAEA,OAAO;EACL,IAAI,QAAQ;GAAE,OAAO,EAAE,GAAG,OAAO;EAAE;EACnC;EACA;EACA;EACA,YAAY,aAAa,YAAY,UAAU,QAAQ;EACvD,YAAY,aAAa,cAAc,UAAU,QAAQ;EACzD,UAAU,aAAa,YAAY,UAAU,QAAQ;CACvD;AACF"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * 异步 Action 工具
3
+ *
4
+ * 提供框架无关的异步操作状态管理
5
+ * @module core/async-action
6
+ */
7
+ import type { Unsubscribe } from '../types';
8
+ /**
9
+ * 异步 Action 配置
10
+ */
11
+ export interface AsyncActionOptions {
12
+ /** 重试次数 (默认 0) */
13
+ retryCount?: number;
14
+ /** 重试间隔 (毫秒, 默认 1000) */
15
+ retryDelay?: number;
16
+ /** 超时时间 (毫秒, 0=不限) */
17
+ timeout?: number;
18
+ /** 执行前是否自动清除上次错误 */
19
+ resetOnExecute?: boolean;
20
+ }
21
+ /**
22
+ * 异步 Action 状态
23
+ */
24
+ export interface AsyncActionState<T> {
25
+ /** 返回数据 */
26
+ data: T | null;
27
+ /** 错误信息 */
28
+ error: Error | null;
29
+ /** 是否加载中 */
30
+ loading: boolean;
31
+ /** 执行次数 */
32
+ executionCount: number;
33
+ /** 最后执行时间 */
34
+ lastExecutedAt: number | null;
35
+ }
36
+ /**
37
+ * 异步 Action 实例
38
+ */
39
+ export interface AsyncAction<T, Args extends unknown[]> {
40
+ /** 当前状态 */
41
+ readonly state: AsyncActionState<T>;
42
+ /** 执行异步操作 */
43
+ execute: (...args: Args) => Promise<T>;
44
+ /** 重置状态 */
45
+ reset: () => void;
46
+ /** 取消当前执行 */
47
+ abort: () => void;
48
+ /** 订阅状态变化 */
49
+ subscribe: (callback: (state: AsyncActionState<T>) => void) => Unsubscribe;
50
+ /** 设置成功回调 */
51
+ onSuccess: (callback: (data: T) => void) => Unsubscribe;
52
+ /** 设置错误回调 */
53
+ onError: (callback: (error: Error) => void) => Unsubscribe;
54
+ }
55
+ /**
56
+ * 创建异步 Action
57
+ *
58
+ * 将异步函数包装为带状态追踪的 Action,自动管理 loading/data/error 状态
59
+ *
60
+ * @template T - 返回数据类型
61
+ * @template Args - 参数类型
62
+ * @param fn - 异步函数
63
+ * @param options - 配置选项
64
+ * @returns AsyncAction 实例
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * // 基本用法
69
+ * const fetchUsers = createAsyncAction(async (page: number) => {
70
+ * const res = await fetch(`/api/users?page=${page}`)
71
+ * return res.json()
72
+ * })
73
+ *
74
+ * await fetchUsers.execute(1)
75
+ * console.log(fetchUsers.state.data) // 用户列表
76
+ * console.log(fetchUsers.state.loading) // false
77
+ *
78
+ * // 带重试
79
+ * const fetchWithRetry = createAsyncAction(
80
+ * async () => fetch('/api/unstable').then(r => r.json()),
81
+ * { retryCount: 3, retryDelay: 1000 }
82
+ * )
83
+ *
84
+ * // 订阅状态变化
85
+ * fetchUsers.subscribe((state) => {
86
+ * console.log('loading:', state.loading, 'data:', state.data)
87
+ * })
88
+ *
89
+ * // 成功/错误回调
90
+ * fetchUsers.onSuccess((data) => console.log('Got:', data))
91
+ * fetchUsers.onError((err) => console.error('Failed:', err))
92
+ * ```
93
+ */
94
+ export declare function createAsyncAction<T, Args extends unknown[] = []>(fn: (...args: Args) => Promise<T>, options?: AsyncActionOptions): AsyncAction<T, Args>;
95
+ //# sourceMappingURL=async-action.d.ts.map
@@ -0,0 +1,187 @@
1
+ /*!
2
+ * ***********************************
3
+ * @composy/store-core v0.0.1 *
4
+ * Built with rollup *
5
+ * Build time: 2024-08-17 11:27:33 *
6
+ * Build mode: production *
7
+ * Minified: No *
8
+ * ***********************************
9
+ */
10
+ "use strict";
11
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
12
+ const require_pub_sub = require("./pub-sub.cjs");
13
+ const require_event_bus = require("./event-bus.cjs");
14
+ //#region src/core/base-store.ts
15
+ function isPromiseLike(value) {
16
+ return !!value && typeof value.then === "function";
17
+ }
18
+ async function runCallbacks(callbacks, value) {
19
+ for (const callback of callbacks) await callback(value);
20
+ }
21
+ var BaseStore = class {
22
+ /**
23
+ * 构造函数
24
+ *
25
+ * @param definition - Store 定义
26
+ * @param _options - Store 配置选项
27
+ */
28
+ constructor(definition, _options = {}) {
29
+ /** 状态订阅管理器 */
30
+ this.stateSubscribers = require_pub_sub.createPubSub();
31
+ /** Action 订阅管理器 */
32
+ this.actionSubscribers = require_pub_sub.createPubSub();
33
+ /** 是否已销毁 */
34
+ this.disposed = false;
35
+ this.$id = definition.id;
36
+ this.initialStateFactory = definition.state;
37
+ this._state = definition.state();
38
+ this.getters = this.createGetters(definition.getters || {});
39
+ this.actions = this.createActions(definition.actions || {});
40
+ require_event_bus.globalEventBus.emit("store:created", { storeId: this.$id });
41
+ }
42
+ /**
43
+ * 获取当前状态
44
+ */
45
+ get $state() {
46
+ return this._state;
47
+ }
48
+ /**
49
+ * 设置状态
50
+ */
51
+ set $state(newState) {
52
+ this._state = newState;
53
+ }
54
+ /**
55
+ * 重置状态到初始值
56
+ */
57
+ $reset() {
58
+ this.checkDisposed();
59
+ const oldState = { ...this._state };
60
+ this._state = this.initialStateFactory();
61
+ this.notifyStateChange({
62
+ type: "direct",
63
+ storeId: this.$id,
64
+ oldState
65
+ });
66
+ }
67
+ /**
68
+ * 批量更新状态
69
+ */
70
+ $patch(partialState) {
71
+ this.checkDisposed();
72
+ const oldState = { ...this._state };
73
+ if (typeof partialState === "function") {
74
+ partialState(this._state);
75
+ this.notifyStateChange({
76
+ type: "patch function",
77
+ storeId: this.$id,
78
+ oldState
79
+ });
80
+ } else {
81
+ Object.assign(this._state, partialState);
82
+ this.notifyStateChange({
83
+ type: "patch object",
84
+ storeId: this.$id,
85
+ oldState,
86
+ events: Object.keys(partialState)
87
+ });
88
+ }
89
+ }
90
+ /**
91
+ * 订阅状态变化
92
+ */
93
+ $subscribe(callback, options = {}) {
94
+ this.checkDisposed();
95
+ return this.stateSubscribers.subscribe(({ mutation, state }) => callback(mutation, state), { immediate: options.immediate });
96
+ }
97
+ /**
98
+ * 订阅 Action 调用
99
+ */
100
+ $onAction(callback) {
101
+ this.checkDisposed();
102
+ return this.actionSubscribers.subscribe(callback);
103
+ }
104
+ /**
105
+ * 销毁 Store
106
+ */
107
+ $dispose() {
108
+ if (this.disposed) return;
109
+ this.disposed = true;
110
+ this.stateSubscribers.clear();
111
+ this.actionSubscribers.clear();
112
+ require_event_bus.globalEventBus.emit("store:disposed", { storeId: this.$id });
113
+ }
114
+ /**
115
+ * 通知状态变化
116
+ */
117
+ notifyStateChange(mutation) {
118
+ this.stateSubscribers.publish({
119
+ mutation,
120
+ state: this._state
121
+ });
122
+ require_event_bus.globalEventBus.emit("state:changed", {
123
+ storeId: this.$id,
124
+ state: this._state,
125
+ mutation
126
+ });
127
+ }
128
+ /**
129
+ * 通知 Action 调用
130
+ */
131
+ notifyAction(context) {
132
+ this.actionSubscribers.publish(context);
133
+ }
134
+ /**
135
+ * 检查是否已销毁
136
+ */
137
+ checkDisposed() {
138
+ if (this.disposed) throw new Error(`[Store] Store "${this.$id}" \u5DF2\u88AB\u9500\u6BC1`);
139
+ }
140
+ createGetters(gettersDefinition) {
141
+ const getterCache = {};
142
+ for (const key of Object.keys(gettersDefinition)) Object.defineProperty(getterCache, key, {
143
+ enumerable: true,
144
+ get: () => gettersDefinition[key](this._state)
145
+ });
146
+ return getterCache;
147
+ }
148
+ createActions(actionsDefinition) {
149
+ const actionCache = {};
150
+ for (const key of Object.keys(actionsDefinition)) {
151
+ const action = actionsDefinition[key];
152
+ actionCache[key] = ((...args) => {
153
+ this.checkDisposed();
154
+ const afterCallbacks = [];
155
+ const errorCallbacks = [];
156
+ const context = {
157
+ after: (callback) => afterCallbacks.push(callback),
158
+ args,
159
+ name: key,
160
+ onError: (callback) => errorCallbacks.push(callback),
161
+ storeId: this.$id
162
+ };
163
+ this.notifyAction(context);
164
+ try {
165
+ const result = action.apply(this, args);
166
+ if (isPromiseLike(result)) return result.then(async (resolvedResult) => {
167
+ await runCallbacks(afterCallbacks, resolvedResult);
168
+ return resolvedResult;
169
+ }).catch(async (error) => {
170
+ await runCallbacks(errorCallbacks, error);
171
+ throw error;
172
+ });
173
+ runCallbacks(afterCallbacks, result);
174
+ return result;
175
+ } catch (error) {
176
+ runCallbacks(errorCallbacks, error);
177
+ throw error;
178
+ }
179
+ });
180
+ }
181
+ return actionCache;
182
+ }
183
+ };
184
+ //#endregion
185
+ exports.BaseStore = BaseStore;
186
+ /*! End of @composy/store-core | Powered by @composy/builder */
187
+ //# sourceMappingURL=base-store.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-store.cjs","names":[],"sources":["../../src/core/base-store.ts"],"sourcesContent":["/**\n * 基础 Store 抽象类\n *\n * 提供框架无关的 Store 基础实现\n * @module core/base-store\n */\n\nimport type {\n ActionContext,\n ActionSubscriber,\n StateMutation,\n StateSubscriber,\n StateTree,\n StoreActions,\n StoreDefinition,\n StoreGetters,\n StoreId,\n StoreInstance,\n StoreOptions,\n SubscribeOptions,\n Unsubscribe,\n} from '../types'\nimport { globalEventBus } from './event-bus'\nimport { createPubSub } from './pub-sub'\n\ntype ActionCallback = (value: unknown) => void | Promise<void>\n\nfunction isPromiseLike(value: unknown): value is Promise<unknown> {\n return !!value && typeof (value as { then?: unknown }).then === 'function'\n}\n\nasync function runCallbacks(callbacks: ActionCallback[], value: unknown): Promise<void> {\n for (const callback of callbacks) {\n await callback(value)\n }\n}\n\n/**\n * 基础 Store 类\n *\n * @template Id - Store ID 类型\n * @template S - 状态类型\n * @template G - Getters 类型\n * @template A - Actions 类型\n */\nexport class BaseStore<\n Id extends StoreId = StoreId,\n S extends StateTree = StateTree,\n G extends StoreGetters<S> = StoreGetters<S>,\n A extends StoreActions = StoreActions,\n> implements StoreInstance<Id, S, G, A> {\n /** Store ID */\n readonly $id: Id\n\n /** Getter 计算结果 */\n readonly getters: { [K in keyof G]: ReturnType<G[K]> }\n\n /** Action 方法集合 */\n readonly actions: A\n\n /** 状态订阅管理器 */\n private stateSubscribers = createPubSub<{ mutation: StateMutation<S>, state: S }>()\n\n /** Action 订阅管理器 */\n private actionSubscribers = createPubSub<ActionContext<A>>()\n\n /** 初始状态工厂 */\n private initialStateFactory: () => S\n\n /** 当前状态 */\n private _state: S\n\n /** 是否已销毁 */\n private disposed = false\n\n /**\n * 构造函数\n *\n * @param definition - Store 定义\n * @param _options - Store 配置选项\n */\n constructor(\n definition: StoreDefinition<Id, S, G, A>,\n _options: StoreOptions = {},\n ) {\n this.$id = definition.id\n this.initialStateFactory = definition.state\n this._state = definition.state()\n this.getters = this.createGetters((definition.getters || {}) as G)\n this.actions = this.createActions((definition.actions || {}) as A)\n\n // 发送 Store 创建事件\n globalEventBus.emit('store:created', { storeId: this.$id })\n }\n\n /**\n * 获取当前状态\n */\n get $state(): S {\n return this._state\n }\n\n /**\n * 设置状态\n */\n set $state(newState: S) {\n this._state = newState\n }\n\n /**\n * 重置状态到初始值\n */\n $reset(): void {\n this.checkDisposed()\n const oldState = { ...this._state }\n this._state = this.initialStateFactory()\n\n this.notifyStateChange({\n type: 'direct',\n storeId: this.$id,\n oldState,\n })\n }\n\n /**\n * 批量更新状态\n */\n $patch(partialState: Partial<S> | ((state: S) => void)): void {\n this.checkDisposed()\n const oldState = { ...this._state }\n\n if (typeof partialState === 'function') {\n partialState(this._state)\n this.notifyStateChange({\n type: 'patch function',\n storeId: this.$id,\n oldState,\n })\n }\n else {\n Object.assign(this._state, partialState)\n this.notifyStateChange({\n type: 'patch object',\n storeId: this.$id,\n oldState,\n events: Object.keys(partialState),\n })\n }\n }\n\n /**\n * 订阅状态变化\n */\n $subscribe(\n callback: StateSubscriber<S>,\n options: SubscribeOptions = {},\n ): Unsubscribe {\n this.checkDisposed()\n\n return this.stateSubscribers.subscribe(\n ({ mutation, state }) => callback(mutation, state),\n { immediate: options.immediate },\n )\n }\n\n /**\n * 订阅 Action 调用\n */\n $onAction(callback: ActionSubscriber<A>): Unsubscribe {\n this.checkDisposed()\n\n return this.actionSubscribers.subscribe(callback)\n }\n\n /**\n * 销毁 Store\n */\n $dispose(): void {\n if (this.disposed) return\n\n this.disposed = true\n this.stateSubscribers.clear()\n this.actionSubscribers.clear()\n\n globalEventBus.emit('store:disposed', { storeId: this.$id })\n }\n\n /**\n * 通知状态变化\n */\n protected notifyStateChange(mutation: StateMutation<S>): void {\n this.stateSubscribers.publish({ mutation, state: this._state })\n globalEventBus.emit('state:changed', {\n storeId: this.$id,\n state: this._state,\n mutation,\n })\n }\n\n /**\n * 通知 Action 调用\n */\n protected notifyAction(context: ActionContext<A>): void {\n this.actionSubscribers.publish(context)\n }\n\n /**\n * 检查是否已销毁\n */\n private checkDisposed(): void {\n if (this.disposed) {\n throw new Error(`[Store] Store \"${this.$id}\" 已被销毁`)\n }\n }\n\n private createGetters(\n gettersDefinition: G,\n ): { [K in keyof G]: ReturnType<G[K]> } {\n const getterCache = {} as { [K in keyof G]: ReturnType<G[K]> }\n\n for (const key of Object.keys(gettersDefinition) as Array<keyof G>) {\n Object.defineProperty(getterCache, key, {\n enumerable: true,\n get: () => gettersDefinition[key](this._state),\n })\n }\n\n return getterCache\n }\n\n private createActions(actionsDefinition: A): A {\n const actionCache = {} as A\n\n for (const key of Object.keys(actionsDefinition) as Array<keyof A>) {\n const action = actionsDefinition[key]\n actionCache[key] = ((...args: unknown[]) => {\n this.checkDisposed()\n\n const afterCallbacks: ActionCallback[] = []\n const errorCallbacks: ActionCallback[] = []\n const context: ActionContext<A> = {\n after: callback => afterCallbacks.push(callback),\n args,\n name: key,\n onError: callback => errorCallbacks.push(callback),\n storeId: this.$id,\n }\n\n this.notifyAction(context)\n\n try {\n const result = action.apply(this, args)\n\n if (isPromiseLike(result)) {\n return result\n .then(async (resolvedResult) => {\n await runCallbacks(afterCallbacks, resolvedResult)\n return resolvedResult\n })\n .catch(async (error: unknown) => {\n await runCallbacks(errorCallbacks, error)\n throw error\n }) as ReturnType<A[typeof key]>\n }\n\n void runCallbacks(afterCallbacks, result)\n return result\n }\n catch (error) {\n void runCallbacks(errorCallbacks, error)\n throw error\n }\n }) as A[typeof key]\n }\n\n return actionCache\n }\n}\n\n"],"mappings":";;;;;;;;;;;;;;AA2BA,SAAS,cAAc,OAA2C;CAChE,OAAO,CAAC,CAAC,SAAS,OAAQ,MAA6B,SAAS;AAClE;AAEA,eAAe,aAAa,WAA6B,OAA+B;CACtF,KAAA,MAAW,YAAY,WACrB,MAAM,SAAS,KAAK;AAExB;AAUO,IAAM,YAAN,MAKiC;;;;;;;CA+BtC,YACE,YACA,WAAyB,CAAC,GAC1B;;EAvBF,KAAQ,mBAAmB,gBAAA,aAAuD;;EAGlF,KAAQ,oBAAoB,gBAAA,aAA+B;;EAS3D,KAAQ,WAAW;EAYjB,KAAK,MAAM,WAAW;EACtB,KAAK,sBAAsB,WAAW;EACtC,KAAK,SAAS,WAAW,MAAM;EAC/B,KAAK,UAAU,KAAK,cAAe,WAAW,WAAW,CAAC,CAAO;EACjE,KAAK,UAAU,KAAK,cAAe,WAAW,WAAW,CAAC,CAAO;EAGjE,kBAAA,eAAe,KAAK,iBAAiB,EAAE,SAAS,KAAK,IAAI,CAAC;CAC5D;;;;CAKA,IAAI,SAAY;EACd,OAAO,KAAK;CACd;;;;CAKA,IAAI,OAAO,UAAa;EACtB,KAAK,SAAS;CAChB;;;;CAKA,SAAe;EACb,KAAK,cAAc;EACnB,MAAM,WAAW,EAAE,GAAG,KAAK,OAAO;EAClC,KAAK,SAAS,KAAK,oBAAoB;EAEvC,KAAK,kBAAkB;GACrB,MAAM;GACN,SAAS,KAAK;GACd;EACF,CAAC;CACH;;;;CAKA,OAAO,cAAuD;EAC5D,KAAK,cAAc;EACnB,MAAM,WAAW,EAAE,GAAG,KAAK,OAAO;EAElC,IAAI,OAAO,iBAAiB,YAAY;GACtC,aAAa,KAAK,MAAM;GACxB,KAAK,kBAAkB;IACrB,MAAM;IACN,SAAS,KAAK;IACd;GACF,CAAC;EACH,OACK;GACH,OAAO,OAAO,KAAK,QAAQ,YAAY;GACvC,KAAK,kBAAkB;IACrB,MAAM;IACN,SAAS,KAAK;IACd;IACA,QAAQ,OAAO,KAAK,YAAY;GAClC,CAAC;EACH;CACF;;;;CAKA,WACE,UACA,UAA4B,CAAC,GAChB;EACb,KAAK,cAAc;EAEnB,OAAO,KAAK,iBAAiB,WAC1B,EAAE,UAAU,YAAY,SAAS,UAAU,KAAK,GACjD,EAAE,WAAW,QAAQ,UAAU,CACjC;CACF;;;;CAKA,UAAU,UAA4C;EACpD,KAAK,cAAc;EAEnB,OAAO,KAAK,kBAAkB,UAAU,QAAQ;CAClD;;;;CAKA,WAAiB;EACf,IAAI,KAAK,UAAU;EAEnB,KAAK,WAAW;EAChB,KAAK,iBAAiB,MAAM;EAC5B,KAAK,kBAAkB,MAAM;EAE7B,kBAAA,eAAe,KAAK,kBAAkB,EAAE,SAAS,KAAK,IAAI,CAAC;CAC7D;;;;CAKU,kBAAkB,UAAkC;EAC5D,KAAK,iBAAiB,QAAQ;GAAE;GAAU,OAAO,KAAK;EAAO,CAAC;EAC9D,kBAAA,eAAe,KAAK,iBAAiB;GACnC,SAAS,KAAK;GACd,OAAO,KAAK;GACZ;EACF,CAAC;CACH;;;;CAKU,aAAa,SAAiC;EACtD,KAAK,kBAAkB,QAAQ,OAAO;CACxC;;;;CAKQ,gBAAsB;EAC5B,IAAI,KAAK,UACP,MAAM,IAAI,MAAM,kBAAkB,KAAK,IAAG,2BAAQ;CAEtD;CAEQ,cACN,mBACsC;EACtC,MAAM,cAAc,CAAC;EAErB,KAAA,MAAW,OAAO,OAAO,KAAK,iBAAiB,GAC7C,OAAO,eAAe,aAAa,KAAK;GACtC,YAAY;GACZ,WAAW,kBAAkB,IAAG,CAAE,KAAK,MAAM;EAC/C,CAAC;EAGH,OAAO;CACT;CAEQ,cAAc,mBAAyB;EAC7C,MAAM,cAAc,CAAC;EAErB,KAAA,MAAW,OAAO,OAAO,KAAK,iBAAiB,GAAqB;GAClE,MAAM,SAAS,kBAAkB;GACjC,YAAY,SAAQ,GAAI,SAAoB;IAC1C,KAAK,cAAc;IAEnB,MAAM,iBAAmC,CAAC;IAC1C,MAAM,iBAAmC,CAAC;IAC1C,MAAM,UAA4B;KAChC,QAAO,aAAY,eAAe,KAAK,QAAQ;KAC/C;KACA,MAAM;KACN,UAAS,aAAY,eAAe,KAAK,QAAQ;KACjD,SAAS,KAAK;IAChB;IAEA,KAAK,aAAa,OAAO;IAEzB,IAAI;KACF,MAAM,SAAS,OAAO,MAAM,MAAM,IAAI;KAEtC,IAAI,cAAc,MAAM,GACtB,OAAO,OACJ,KAAK,OAAO,mBAAmB;MAC9B,MAAM,aAAa,gBAAgB,cAAc;MACjD,OAAO;KACT,CAAC,CAAA,CACA,MAAM,OAAO,UAAmB;MAC/B,MAAM,aAAa,gBAAgB,KAAK;MACxC,MAAM;KACR,CAAC;KAGL,aAAkB,gBAAgB,MAAM;KACxC,OAAO;IACT,SACO,OAAO;KACZ,aAAkB,gBAAgB,KAAK;KACvC,MAAM;IACR;GACF;EACF;EAEA,OAAO;CACT;AACF"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * 基础 Store 抽象类
3
+ *
4
+ * 提供框架无关的 Store 基础实现
5
+ * @module core/base-store
6
+ */
7
+ import type { ActionContext, ActionSubscriber, StateMutation, StateSubscriber, StateTree, StoreActions, StoreDefinition, StoreGetters, StoreId, StoreInstance, StoreOptions, SubscribeOptions, Unsubscribe } from '../types';
8
+ /**
9
+ * 基础 Store 类
10
+ *
11
+ * @template Id - Store ID 类型
12
+ * @template S - 状态类型
13
+ * @template G - Getters 类型
14
+ * @template A - Actions 类型
15
+ */
16
+ export declare class BaseStore<Id extends StoreId = StoreId, S extends StateTree = StateTree, G extends StoreGetters<S> = StoreGetters<S>, A extends StoreActions = StoreActions> implements StoreInstance<Id, S, G, A> {
17
+ /** Store ID */
18
+ readonly $id: Id;
19
+ /** Getter 计算结果 */
20
+ readonly getters: {
21
+ [K in keyof G]: ReturnType<G[K]>;
22
+ };
23
+ /** Action 方法集合 */
24
+ readonly actions: A;
25
+ /** 状态订阅管理器 */
26
+ private stateSubscribers;
27
+ /** Action 订阅管理器 */
28
+ private actionSubscribers;
29
+ /** 初始状态工厂 */
30
+ private initialStateFactory;
31
+ /** 当前状态 */
32
+ private _state;
33
+ /** 是否已销毁 */
34
+ private disposed;
35
+ /**
36
+ * 构造函数
37
+ *
38
+ * @param definition - Store 定义
39
+ * @param _options - Store 配置选项
40
+ */
41
+ constructor(definition: StoreDefinition<Id, S, G, A>, _options?: StoreOptions);
42
+ /**
43
+ * 获取当前状态
44
+ */
45
+ get $state(): S;
46
+ /**
47
+ * 设置状态
48
+ */
49
+ set $state(newState: S);
50
+ /**
51
+ * 重置状态到初始值
52
+ */
53
+ $reset(): void;
54
+ /**
55
+ * 批量更新状态
56
+ */
57
+ $patch(partialState: Partial<S> | ((state: S) => void)): void;
58
+ /**
59
+ * 订阅状态变化
60
+ */
61
+ $subscribe(callback: StateSubscriber<S>, options?: SubscribeOptions): Unsubscribe;
62
+ /**
63
+ * 订阅 Action 调用
64
+ */
65
+ $onAction(callback: ActionSubscriber<A>): Unsubscribe;
66
+ /**
67
+ * 销毁 Store
68
+ */
69
+ $dispose(): void;
70
+ /**
71
+ * 通知状态变化
72
+ */
73
+ protected notifyStateChange(mutation: StateMutation<S>): void;
74
+ /**
75
+ * 通知 Action 调用
76
+ */
77
+ protected notifyAction(context: ActionContext<A>): void;
78
+ /**
79
+ * 检查是否已销毁
80
+ */
81
+ private checkDisposed;
82
+ private createGetters;
83
+ private createActions;
84
+ }
85
+ //# sourceMappingURL=base-store.d.ts.map
@@ -0,0 +1,69 @@
1
+ /*!
2
+ * ***********************************
3
+ * @composy/store-core v0.0.1 *
4
+ * Built with rollup *
5
+ * Build time: 2024-08-17 11:27:33 *
6
+ * Build mode: production *
7
+ * Minified: No *
8
+ * ***********************************
9
+ */
10
+ "use strict";
11
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
12
+ //#region src/core/batch-manager.ts
13
+ function createBatchManager(onFlush) {
14
+ let batchDepth = 0;
15
+ const pendingStores = /* @__PURE__ */ new Set();
16
+ const flush = () => {
17
+ if (pendingStores.size > 0) {
18
+ const stores = new Set(pendingStores);
19
+ pendingStores.clear();
20
+ onFlush?.(stores);
21
+ }
22
+ };
23
+ const start = () => {
24
+ batchDepth++;
25
+ };
26
+ const end = () => {
27
+ if (batchDepth === 0) return;
28
+ batchDepth--;
29
+ if (batchDepth === 0) flush();
30
+ };
31
+ const markDirty = (storeId) => {
32
+ pendingStores.add(storeId);
33
+ if (batchDepth === 0) flush();
34
+ };
35
+ const batch2 = (fn) => {
36
+ start();
37
+ try {
38
+ return fn();
39
+ } finally {
40
+ end();
41
+ }
42
+ };
43
+ const isBatching = () => batchDepth > 0;
44
+ return {
45
+ start,
46
+ end,
47
+ markDirty,
48
+ batch: batch2,
49
+ isBatching
50
+ };
51
+ }
52
+ let globalBatchManager = null;
53
+ function getGlobalBatchManager() {
54
+ if (!globalBatchManager) globalBatchManager = createBatchManager();
55
+ return globalBatchManager;
56
+ }
57
+ function setGlobalBatchManager(manager) {
58
+ globalBatchManager = manager;
59
+ }
60
+ function batch(fn) {
61
+ return getGlobalBatchManager().batch(fn);
62
+ }
63
+ //#endregion
64
+ exports.batch = batch;
65
+ exports.createBatchManager = createBatchManager;
66
+ exports.getGlobalBatchManager = getGlobalBatchManager;
67
+ exports.setGlobalBatchManager = setGlobalBatchManager;
68
+ /*! End of @composy/store-core | Powered by @composy/builder */
69
+ //# sourceMappingURL=batch-manager.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-manager.cjs","names":["batch"],"sources":["../../src/core/batch-manager.ts"],"sourcesContent":["/**\n * 批量更新管理器\n *\n * 用于优化多个状态更新的性能\n * @module core/batch-manager\n */\n\nimport type { BatchManager, StoreId } from '../types'\n\n/**\n * 创建批量更新管理器\n *\n * @param onFlush - 刷新回调,接收所有待更新的 Store ID\n * @returns 批量更新管理器实例\n *\n * @example\n * ```typescript\n * const batchManager = createBatchManager((storeIds) => {\n * storeIds.forEach(id => {\n * // 通知订阅者更新\n * notifySubscribers(id)\n * })\n * })\n *\n * // 批量更新\n * batchManager.batch(() => {\n * store1.count++\n * store2.name = 'new name'\n * })\n * ```\n */\nexport function createBatchManager(\n onFlush?: (storeIds: Set<StoreId>) => void,\n): BatchManager {\n /** 批处理嵌套深度,0 表示不在批处理上下文。 */\n let batchDepth = 0\n\n /** 待更新的 Store ID 集合 */\n const pendingStores = new Set<StoreId>()\n\n /**\n * 刷新待更新的 Store\n */\n const flush = (): void => {\n if (pendingStores.size > 0) {\n const stores = new Set(pendingStores)\n pendingStores.clear()\n onFlush?.(stores)\n }\n }\n\n /**\n * 开始批量更新\n */\n const start = (): void => {\n batchDepth++\n }\n\n /**\n * 结束批量更新\n */\n const end = (): void => {\n if (batchDepth === 0) {\n return\n }\n\n batchDepth--\n if (batchDepth === 0) {\n flush()\n }\n }\n\n /**\n * 标记 Store 需要更新\n */\n const markDirty = (storeId: StoreId): void => {\n pendingStores.add(storeId)\n\n // 如果不在批量更新中,立即刷新\n if (batchDepth === 0) {\n flush()\n }\n }\n\n /**\n * 在批量上下文中执行\n */\n const batch = <T>(fn: () => T): T => {\n start()\n try {\n return fn()\n }\n finally {\n end()\n }\n }\n\n /**\n * 是否正在批量更新\n */\n const isBatching = (): boolean => batchDepth > 0\n\n return {\n start,\n end,\n markDirty,\n batch,\n isBatching,\n }\n}\n\n/**\n * 全局批量更新管理器\n */\nlet globalBatchManager: BatchManager | null = null\n\n/**\n * 获取全局批量更新管理器\n */\nexport function getGlobalBatchManager(): BatchManager {\n if (!globalBatchManager) {\n globalBatchManager = createBatchManager()\n }\n return globalBatchManager\n}\n\n/**\n * 设置全局批量更新管理器\n */\nexport function setGlobalBatchManager(manager: BatchManager): void {\n globalBatchManager = manager\n}\n\n/**\n * 批量更新辅助函数\n *\n * @param fn - 执行函数\n * @returns 执行结果\n */\nexport function batch<T>(fn: () => T): T {\n return getGlobalBatchManager().batch(fn)\n}\n\n"],"mappings":";;;;;;;;;;;;AA+BO,SAAS,mBACd,SACc;CAEd,IAAI,aAAa;CAGjB,MAAM,gCAAgB,IAAI,IAAa;CAKvC,MAAM,cAAoB;EACxB,IAAI,cAAc,OAAO,GAAG;GAC1B,MAAM,SAAS,IAAI,IAAI,aAAa;GACpC,cAAc,MAAM;GACpB,UAAU,MAAM;EAClB;CACF;CAKA,MAAM,cAAoB;EACxB;CACF;CAKA,MAAM,YAAkB;EACtB,IAAI,eAAe,GACjB;EAGF;EACA,IAAI,eAAe,GACjB,MAAM;CAEV;CAKA,MAAM,aAAa,YAA2B;EAC5C,cAAc,IAAI,OAAO;EAGzB,IAAI,eAAe,GACjB,MAAM;CAEV;CAKA,MAAMA,UAAY,OAAmB;EACnC,MAAM;EACN,IAAI;GACF,OAAO,GAAG;EACZ,UACA;GACE,IAAI;EACN;CACF;CAKA,MAAM,mBAA4B,aAAa;CAE/C,OAAO;EACL;EACA;EACA;EACA,OAAAA;EACA;CACF;AACF;AAKA,IAAI,qBAA0C;AAKvC,SAAS,wBAAsC;CACpD,IAAI,CAAC,oBACH,qBAAqB,mBAAmB;CAE1C,OAAO;AACT;AAKO,SAAS,sBAAsB,SAA6B;CACjE,qBAAqB;AACvB;AAQO,SAAS,MAAS,IAAgB;CACvC,OAAO,sBAAsB,CAAA,CAAE,MAAM,EAAE;AACzC"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * 批量更新管理器
3
+ *
4
+ * 用于优化多个状态更新的性能
5
+ * @module core/batch-manager
6
+ */
7
+ import type { BatchManager, StoreId } from '../types';
8
+ /**
9
+ * 创建批量更新管理器
10
+ *
11
+ * @param onFlush - 刷新回调,接收所有待更新的 Store ID
12
+ * @returns 批量更新管理器实例
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const batchManager = createBatchManager((storeIds) => {
17
+ * storeIds.forEach(id => {
18
+ * // 通知订阅者更新
19
+ * notifySubscribers(id)
20
+ * })
21
+ * })
22
+ *
23
+ * // 批量更新
24
+ * batchManager.batch(() => {
25
+ * store1.count++
26
+ * store2.name = 'new name'
27
+ * })
28
+ * ```
29
+ */
30
+ export declare function createBatchManager(onFlush?: (storeIds: Set<StoreId>) => void): BatchManager;
31
+ /**
32
+ * 获取全局批量更新管理器
33
+ */
34
+ export declare function getGlobalBatchManager(): BatchManager;
35
+ /**
36
+ * 设置全局批量更新管理器
37
+ */
38
+ export declare function setGlobalBatchManager(manager: BatchManager): void;
39
+ /**
40
+ * 批量更新辅助函数
41
+ *
42
+ * @param fn - 执行函数
43
+ * @returns 执行结果
44
+ */
45
+ export declare function batch<T>(fn: () => T): T;
46
+ //# sourceMappingURL=batch-manager.d.ts.map
@@ -0,0 +1,31 @@
1
+ /*!
2
+ * ***********************************
3
+ * @composy/store-core v0.0.1 *
4
+ * Built with rollup *
5
+ * Build time: 2024-08-17 11:27:33 *
6
+ * Build mode: production *
7
+ * Minified: No *
8
+ * ***********************************
9
+ */
10
+ "use strict";
11
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
12
+ const require_base_store = require("./base-store.cjs");
13
+ //#region src/core/create-store.ts
14
+ function createStore(definition) {
15
+ let instance = null;
16
+ return () => {
17
+ if (instance) return instance;
18
+ const store = new require_base_store.BaseStore(definition);
19
+ const originalDispose = store.$dispose.bind(store);
20
+ store.$dispose = () => {
21
+ originalDispose();
22
+ instance = null;
23
+ };
24
+ instance = store;
25
+ return store;
26
+ };
27
+ }
28
+ //#endregion
29
+ exports.createStore = createStore;
30
+ /*! End of @composy/store-core | Powered by @composy/builder */
31
+ //# sourceMappingURL=create-store.cjs.map