@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,15 +2,31 @@
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
  import { createPubSub } from "./pub-sub.js";
11
11
  //#region src/core/async-action.ts
12
- function delay(ms) {
13
- return new Promise((resolve) => setTimeout(resolve, ms));
12
+ function abortError() {
13
+ return /* @__PURE__ */ new Error("Aborted");
14
+ }
15
+ function delay(ms, signal) {
16
+ if (signal.aborted) return Promise.reject(abortError());
17
+ return new Promise((resolve, reject) => {
18
+ let timer;
19
+ const onAbort = () => {
20
+ clearTimeout(timer);
21
+ signal.removeEventListener("abort", onAbort);
22
+ reject(abortError());
23
+ };
24
+ timer = setTimeout(() => {
25
+ signal.removeEventListener("abort", onAbort);
26
+ resolve();
27
+ }, ms);
28
+ signal.addEventListener("abort", onAbort, { once: true });
29
+ });
14
30
  }
15
31
  function createAsyncAction(fn, options = {}) {
16
32
  const { retryCount = 0, retryDelay = 1e3, timeout = 0, resetOnExecute = true } = options;
@@ -24,39 +40,64 @@ function createAsyncAction(fn, options = {}) {
24
40
  const statePubSub = createPubSub();
25
41
  const successPubSub = createPubSub();
26
42
  const errorPubSub = createPubSub();
27
- let abortController = null;
28
- const notify = () => {
29
- statePubSub.publish({ ..._state });
30
- };
31
- const executeWithRetry = async (args, retriesLeft) => {
43
+ let nextExecutionId = 0;
44
+ let activeExecution = null;
45
+ const notify = () => statePubSub.publish({ ..._state });
46
+ const invoke = fn;
47
+ const executeWithRetry = async (args, retriesLeft, execution) => {
48
+ if (execution.controller.signal.aborted) throw execution.abortReason ?? abortError();
32
49
  try {
33
- return await fn(...args);
50
+ const result = await invoke(...args, execution.controller.signal);
51
+ if (execution.controller.signal.aborted) throw execution.abortReason ?? abortError();
52
+ return result;
34
53
  } catch (error) {
35
- if (retriesLeft > 0 && !abortController?.signal.aborted) {
36
- await delay(retryDelay);
37
- if (abortController?.signal.aborted) throw new Error("Aborted");
38
- return executeWithRetry(args, retriesLeft - 1);
39
- }
40
- throw error;
54
+ if (execution.controller.signal.aborted) throw execution.abortReason ?? abortError();
55
+ if (retriesLeft <= 0) throw error;
56
+ await delay(retryDelay, execution.controller.signal);
57
+ return executeWithRetry(args, retriesLeft - 1, execution);
58
+ }
59
+ };
60
+ const cancelExecution = (execution, reason) => {
61
+ execution.abortReason = reason;
62
+ if (!execution.controller.signal.aborted) execution.controller.abort();
63
+ execution.rejectAbort?.(reason);
64
+ if (execution.timeoutId) {
65
+ clearTimeout(execution.timeoutId);
66
+ execution.timeoutId = void 0;
41
67
  }
42
68
  };
43
69
  const execute = async (...args) => {
44
- if (abortController) abortController.abort();
45
- abortController = new AbortController();
70
+ if (activeExecution) cancelExecution(activeExecution, abortError());
71
+ const execution = {
72
+ id: ++nextExecutionId,
73
+ controller: new AbortController()
74
+ };
75
+ activeExecution = execution;
46
76
  if (resetOnExecute) _state.error = null;
47
77
  _state.loading = true;
48
78
  _state.executionCount++;
49
79
  _state.lastExecutedAt = Date.now();
50
80
  notify();
51
81
  try {
52
- let result;
53
- if (timeout > 0) {
54
- const timeoutPromise = new Promise((_, reject) => {
55
- setTimeout(() => reject(/* @__PURE__ */ new Error(`Timeout after ${timeout}ms`)), timeout);
56
- });
57
- result = await Promise.race([executeWithRetry(args, retryCount), timeoutPromise]);
58
- } else result = await executeWithRetry(args, retryCount);
59
- if (!abortController.signal.aborted) {
82
+ const work = executeWithRetry(args, retryCount, execution);
83
+ const abortPromise = new Promise((_, reject) => {
84
+ execution.rejectAbort = reject;
85
+ });
86
+ const timeoutPromise = timeout > 0 ? new Promise((_, reject) => {
87
+ execution.timeoutId = setTimeout(() => {
88
+ const error = /* @__PURE__ */ new Error(`Timeout after ${timeout}ms`);
89
+ execution.abortReason = error;
90
+ execution.controller.abort();
91
+ reject(error);
92
+ }, timeout);
93
+ }) : null;
94
+ execution.result = timeoutPromise ? Promise.race([
95
+ work,
96
+ abortPromise,
97
+ timeoutPromise
98
+ ]) : Promise.race([work, abortPromise]);
99
+ const result = await execution.result;
100
+ if (activeExecution?.id === execution.id && !execution.controller.signal.aborted) {
60
101
  _state.data = result;
61
102
  _state.error = null;
62
103
  _state.loading = false;
@@ -65,20 +106,27 @@ function createAsyncAction(fn, options = {}) {
65
106
  }
66
107
  return result;
67
108
  } catch (error) {
68
- if (!abortController.signal.aborted) {
109
+ if (activeExecution?.id === execution.id) {
69
110
  const err = error instanceof Error ? error : new Error(String(error));
70
111
  _state.error = err;
71
112
  _state.loading = false;
72
113
  notify();
73
- errorPubSub.publish(err);
114
+ if (execution.abortReason?.message !== "Aborted") errorPubSub.publish(err);
74
115
  }
75
116
  throw error;
117
+ } finally {
118
+ if (execution.timeoutId) {
119
+ clearTimeout(execution.timeoutId);
120
+ execution.timeoutId = void 0;
121
+ }
122
+ if (activeExecution?.id === execution.id) activeExecution = null;
76
123
  }
77
124
  };
78
125
  const reset = () => {
79
- if (abortController) {
80
- abortController.abort();
81
- abortController = null;
126
+ if (activeExecution) {
127
+ const execution = activeExecution;
128
+ activeExecution = null;
129
+ cancelExecution(execution, abortError());
82
130
  }
83
131
  _state.data = null;
84
132
  _state.error = null;
@@ -88,13 +136,13 @@ function createAsyncAction(fn, options = {}) {
88
136
  notify();
89
137
  };
90
138
  const abort = () => {
91
- if (abortController) {
92
- abortController.abort();
93
- abortController = null;
94
- }
139
+ const execution = activeExecution;
140
+ if (!execution) return;
141
+ activeExecution = null;
142
+ cancelExecution(execution, abortError());
95
143
  if (_state.loading) {
96
144
  _state.loading = false;
97
- _state.error = /* @__PURE__ */ new Error("Aborted");
145
+ _state.error = execution.abortReason ?? abortError();
98
146
  notify();
99
147
  }
100
148
  };
@@ -1 +1 @@
1
- {"version":3,"file":"async-action.js","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,aAAkC;CACtD,MAAM,gBAAgB,aAAgB;CACtC,MAAM,cAAc,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"}
1
+ {"version":3,"file":"async-action.js","names":[],"sources":["../../src/core/async-action.ts"],"sourcesContent":["/** Race-safe asynchronous action helper. */\n\nimport type { Unsubscribe } from '../types'\nimport { createPubSub } from './pub-sub'\n\nexport interface AsyncActionOptions {\n retryCount?: number\n retryDelay?: number\n timeout?: number\n resetOnExecute?: boolean\n}\n\nexport interface AsyncActionState<T> {\n data: T | null\n error: Error | null\n loading: boolean\n executionCount: number\n lastExecutedAt: number | null\n}\n\nexport interface AsyncAction<T, Args extends unknown[]> {\n readonly state: AsyncActionState<T>\n execute: (...args: Args) => Promise<T>\n reset: () => void\n abort: () => void\n subscribe: (callback: (state: AsyncActionState<T>) => void) => Unsubscribe\n onSuccess: (callback: (data: T) => void) => Unsubscribe\n onError: (callback: (error: Error) => void) => Unsubscribe\n}\n\ninterface Execution<T> {\n id: number\n controller: AbortController\n timeoutId?: ReturnType<typeof setTimeout>\n rejectAbort?: (error: Error) => void\n abortReason?: Error\n result?: Promise<T>\n}\n\nfunction abortError(): Error {\n return new Error('Aborted')\n}\n\nfunction delay(ms: number, signal: AbortSignal): Promise<void> {\n if (signal.aborted) {\n return Promise.reject(abortError())\n }\n\n return new Promise((resolve, reject) => {\n let timer: ReturnType<typeof setTimeout>\n const onAbort = (): void => {\n clearTimeout(timer)\n signal.removeEventListener('abort', onAbort)\n reject(abortError())\n }\n timer = setTimeout(() => {\n signal.removeEventListener('abort', onAbort)\n resolve()\n }, ms)\n signal.addEventListener('abort', onAbort, { once: true })\n })\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 const _state: AsyncActionState<T> = {\n data: null,\n error: null,\n loading: false,\n executionCount: 0,\n lastExecutedAt: null,\n }\n const statePubSub = createPubSub<AsyncActionState<T>>()\n const successPubSub = createPubSub<T>()\n const errorPubSub = createPubSub<Error>()\n let nextExecutionId = 0\n let activeExecution: Execution<T> | null = null\n\n const notify = (): void => statePubSub.publish({ ..._state })\n\n const invoke = fn as unknown as (\n ...args: [...Args, AbortSignal]\n ) => Promise<T>\n const executeWithRetry = async (\n args: Args,\n retriesLeft: number,\n execution: Execution<T>\n ): Promise<T> => {\n if (execution.controller.signal.aborted) {\n throw execution.abortReason ?? abortError()\n }\n\n try {\n const result = await invoke(...args, execution.controller.signal)\n if (execution.controller.signal.aborted) {\n throw execution.abortReason ?? abortError()\n }\n return result\n } catch (error) {\n if (execution.controller.signal.aborted) {\n throw execution.abortReason ?? abortError()\n }\n if (retriesLeft <= 0) {\n throw error\n }\n await delay(retryDelay, execution.controller.signal)\n return executeWithRetry(args, retriesLeft - 1, execution)\n }\n }\n\n const cancelExecution = (execution: Execution<T>, reason: Error): void => {\n execution.abortReason = reason\n if (!execution.controller.signal.aborted) {\n execution.controller.abort()\n }\n execution.rejectAbort?.(reason)\n if (execution.timeoutId) {\n clearTimeout(execution.timeoutId)\n execution.timeoutId = undefined\n }\n }\n\n const execute = async (...args: Args): Promise<T> => {\n if (activeExecution) {\n cancelExecution(activeExecution, abortError())\n }\n\n const execution: Execution<T> = {\n id: ++nextExecutionId,\n controller: new AbortController(),\n }\n activeExecution = execution\n\n if (resetOnExecute) {\n _state.error = null\n }\n _state.loading = true\n _state.executionCount++\n _state.lastExecutedAt = Date.now()\n notify()\n\n try {\n const work = executeWithRetry(args, retryCount, execution)\n const abortPromise = new Promise<never>((_, reject) => {\n execution.rejectAbort = reject\n })\n const timeoutPromise =\n timeout > 0\n ? new Promise<never>((_, reject) => {\n execution.timeoutId = setTimeout(() => {\n const error = new Error(`Timeout after ${timeout}ms`)\n execution.abortReason = error\n execution.controller.abort()\n reject(error)\n }, timeout)\n })\n : null\n\n execution.result = timeoutPromise\n ? Promise.race([work, abortPromise, timeoutPromise])\n : Promise.race([work, abortPromise])\n const result = await execution.result\n\n if (\n activeExecution?.id === execution.id &&\n !execution.controller.signal.aborted\n ) {\n _state.data = result\n _state.error = null\n _state.loading = false\n notify()\n successPubSub.publish(result)\n }\n\n return result\n } catch (error) {\n if (activeExecution?.id === execution.id) {\n const err = error instanceof Error ? error : new Error(String(error))\n _state.error = err\n _state.loading = false\n notify()\n if (execution.abortReason?.message !== 'Aborted') {\n errorPubSub.publish(err)\n }\n }\n throw error\n } finally {\n if (execution.timeoutId) {\n clearTimeout(execution.timeoutId)\n execution.timeoutId = undefined\n }\n if (activeExecution?.id === execution.id) {\n activeExecution = null\n }\n }\n }\n\n const reset = (): void => {\n if (activeExecution) {\n const execution = activeExecution\n activeExecution = null\n cancelExecution(execution, abortError())\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 const abort = (): void => {\n const execution = activeExecution\n if (!execution) return\n\n activeExecution = null\n cancelExecution(execution, abortError())\n if (_state.loading) {\n _state.loading = false\n _state.error = execution.abortReason ?? abortError()\n notify()\n }\n }\n\n return {\n get state() {\n return { ..._state }\n },\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":"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"}
@@ -2,14 +2,26 @@
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
  import { createPubSub } from "./pub-sub.js";
11
+ import { getGlobalMiddlewareManager } from "../middleware/middleware-manager.js";
12
+ import { getGlobalPluginManager } from "../plugins/plugin-manager.js";
13
+ import { deepClone } from "../utils/deep-clone.js";
14
+ import { getGlobalBatchManager } from "./batch-manager.js";
11
15
  import { globalEventBus } from "./event-bus.js";
12
16
  //#region src/core/base-store.ts
17
+ var __defProp = Object.defineProperty;
18
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, {
19
+ enumerable: true,
20
+ configurable: true,
21
+ writable: true,
22
+ value
23
+ }) : obj[key] = value;
24
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
13
25
  function isPromiseLike(value) {
14
26
  return !!value && typeof value.then === "function";
15
27
  }
@@ -17,123 +29,208 @@ async function runCallbacks(callbacks, value) {
17
29
  for (const callback of callbacks) await callback(value);
18
30
  }
19
31
  var BaseStore = class {
20
- /**
21
- * 构造函数
22
- *
23
- * @param definition - Store 定义
24
- * @param _options - Store 配置选项
25
- */
26
- constructor(definition, _options = {}) {
27
- /** 状态订阅管理器 */
28
- this.stateSubscribers = createPubSub();
29
- /** Action 订阅管理器 */
30
- this.actionSubscribers = createPubSub();
31
- /** 是否已销毁 */
32
- this.disposed = false;
32
+ constructor(definition, options = {}) {
33
+ __publicField(this, "$id");
34
+ __publicField(this, "getters");
35
+ __publicField(this, "actions");
36
+ __publicField(this, "stateSubscribers", createPubSub());
37
+ __publicField(this, "actionSubscribers", createPubSub());
38
+ __publicField(this, "initialStateFactory");
39
+ __publicField(this, "middlewareManager");
40
+ __publicField(this, "pluginManager");
41
+ __publicField(this, "batchManager");
42
+ __publicField(this, "pendingBatchMutation", null);
43
+ __publicField(this, "stopBatchFlush");
44
+ __publicField(this, "mutationQueue", Promise.resolve());
45
+ __publicField(this, "pendingMutations", 0);
46
+ __publicField(this, "_state");
47
+ __publicField(this, "disposed", false);
33
48
  this.$id = definition.id;
34
49
  this.initialStateFactory = definition.state;
35
50
  this._state = definition.state();
51
+ this.middlewareManager = options.middleware ?? getGlobalMiddlewareManager();
52
+ this.pluginManager = options.plugins ?? getGlobalPluginManager();
53
+ this.batchManager = options.batch ?? getGlobalBatchManager();
36
54
  this.getters = this.createGetters(definition.getters || {});
37
55
  this.actions = this.createActions(definition.actions || {});
56
+ this.stopBatchFlush = this.batchManager.onFlush?.((storeIds) => {
57
+ if (!storeIds.has(this.$id) || !this.pendingBatchMutation) return;
58
+ const mutation = this.pendingBatchMutation;
59
+ this.pendingBatchMutation = null;
60
+ this.publishStateChange(mutation);
61
+ });
38
62
  globalEventBus.emit("store:created", { storeId: this.$id });
63
+ this.notifyPluginStoreCreated();
39
64
  }
40
- /**
41
- * 获取当前状态
42
- */
43
65
  get $state() {
44
66
  return this._state;
45
67
  }
46
- /**
47
- * 设置状态
48
- */
49
68
  set $state(newState) {
50
- this._state = newState;
69
+ this.checkDisposed();
70
+ const nextState = deepClone(newState);
71
+ const operation = () => this.runStateMutation(nextState, newState);
72
+ this.scheduleMutation(operation).catch((error) => {
73
+ console.error(`[Store] Failed to replace state for "${this.$id}":`, error);
74
+ });
51
75
  }
52
- /**
53
- * 重置状态到初始值
54
- */
55
76
  $reset() {
56
77
  this.checkDisposed();
57
- const oldState = { ...this._state };
58
- this._state = this.initialStateFactory();
59
- this.notifyStateChange({
60
- type: "direct",
61
- storeId: this.$id,
62
- oldState
78
+ this.scheduleMutation(() => this.runStateMutation()).catch((error) => {
79
+ console.error(`[Store] Failed to reset "${this.$id}":`, error);
63
80
  });
64
81
  }
65
- /**
66
- * 批量更新状态
67
- */
68
82
  $patch(partialState) {
69
83
  this.checkDisposed();
70
- const oldState = { ...this._state };
71
- if (typeof partialState === "function") {
72
- partialState(this._state);
73
- this.notifyStateChange({
74
- type: "patch function",
75
- storeId: this.$id,
76
- oldState
77
- });
78
- } else {
79
- Object.assign(this._state, partialState);
80
- this.notifyStateChange({
81
- type: "patch object",
82
- storeId: this.$id,
83
- oldState,
84
- events: Object.keys(partialState)
85
- });
86
- }
84
+ const patch = typeof partialState === "function" ? partialState : deepClone(partialState);
85
+ this.scheduleMutation(() => this.runPatchMutation(patch)).catch((error) => {
86
+ console.error(`[Store] Failed to patch "${this.$id}":`, error);
87
+ });
88
+ }
89
+ async $patchAsync(partialState) {
90
+ this.checkDisposed();
91
+ const patch = typeof partialState === "function" ? partialState : deepClone(partialState);
92
+ await this.scheduleMutation(() => this.runPatchMutation(patch));
87
93
  }
88
- /**
89
- * 订阅状态变化
90
- */
91
94
  $subscribe(callback, options = {}) {
92
95
  this.checkDisposed();
93
- return this.stateSubscribers.subscribe(({ mutation, state }) => callback(mutation, state), { immediate: options.immediate });
96
+ const unsubscribe = this.stateSubscribers.subscribe(({ mutation, state }) => callback(mutation, state), { immediate: options.immediate });
97
+ if (options.immediate) try {
98
+ callback({
99
+ type: "direct",
100
+ storeId: this.$id
101
+ }, deepClone(this._state));
102
+ } catch (error) {
103
+ console.error("[Store] immediate subscriber failed:", error);
104
+ }
105
+ return unsubscribe;
94
106
  }
95
- /**
96
- * 订阅 Action 调用
97
- */
98
107
  $onAction(callback) {
99
108
  this.checkDisposed();
100
109
  return this.actionSubscribers.subscribe(callback);
101
110
  }
102
- /**
103
- * 销毁 Store
104
- */
105
111
  $dispose() {
106
112
  if (this.disposed) return;
107
113
  this.disposed = true;
114
+ this.stopBatchFlush?.();
115
+ this.stopBatchFlush = void 0;
116
+ this.mutationQueue = Promise.resolve();
117
+ this.pendingMutations = 0;
108
118
  this.stateSubscribers.clear();
109
119
  this.actionSubscribers.clear();
120
+ this.notifyPluginStoreDisposed();
110
121
  globalEventBus.emit("store:disposed", { storeId: this.$id });
111
122
  }
112
- /**
113
- * 通知状态变化
114
- */
115
123
  notifyStateChange(mutation) {
124
+ this.publishStateChange(mutation);
125
+ }
126
+ publishStateChange(mutation) {
127
+ const stateSnapshot = deepClone(this._state);
116
128
  this.stateSubscribers.publish({
117
129
  mutation,
118
- state: this._state
130
+ state: stateSnapshot
119
131
  });
120
132
  globalEventBus.emit("state:changed", {
121
133
  storeId: this.$id,
122
- state: this._state,
134
+ state: stateSnapshot,
123
135
  mutation
124
136
  });
125
137
  }
126
- /**
127
- * 通知 Action 调用
128
- */
129
- notifyAction(context) {
130
- this.actionSubscribers.publish(context);
138
+ async runMutation(candidate, mutation, payload, previousState) {
139
+ this.checkDisposed();
140
+ let committed = false;
141
+ const commit = () => {
142
+ if (committed || this.disposed) return;
143
+ committed = true;
144
+ this._state = candidate;
145
+ this.notifyPluginStateChange(candidate, previousState);
146
+ if (this.batchManager.isBatching() && this.batchManager.onFlush) {
147
+ this.pendingBatchMutation = this.pendingBatchMutation ? {
148
+ ...mutation,
149
+ oldState: this.pendingBatchMutation.oldState
150
+ } : mutation;
151
+ this.batchManager.markDirty(this.$id);
152
+ } else this.publishStateChange(mutation);
153
+ };
154
+ if (this.middlewareManager.getAll().length === 0) {
155
+ commit();
156
+ return;
157
+ }
158
+ await this.middlewareManager.execute({
159
+ storeId: this.$id,
160
+ state: candidate,
161
+ type: mutation.type === "direct" ? "state:reset" : "state:patch",
162
+ payload,
163
+ meta: {
164
+ candidateState: candidate,
165
+ previousState,
166
+ commit
167
+ }
168
+ });
169
+ commit();
170
+ }
171
+ runStateMutation(nextState, payload) {
172
+ this.checkDisposed();
173
+ const previousState = deepClone(this._state);
174
+ const mutation = {
175
+ type: "direct",
176
+ storeId: this.$id,
177
+ oldState: previousState
178
+ };
179
+ return this.runMutation(deepClone(nextState ?? this.initialStateFactory()), mutation, payload, previousState);
180
+ }
181
+ runPatchMutation(partialState) {
182
+ this.checkDisposed();
183
+ const previousState = deepClone(this._state);
184
+ const candidate = deepClone(this._state);
185
+ const mutation = typeof partialState === "function" ? {
186
+ type: "patch function",
187
+ storeId: this.$id,
188
+ oldState: previousState
189
+ } : {
190
+ type: "patch object",
191
+ storeId: this.$id,
192
+ oldState: previousState,
193
+ events: Object.keys(partialState)
194
+ };
195
+ if (typeof partialState === "function") partialState(candidate);
196
+ else Object.assign(candidate, partialState);
197
+ return this.runMutation(candidate, mutation, partialState, previousState);
198
+ }
199
+ scheduleMutation(operation) {
200
+ if (this.pendingMutations === 0 && this.middlewareManager.getAll().length === 0) return operation();
201
+ this.pendingMutations += 1;
202
+ const queuedOperation = this.mutationQueue.then(operation);
203
+ this.mutationQueue = queuedOperation.catch(() => void 0);
204
+ queuedOperation.then(() => {
205
+ this.pendingMutations -= 1;
206
+ }, () => {
207
+ this.pendingMutations -= 1;
208
+ });
209
+ return queuedOperation;
210
+ }
211
+ notifyPluginStoreCreated() {
212
+ if (this.pluginManager.notifyStoreCreated) {
213
+ this.pluginManager.notifyStoreCreated(this);
214
+ return;
215
+ }
216
+ this.pluginManager.getAll().forEach((plugin) => plugin.onStoreCreated?.(this));
217
+ }
218
+ notifyPluginStoreDisposed() {
219
+ if (this.pluginManager.notifyStoreDisposed) {
220
+ this.pluginManager.notifyStoreDisposed(this);
221
+ return;
222
+ }
223
+ this.pluginManager.getAll().forEach((plugin) => plugin.onStoreDisposed?.(this));
224
+ }
225
+ notifyPluginStateChange(state, previousState) {
226
+ if (this.pluginManager.notifyStateChange) {
227
+ this.pluginManager.notifyStateChange(this.$id, deepClone(state), deepClone(previousState));
228
+ return;
229
+ }
230
+ this.pluginManager.getAll().forEach((plugin) => plugin.onStateChange?.(this.$id, deepClone(state), deepClone(previousState)));
131
231
  }
132
- /**
133
- * 检查是否已销毁
134
- */
135
232
  checkDisposed() {
136
- if (this.disposed) throw new Error(`[Store] Store "${this.$id}" \u5DF2\u88AB\u9500\u6BC1`);
233
+ if (this.disposed) throw new Error(`[Store] Store "${this.$id}" has been disposed`);
137
234
  }
138
235
  createGetters(gettersDefinition) {
139
236
  const getterCache = {};
@@ -178,6 +275,9 @@ var BaseStore = class {
178
275
  }
179
276
  return actionCache;
180
277
  }
278
+ notifyAction(context) {
279
+ this.actionSubscribers.publish(context);
280
+ }
181
281
  };
182
282
  //#endregion
183
283
  export { BaseStore };
@@ -1 +1 @@
1
- {"version":3,"file":"base-store.js","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":"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"}
1
+ {"version":3,"file":"base-store.js","names":[],"sources":["../../src/core/base-store.ts"],"sourcesContent":["/** Framework-independent Store runtime. */\n\nimport type {\n ActionContext,\n ActionSubscriber,\n BatchManager,\n MiddlewareManager,\n PluginManager,\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 { getGlobalMiddlewareManager } from '../middleware/middleware-manager'\nimport { getGlobalPluginManager } from '../plugins/plugin-manager'\nimport { deepClone } from '../utils'\nimport { getGlobalBatchManager } from './batch-manager'\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(\n callbacks: ActionCallback[],\n value: unknown\n): Promise<void> {\n for (const callback of callbacks) {\n await callback(value)\n }\n}\n\n/**\n * Base Store implementation.\n *\n * State changes are built on a candidate state. Middleware can reject the\n * candidate before it is committed, while stores without middleware retain\n * synchronous patch semantics.\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 readonly $id: Id\n readonly getters: { [K in keyof G]: ReturnType<G[K]> }\n readonly actions: A\n\n private readonly stateSubscribers = createPubSub<{\n mutation: StateMutation<S>\n state: S\n }>()\n private readonly actionSubscribers = createPubSub<ActionContext<A>>()\n private readonly initialStateFactory: () => S\n private readonly middlewareManager: MiddlewareManager\n private readonly pluginManager: PluginManager\n private readonly batchManager: BatchManager\n private pendingBatchMutation: StateMutation<S> | null = null\n private stopBatchFlush: Unsubscribe | undefined\n private mutationQueue: Promise<void> = Promise.resolve()\n private pendingMutations = 0\n private _state: S\n private disposed = false\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.middlewareManager = options.middleware ?? getGlobalMiddlewareManager()\n this.pluginManager = options.plugins ?? getGlobalPluginManager()\n this.batchManager = options.batch ?? getGlobalBatchManager()\n this.getters = this.createGetters((definition.getters || {}) as G)\n this.actions = this.createActions((definition.actions || {}) as A)\n\n this.stopBatchFlush = this.batchManager.onFlush?.(storeIds => {\n if (!storeIds.has(this.$id) || !this.pendingBatchMutation) {\n return\n }\n\n const mutation = this.pendingBatchMutation\n this.pendingBatchMutation = null\n this.publishStateChange(mutation)\n })\n\n globalEventBus.emit('store:created', { storeId: this.$id })\n this.notifyPluginStoreCreated()\n }\n\n get $state(): S {\n return this._state\n }\n\n set $state(newState: S) {\n this.checkDisposed()\n const nextState = deepClone(newState)\n const operation = () => this.runStateMutation(nextState, newState)\n void this.scheduleMutation(operation).catch((error: unknown) => {\n console.error(`[Store] Failed to replace state for \"${this.$id}\":`, error)\n })\n }\n\n $reset(): void {\n this.checkDisposed()\n void this.scheduleMutation(() => this.runStateMutation()).catch(\n (error: unknown) => {\n console.error(`[Store] Failed to reset \"${this.$id}\":`, error)\n }\n )\n }\n\n $patch(partialState: Partial<S> | ((state: S) => void)): void {\n this.checkDisposed()\n const patch =\n typeof partialState === 'function'\n ? partialState\n : deepClone(partialState)\n void this.scheduleMutation(() => this.runPatchMutation(patch)).catch(\n (error: unknown) => {\n console.error(`[Store] Failed to patch \"${this.$id}\":`, error)\n }\n )\n }\n\n async $patchAsync(\n partialState: Partial<S> | ((state: S) => void)\n ): Promise<void> {\n this.checkDisposed()\n const patch =\n typeof partialState === 'function'\n ? partialState\n : deepClone(partialState)\n await this.scheduleMutation(() => this.runPatchMutation(patch))\n }\n\n $subscribe(\n callback: StateSubscriber<S>,\n options: SubscribeOptions = {}\n ): Unsubscribe {\n this.checkDisposed()\n const unsubscribe = this.stateSubscribers.subscribe(\n ({ mutation, state }) => callback(mutation, state),\n { immediate: options.immediate }\n )\n\n if (options.immediate) {\n try {\n callback({ type: 'direct', storeId: this.$id }, deepClone(this._state))\n } catch (error) {\n console.error('[Store] immediate subscriber failed:', error)\n }\n }\n\n return unsubscribe\n }\n\n $onAction(callback: ActionSubscriber<A>): Unsubscribe {\n this.checkDisposed()\n return this.actionSubscribers.subscribe(callback)\n }\n\n $dispose(): void {\n if (this.disposed) return\n\n this.disposed = true\n this.stopBatchFlush?.()\n this.stopBatchFlush = undefined\n this.mutationQueue = Promise.resolve()\n this.pendingMutations = 0\n this.stateSubscribers.clear()\n this.actionSubscribers.clear()\n this.notifyPluginStoreDisposed()\n globalEventBus.emit('store:disposed', { storeId: this.$id })\n }\n\n protected notifyStateChange(mutation: StateMutation<S>): void {\n this.publishStateChange(mutation)\n }\n\n private publishStateChange(mutation: StateMutation<S>): void {\n const stateSnapshot = deepClone(this._state)\n this.stateSubscribers.publish({ mutation, state: stateSnapshot })\n globalEventBus.emit('state:changed', {\n storeId: this.$id,\n state: stateSnapshot,\n mutation,\n })\n }\n\n private async runMutation(\n candidate: S,\n mutation: StateMutation<S>,\n payload: unknown,\n previousState: S\n ): Promise<void> {\n this.checkDisposed()\n let committed = false\n const commit = (): void => {\n if (committed || this.disposed) return\n\n committed = true\n this._state = candidate\n this.notifyPluginStateChange(candidate, previousState)\n\n if (this.batchManager.isBatching() && this.batchManager.onFlush) {\n this.pendingBatchMutation = this.pendingBatchMutation\n ? { ...mutation, oldState: this.pendingBatchMutation.oldState }\n : mutation\n this.batchManager.markDirty(this.$id)\n } else {\n this.publishStateChange(mutation)\n }\n }\n\n const middlewares = this.middlewareManager.getAll()\n if (middlewares.length === 0) {\n commit()\n return\n }\n\n await this.middlewareManager.execute({\n storeId: this.$id,\n state: candidate,\n type: mutation.type === 'direct' ? 'state:reset' : 'state:patch',\n payload,\n meta: {\n candidateState: candidate,\n previousState,\n commit,\n },\n })\n commit()\n }\n\n private runStateMutation(nextState?: S, payload?: unknown): Promise<void> {\n this.checkDisposed()\n const previousState = deepClone(this._state)\n const mutation: StateMutation<S> = {\n type: 'direct',\n storeId: this.$id,\n oldState: previousState,\n }\n return this.runMutation(\n deepClone(nextState ?? this.initialStateFactory()),\n mutation,\n payload,\n previousState\n )\n }\n\n private runPatchMutation(\n partialState: Partial<S> | ((state: S) => void)\n ): Promise<void> {\n this.checkDisposed()\n const previousState = deepClone(this._state)\n const candidate = deepClone(this._state)\n const mutation: StateMutation<S> =\n typeof partialState === 'function'\n ? { type: 'patch function', storeId: this.$id, oldState: previousState }\n : {\n type: 'patch object',\n storeId: this.$id,\n oldState: previousState,\n events: Object.keys(partialState),\n }\n\n if (typeof partialState === 'function') {\n partialState(candidate)\n } else {\n Object.assign(candidate, partialState)\n }\n\n return this.runMutation(candidate, mutation, partialState, previousState)\n }\n\n private scheduleMutation(operation: () => Promise<void>): Promise<void> {\n if (\n this.pendingMutations === 0 &&\n this.middlewareManager.getAll().length === 0\n ) {\n return operation()\n }\n\n this.pendingMutations += 1\n const queuedOperation = this.mutationQueue.then(operation)\n this.mutationQueue = queuedOperation.catch(() => undefined)\n void queuedOperation.then(\n () => {\n this.pendingMutations -= 1\n },\n () => {\n this.pendingMutations -= 1\n }\n )\n return queuedOperation\n }\n\n private notifyPluginStoreCreated(): void {\n if (this.pluginManager.notifyStoreCreated) {\n this.pluginManager.notifyStoreCreated(this)\n return\n }\n this.pluginManager.getAll().forEach(plugin => plugin.onStoreCreated?.(this))\n }\n\n private notifyPluginStoreDisposed(): void {\n if (this.pluginManager.notifyStoreDisposed) {\n this.pluginManager.notifyStoreDisposed(this)\n return\n }\n this.pluginManager\n .getAll()\n .forEach(plugin => plugin.onStoreDisposed?.(this))\n }\n\n private notifyPluginStateChange(state: S, previousState: S): void {\n if (this.pluginManager.notifyStateChange) {\n this.pluginManager.notifyStateChange(\n this.$id,\n deepClone(state),\n deepClone(previousState)\n )\n return\n }\n this.pluginManager\n .getAll()\n .forEach(plugin =>\n plugin.onStateChange?.(\n this.$id,\n deepClone(state),\n deepClone(previousState)\n )\n )\n }\n\n private checkDisposed(): void {\n if (this.disposed) {\n throw new Error(`[Store] Store \"${this.$id}\" has been disposed`)\n }\n }\n\n private createGetters(gettersDefinition: G): {\n [K in keyof G]: ReturnType<G[K]>\n } {\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 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 } catch (error) {\n void runCallbacks(errorCallbacks, error)\n throw error\n }\n }) as A[typeof key]\n }\n\n return actionCache\n }\n\n private notifyAction(context: ActionContext<A>): void {\n this.actionSubscribers.publish(context)\n }\n}\n"],"mappings":"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"}