@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
package/dist/index.js ADDED
@@ -0,0 +1,1852 @@
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
+ (function(global, factory) {
12
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.LDesignStoreCore = {}));
13
+ })(this, function(exports) {
14
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
15
+ //#region src/core/pub-sub.ts
16
+ function createPubSub() {
17
+ const subscribers = /* @__PURE__ */ new Set();
18
+ const subscribe = (callback, options = {}) => {
19
+ const info = {
20
+ callback,
21
+ options
22
+ };
23
+ subscribers.add(info);
24
+ return () => {
25
+ subscribers.delete(info);
26
+ };
27
+ };
28
+ const publish = (value, oldValue) => {
29
+ subscribers.forEach((info) => {
30
+ try {
31
+ info.callback(value, oldValue);
32
+ } catch (error) {
33
+ console.error("[PubSub] 订阅回调执行出错:", error);
34
+ }
35
+ });
36
+ };
37
+ const clear = () => {
38
+ subscribers.clear();
39
+ };
40
+ const size = () => {
41
+ return subscribers.size;
42
+ };
43
+ return {
44
+ subscribe,
45
+ publish,
46
+ clear,
47
+ size
48
+ };
49
+ }
50
+ function createPubSubWithValue(initialValue) {
51
+ let currentValue = initialValue;
52
+ const pubsub = createPubSub();
53
+ const getValue = () => currentValue;
54
+ const setValue = (value) => {
55
+ const oldValue = currentValue;
56
+ currentValue = value;
57
+ pubsub.publish(value, oldValue);
58
+ };
59
+ const subscribe = (callback, options = {}) => {
60
+ const unsubscribe = pubsub.subscribe(callback, options);
61
+ if (options.immediate) callback(currentValue);
62
+ return unsubscribe;
63
+ };
64
+ return {
65
+ subscribe,
66
+ publish: pubsub.publish,
67
+ clear: pubsub.clear,
68
+ size: pubsub.size,
69
+ getValue,
70
+ setValue
71
+ };
72
+ }
73
+ //#endregion
74
+ //#region src/core/async-action.ts
75
+ function delay(ms) {
76
+ return new Promise((resolve) => setTimeout(resolve, ms));
77
+ }
78
+ function createAsyncAction(fn, options = {}) {
79
+ const { retryCount = 0, retryDelay = 1e3, timeout = 0, resetOnExecute = true } = options;
80
+ const _state = {
81
+ data: null,
82
+ error: null,
83
+ loading: false,
84
+ executionCount: 0,
85
+ lastExecutedAt: null
86
+ };
87
+ const statePubSub = createPubSub();
88
+ const successPubSub = createPubSub();
89
+ const errorPubSub = createPubSub();
90
+ let abortController = null;
91
+ const notify = () => {
92
+ statePubSub.publish({ ..._state });
93
+ };
94
+ const executeWithRetry = async (args, retriesLeft) => {
95
+ try {
96
+ return await fn(...args);
97
+ } catch (error) {
98
+ if (retriesLeft > 0 && !abortController?.signal.aborted) {
99
+ await delay(retryDelay);
100
+ if (abortController?.signal.aborted) throw new Error("Aborted");
101
+ return executeWithRetry(args, retriesLeft - 1);
102
+ }
103
+ throw error;
104
+ }
105
+ };
106
+ const execute = async (...args) => {
107
+ if (abortController) abortController.abort();
108
+ abortController = new AbortController();
109
+ if (resetOnExecute) _state.error = null;
110
+ _state.loading = true;
111
+ _state.executionCount++;
112
+ _state.lastExecutedAt = Date.now();
113
+ notify();
114
+ try {
115
+ let result;
116
+ if (timeout > 0) {
117
+ const timeoutPromise = new Promise((_, reject) => {
118
+ setTimeout(() => reject(/* @__PURE__ */ new Error(`Timeout after ${timeout}ms`)), timeout);
119
+ });
120
+ result = await Promise.race([executeWithRetry(args, retryCount), timeoutPromise]);
121
+ } else result = await executeWithRetry(args, retryCount);
122
+ if (!abortController.signal.aborted) {
123
+ _state.data = result;
124
+ _state.error = null;
125
+ _state.loading = false;
126
+ notify();
127
+ successPubSub.publish(result);
128
+ }
129
+ return result;
130
+ } catch (error) {
131
+ if (!abortController.signal.aborted) {
132
+ const err = error instanceof Error ? error : new Error(String(error));
133
+ _state.error = err;
134
+ _state.loading = false;
135
+ notify();
136
+ errorPubSub.publish(err);
137
+ }
138
+ throw error;
139
+ }
140
+ };
141
+ const reset = () => {
142
+ if (abortController) {
143
+ abortController.abort();
144
+ abortController = null;
145
+ }
146
+ _state.data = null;
147
+ _state.error = null;
148
+ _state.loading = false;
149
+ _state.executionCount = 0;
150
+ _state.lastExecutedAt = null;
151
+ notify();
152
+ };
153
+ const abort = () => {
154
+ if (abortController) {
155
+ abortController.abort();
156
+ abortController = null;
157
+ }
158
+ if (_state.loading) {
159
+ _state.loading = false;
160
+ _state.error = /* @__PURE__ */ new Error("Aborted");
161
+ notify();
162
+ }
163
+ };
164
+ return {
165
+ get state() {
166
+ return { ..._state };
167
+ },
168
+ execute,
169
+ reset,
170
+ abort,
171
+ subscribe: (callback) => statePubSub.subscribe(callback),
172
+ onSuccess: (callback) => successPubSub.subscribe(callback),
173
+ onError: (callback) => errorPubSub.subscribe(callback)
174
+ };
175
+ }
176
+ //#endregion
177
+ //#region src/core/event-bus.ts
178
+ function createEventBus() {
179
+ const listeners = /* @__PURE__ */ new Map();
180
+ const getListeners = (type) => {
181
+ let set = listeners.get(type);
182
+ if (!set) {
183
+ set = /* @__PURE__ */ new Set();
184
+ listeners.set(type, set);
185
+ }
186
+ return set;
187
+ };
188
+ const on = (type, listener) => {
189
+ const set = getListeners(type);
190
+ set.add(listener);
191
+ return () => {
192
+ set.delete(listener);
193
+ if (set.size === 0) listeners.delete(type);
194
+ };
195
+ };
196
+ const off = (type, listener) => {
197
+ if (listener) {
198
+ const set = listeners.get(type);
199
+ if (set) {
200
+ set.delete(listener);
201
+ if (set.size === 0) listeners.delete(type);
202
+ }
203
+ } else listeners.delete(type);
204
+ };
205
+ const once = (type, listener) => {
206
+ const wrappedListener = (data) => {
207
+ listener(data);
208
+ off(type, wrappedListener);
209
+ };
210
+ return on(type, wrappedListener);
211
+ };
212
+ const emit = (type, payload) => {
213
+ const data = {
214
+ type,
215
+ payload,
216
+ timestamp: Date.now()
217
+ };
218
+ const typeListeners = listeners.get(type);
219
+ if (typeListeners) typeListeners.forEach((listener) => listener(data));
220
+ const wildcardListeners = listeners.get("*");
221
+ if (wildcardListeners) wildcardListeners.forEach((listener) => listener(data));
222
+ };
223
+ const clear = () => {
224
+ listeners.clear();
225
+ };
226
+ return {
227
+ on,
228
+ once,
229
+ off,
230
+ emit,
231
+ clear
232
+ };
233
+ }
234
+ const globalEventBus = createEventBus();
235
+ //#endregion
236
+ //#region src/core/base-store.ts
237
+ function isPromiseLike(value) {
238
+ return !!value && typeof value.then === "function";
239
+ }
240
+ async function runCallbacks(callbacks, value) {
241
+ for (const callback of callbacks) await callback(value);
242
+ }
243
+ var BaseStore = class {
244
+ /**
245
+ * 构造函数
246
+ *
247
+ * @param definition - Store 定义
248
+ * @param _options - Store 配置选项
249
+ */
250
+ constructor(definition, _options = {}) {
251
+ /** 状态订阅管理器 */
252
+ this.stateSubscribers = createPubSub();
253
+ /** Action 订阅管理器 */
254
+ this.actionSubscribers = createPubSub();
255
+ /** 是否已销毁 */
256
+ this.disposed = false;
257
+ this.$id = definition.id;
258
+ this.initialStateFactory = definition.state;
259
+ this._state = definition.state();
260
+ this.getters = this.createGetters(definition.getters || {});
261
+ this.actions = this.createActions(definition.actions || {});
262
+ globalEventBus.emit("store:created", { storeId: this.$id });
263
+ }
264
+ /**
265
+ * 获取当前状态
266
+ */
267
+ get $state() {
268
+ return this._state;
269
+ }
270
+ /**
271
+ * 设置状态
272
+ */
273
+ set $state(newState) {
274
+ this._state = newState;
275
+ }
276
+ /**
277
+ * 重置状态到初始值
278
+ */
279
+ $reset() {
280
+ this.checkDisposed();
281
+ const oldState = { ...this._state };
282
+ this._state = this.initialStateFactory();
283
+ this.notifyStateChange({
284
+ type: "direct",
285
+ storeId: this.$id,
286
+ oldState
287
+ });
288
+ }
289
+ /**
290
+ * 批量更新状态
291
+ */
292
+ $patch(partialState) {
293
+ this.checkDisposed();
294
+ const oldState = { ...this._state };
295
+ if (typeof partialState === "function") {
296
+ partialState(this._state);
297
+ this.notifyStateChange({
298
+ type: "patch function",
299
+ storeId: this.$id,
300
+ oldState
301
+ });
302
+ } else {
303
+ Object.assign(this._state, partialState);
304
+ this.notifyStateChange({
305
+ type: "patch object",
306
+ storeId: this.$id,
307
+ oldState,
308
+ events: Object.keys(partialState)
309
+ });
310
+ }
311
+ }
312
+ /**
313
+ * 订阅状态变化
314
+ */
315
+ $subscribe(callback, options = {}) {
316
+ this.checkDisposed();
317
+ return this.stateSubscribers.subscribe(({ mutation, state }) => callback(mutation, state), { immediate: options.immediate });
318
+ }
319
+ /**
320
+ * 订阅 Action 调用
321
+ */
322
+ $onAction(callback) {
323
+ this.checkDisposed();
324
+ return this.actionSubscribers.subscribe(callback);
325
+ }
326
+ /**
327
+ * 销毁 Store
328
+ */
329
+ $dispose() {
330
+ if (this.disposed) return;
331
+ this.disposed = true;
332
+ this.stateSubscribers.clear();
333
+ this.actionSubscribers.clear();
334
+ globalEventBus.emit("store:disposed", { storeId: this.$id });
335
+ }
336
+ /**
337
+ * 通知状态变化
338
+ */
339
+ notifyStateChange(mutation) {
340
+ this.stateSubscribers.publish({
341
+ mutation,
342
+ state: this._state
343
+ });
344
+ globalEventBus.emit("state:changed", {
345
+ storeId: this.$id,
346
+ state: this._state,
347
+ mutation
348
+ });
349
+ }
350
+ /**
351
+ * 通知 Action 调用
352
+ */
353
+ notifyAction(context) {
354
+ this.actionSubscribers.publish(context);
355
+ }
356
+ /**
357
+ * 检查是否已销毁
358
+ */
359
+ checkDisposed() {
360
+ if (this.disposed) throw new Error(`[Store] Store "${this.$id}" \u5DF2\u88AB\u9500\u6BC1`);
361
+ }
362
+ createGetters(gettersDefinition) {
363
+ const getterCache = {};
364
+ for (const key of Object.keys(gettersDefinition)) Object.defineProperty(getterCache, key, {
365
+ enumerable: true,
366
+ get: () => gettersDefinition[key](this._state)
367
+ });
368
+ return getterCache;
369
+ }
370
+ createActions(actionsDefinition) {
371
+ const actionCache = {};
372
+ for (const key of Object.keys(actionsDefinition)) {
373
+ const action = actionsDefinition[key];
374
+ actionCache[key] = ((...args) => {
375
+ this.checkDisposed();
376
+ const afterCallbacks = [];
377
+ const errorCallbacks = [];
378
+ const context = {
379
+ after: (callback) => afterCallbacks.push(callback),
380
+ args,
381
+ name: key,
382
+ onError: (callback) => errorCallbacks.push(callback),
383
+ storeId: this.$id
384
+ };
385
+ this.notifyAction(context);
386
+ try {
387
+ const result = action.apply(this, args);
388
+ if (isPromiseLike(result)) return result.then(async (resolvedResult) => {
389
+ await runCallbacks(afterCallbacks, resolvedResult);
390
+ return resolvedResult;
391
+ }).catch(async (error) => {
392
+ await runCallbacks(errorCallbacks, error);
393
+ throw error;
394
+ });
395
+ runCallbacks(afterCallbacks, result);
396
+ return result;
397
+ } catch (error) {
398
+ runCallbacks(errorCallbacks, error);
399
+ throw error;
400
+ }
401
+ });
402
+ }
403
+ return actionCache;
404
+ }
405
+ };
406
+ //#endregion
407
+ //#region src/core/batch-manager.ts
408
+ function createBatchManager(onFlush) {
409
+ let batchDepth = 0;
410
+ const pendingStores = /* @__PURE__ */ new Set();
411
+ const flush = () => {
412
+ if (pendingStores.size > 0) {
413
+ const stores = new Set(pendingStores);
414
+ pendingStores.clear();
415
+ onFlush?.(stores);
416
+ }
417
+ };
418
+ const start = () => {
419
+ batchDepth++;
420
+ };
421
+ const end = () => {
422
+ if (batchDepth === 0) return;
423
+ batchDepth--;
424
+ if (batchDepth === 0) flush();
425
+ };
426
+ const markDirty = (storeId) => {
427
+ pendingStores.add(storeId);
428
+ if (batchDepth === 0) flush();
429
+ };
430
+ const batch2 = (fn) => {
431
+ start();
432
+ try {
433
+ return fn();
434
+ } finally {
435
+ end();
436
+ }
437
+ };
438
+ const isBatching = () => batchDepth > 0;
439
+ return {
440
+ start,
441
+ end,
442
+ markDirty,
443
+ batch: batch2,
444
+ isBatching
445
+ };
446
+ }
447
+ let globalBatchManager = null;
448
+ function getGlobalBatchManager() {
449
+ if (!globalBatchManager) globalBatchManager = createBatchManager();
450
+ return globalBatchManager;
451
+ }
452
+ function setGlobalBatchManager(manager) {
453
+ globalBatchManager = manager;
454
+ }
455
+ function batch(fn) {
456
+ return getGlobalBatchManager().batch(fn);
457
+ }
458
+ //#endregion
459
+ //#region src/core/create-store.ts
460
+ function createStore(definition) {
461
+ let instance = null;
462
+ return () => {
463
+ if (instance) return instance;
464
+ const store = new BaseStore(definition);
465
+ const originalDispose = store.$dispose.bind(store);
466
+ store.$dispose = () => {
467
+ originalDispose();
468
+ instance = null;
469
+ };
470
+ instance = store;
471
+ return store;
472
+ };
473
+ }
474
+ //#endregion
475
+ //#region src/engine/plugin.ts
476
+ const storeStateKeys = {
477
+ BUS: "store:bus",
478
+ PINIA: "store:pinia",
479
+ API: "store:api",
480
+ REGISTRY: "store:registry",
481
+ RUNTIME: "store:runtime"
482
+ };
483
+ const storeEventKeys = {
484
+ INSTALLED: "store:installed",
485
+ UNINSTALLED: "store:uninstalled"
486
+ };
487
+ function resolveEngine(context) {
488
+ const value = context;
489
+ if (value && typeof value === "object" && "engine" in value) return value.engine ?? {};
490
+ return value ?? {};
491
+ }
492
+ function resolvePluginContext(context) {
493
+ return context && typeof context === "object" ? context : void 0;
494
+ }
495
+ function resolveDefaultApp(engine, context, payload) {
496
+ const payloadObject = payload;
497
+ return payloadObject?.app ?? payloadObject?.framework?.app ?? engine.getApp?.() ?? context?.framework?.app;
498
+ }
499
+ function createRegisteredApi(name, version, runtime) {
500
+ return {
501
+ name,
502
+ version,
503
+ pinia: runtime.pinia,
504
+ getStore: runtime.storeAPI.getStore,
505
+ hasStore: runtime.storeAPI.hasStore,
506
+ getStoreIds: runtime.storeAPI.getStoreIds,
507
+ resetAll: runtime.storeAPI.resetAll
508
+ };
509
+ }
510
+ function registerEngineApi(engine, name, version, runtime) {
511
+ if (!engine.api?.register) return;
512
+ const api = createRegisteredApi(name, version, runtime);
513
+ engine.api.unregister?.(name);
514
+ if (engine.api.register.length >= 2) {
515
+ engine.api.register(name, api);
516
+ return;
517
+ }
518
+ engine.api.register(api);
519
+ }
520
+ function syncEngineState(engine, name, options, runtime) {
521
+ engine.state?.set?.(storeStateKeys.RUNTIME, runtime);
522
+ engine.state?.set?.(storeStateKeys.PINIA, runtime.pinia);
523
+ engine.state?.set?.(storeStateKeys.API, runtime.storeAPI);
524
+ engine.state?.set?.(storeStateKeys.REGISTRY, runtime.registry);
525
+ engine.state?.set?.(storeStateKeys.BUS, globalEventBus);
526
+ engine.state?.set?.(`plugins.${name}`, runtime.storeAPI);
527
+ engine.state?.set?.(`plugins.${name}.config`, options);
528
+ }
529
+ function clearEngineState(engine, name) {
530
+ engine.state?.delete?.(storeStateKeys.RUNTIME);
531
+ engine.state?.delete?.(storeStateKeys.PINIA);
532
+ engine.state?.delete?.(storeStateKeys.API);
533
+ engine.state?.delete?.(storeStateKeys.REGISTRY);
534
+ engine.state?.delete?.(storeStateKeys.BUS);
535
+ engine.state?.delete?.(`plugins.${name}`);
536
+ engine.state?.delete?.(`plugins.${name}.config`);
537
+ }
538
+ function registerContainerServices(context, runtime) {
539
+ if (!context?.container?.singleton) return;
540
+ try {
541
+ context.container.singleton("pinia", runtime.pinia);
542
+ context.container.singleton("storeAPI", runtime.storeAPI);
543
+ context.container.singleton("storeRegistry", runtime.registry);
544
+ context.container.singleton("storeRuntime", runtime);
545
+ } catch {}
546
+ }
547
+ function createStoreEngineBridge(options) {
548
+ const { createRuntime, debug = false, name = "store", onRuntimeChange, version = "1.0.0" } = options;
549
+ let activeEngine = {};
550
+ let activeContext;
551
+ let runtime = null;
552
+ let runtimeOwner = null;
553
+ const bindRuntime = (nextRuntime, owner) => {
554
+ const previousRuntime = runtime;
555
+ const previousOwner = runtimeOwner;
556
+ runtime = nextRuntime;
557
+ runtimeOwner = owner;
558
+ onRuntimeChange?.(nextRuntime);
559
+ syncEngineState(activeEngine, name, options, nextRuntime);
560
+ registerEngineApi(activeEngine, name, version, nextRuntime);
561
+ registerContainerServices(activeContext, nextRuntime);
562
+ if (previousRuntime && previousRuntime !== nextRuntime && previousOwner === "engine") previousRuntime.dispose?.();
563
+ return nextRuntime;
564
+ };
565
+ const ensureRuntime = () => {
566
+ if (runtime && runtimeOwner === "engine") return runtime;
567
+ return createRuntime();
568
+ };
569
+ const attachToApp = (app) => {
570
+ const installedRuntime = options.getRuntimeFromApp?.(app);
571
+ if (installedRuntime) return bindRuntime(installedRuntime, "external");
572
+ const nextRuntime = ensureRuntime();
573
+ const mountedRuntime = options.attachToApp ? options.attachToApp(app, nextRuntime) : nextRuntime;
574
+ return bindRuntime(mountedRuntime, mountedRuntime === nextRuntime ? "engine" : "external");
575
+ };
576
+ const install = async (context) => {
577
+ activeEngine = resolveEngine(context);
578
+ activeContext = resolvePluginContext(context);
579
+ const app = options.resolveApp ? options.resolveApp(activeEngine, activeContext ?? {}, void 0) : resolveDefaultApp(activeEngine, activeContext);
580
+ if (app && (!options.isApp || options.isApp(app))) attachToApp(app);
581
+ else {
582
+ bindRuntime(ensureRuntime(), "engine");
583
+ activeEngine.events?.once?.("app:created", (payload) => {
584
+ const createdApp = options.resolveApp ? options.resolveApp(activeEngine, activeContext ?? {}, payload) : resolveDefaultApp(activeEngine, activeContext, payload);
585
+ if (createdApp && (!options.isApp || options.isApp(createdApp))) attachToApp(createdApp);
586
+ });
587
+ }
588
+ await activeEngine.events?.emit?.(storeEventKeys.INSTALLED, {
589
+ name,
590
+ version,
591
+ pinia: runtime?.pinia,
592
+ storeAPI: runtime?.storeAPI
593
+ });
594
+ if (debug) activeEngine.logger?.info?.("[StoreEngineBridge] installed");
595
+ };
596
+ const uninstall = async (context) => {
597
+ const engine = context ? resolveEngine(context) : activeEngine;
598
+ engine.api?.unregister?.(name);
599
+ clearEngineState(engine, name);
600
+ await engine.events?.emit?.(storeEventKeys.UNINSTALLED, { name });
601
+ if (runtime && runtimeOwner === "engine") runtime.dispose?.();
602
+ runtime = null;
603
+ runtimeOwner = null;
604
+ onRuntimeChange?.(null);
605
+ if (debug) engine.logger?.info?.("[StoreEngineBridge] uninstalled");
606
+ };
607
+ return {
608
+ attachToApp,
609
+ getRuntime: () => runtime,
610
+ install,
611
+ uninstall
612
+ };
613
+ }
614
+ //#endregion
615
+ //#region src/errors/index.ts
616
+ var StoreErrorCode = /* @__PURE__ */ ((StoreErrorCode2) => {
617
+ StoreErrorCode2["STORE_DISPOSED"] = "STORE_DISPOSED";
618
+ StoreErrorCode2["STORE_NOT_FOUND"] = "STORE_NOT_FOUND";
619
+ StoreErrorCode2["STORE_ALREADY_EXISTS"] = "STORE_ALREADY_EXISTS";
620
+ StoreErrorCode2["INVALID_STATE"] = "INVALID_STATE";
621
+ StoreErrorCode2["INVALID_ACTION"] = "INVALID_ACTION";
622
+ StoreErrorCode2["SERIALIZATION_ERROR"] = "SERIALIZATION_ERROR";
623
+ StoreErrorCode2["DESERIALIZATION_ERROR"] = "DESERIALIZATION_ERROR";
624
+ StoreErrorCode2["STORAGE_ERROR"] = "STORAGE_ERROR";
625
+ StoreErrorCode2["PLUGIN_ERROR"] = "PLUGIN_ERROR";
626
+ StoreErrorCode2["MIDDLEWARE_ERROR"] = "MIDDLEWARE_ERROR";
627
+ StoreErrorCode2["SUBSCRIPTION_ERROR"] = "SUBSCRIPTION_ERROR";
628
+ StoreErrorCode2["TIMEOUT_ERROR"] = "TIMEOUT_ERROR";
629
+ StoreErrorCode2["UNKNOWN_ERROR"] = "UNKNOWN_ERROR";
630
+ return StoreErrorCode2;
631
+ })(StoreErrorCode || {});
632
+ var ErrorSeverity = /* @__PURE__ */ ((ErrorSeverity2) => {
633
+ ErrorSeverity2["WARNING"] = "warning";
634
+ ErrorSeverity2["ERROR"] = "error";
635
+ ErrorSeverity2["FATAL"] = "fatal";
636
+ return ErrorSeverity2;
637
+ })(ErrorSeverity || {});
638
+ var StoreError = class StoreError extends Error {
639
+ /**
640
+ * 创建 Store 错误
641
+ *
642
+ * @param message - 错误消息
643
+ * @param code - 错误代码
644
+ * @param context - 错误上下文
645
+ * @param severity - 错误严重级别
646
+ * @param cause - 原始错误
647
+ */
648
+ constructor(message, code = "UNKNOWN_ERROR", context = {}, severity = "error", cause) {
649
+ super(message);
650
+ this.name = "StoreError";
651
+ this.code = code;
652
+ this.context = {
653
+ ...context,
654
+ timestamp: context.timestamp ?? Date.now()
655
+ };
656
+ this.severity = severity;
657
+ this.cause = cause;
658
+ Object.setPrototypeOf(this, StoreError.prototype);
659
+ if (Error.captureStackTrace) Error.captureStackTrace(this, StoreError);
660
+ }
661
+ /**
662
+ * 转换为 JSON
663
+ */
664
+ toJSON() {
665
+ return {
666
+ name: this.name,
667
+ message: this.message,
668
+ code: this.code,
669
+ context: this.context,
670
+ severity: this.severity,
671
+ stack: this.stack
672
+ };
673
+ }
674
+ /**
675
+ * 格式化错误信息
676
+ */
677
+ format() {
678
+ const parts = [`[${this.code}] ${this.message}`];
679
+ if (this.context.storeId) parts.push(`Store: ${this.context.storeId}`);
680
+ if (this.context.action) parts.push(`Action: ${this.context.action}`);
681
+ return parts.join(" | ");
682
+ }
683
+ };
684
+ var StoreDisposedError = class StoreDisposedError extends StoreError {
685
+ constructor(storeId, action) {
686
+ super(`Store "${storeId}" \u5DF2\u88AB\u9500\u6BC1\uFF0C\u65E0\u6CD5\u6267\u884C\u64CD\u4F5C${action ? `: ${action}` : ""}`, "STORE_DISPOSED", {
687
+ storeId,
688
+ action
689
+ }, "error");
690
+ this.name = "StoreDisposedError";
691
+ Object.setPrototypeOf(this, StoreDisposedError.prototype);
692
+ }
693
+ };
694
+ var StoreNotFoundError = class StoreNotFoundError extends StoreError {
695
+ constructor(storeId) {
696
+ super(`Store "${storeId}" \u4E0D\u5B58\u5728`, "STORE_NOT_FOUND", { storeId }, "error");
697
+ this.name = "StoreNotFoundError";
698
+ Object.setPrototypeOf(this, StoreNotFoundError.prototype);
699
+ }
700
+ };
701
+ var StoreAlreadyExistsError = class StoreAlreadyExistsError extends StoreError {
702
+ constructor(storeId) {
703
+ super(`Store "${storeId}" \u5DF2\u5B58\u5728`, "STORE_ALREADY_EXISTS", { storeId }, "warning");
704
+ this.name = "StoreAlreadyExistsError";
705
+ Object.setPrototypeOf(this, StoreAlreadyExistsError.prototype);
706
+ }
707
+ };
708
+ var InvalidStateError = class InvalidStateError extends StoreError {
709
+ constructor(message, storeId, data) {
710
+ super(message, "INVALID_STATE", {
711
+ storeId,
712
+ data
713
+ }, "error");
714
+ this.name = "InvalidStateError";
715
+ Object.setPrototypeOf(this, InvalidStateError.prototype);
716
+ }
717
+ };
718
+ var SerializationError = class SerializationError extends StoreError {
719
+ constructor(message, cause, storeId) {
720
+ super(message, "SERIALIZATION_ERROR", { storeId }, "error", cause);
721
+ this.name = "SerializationError";
722
+ Object.setPrototypeOf(this, SerializationError.prototype);
723
+ }
724
+ };
725
+ var DeserializationError = class DeserializationError extends StoreError {
726
+ constructor(message, cause, storeId) {
727
+ super(message, "DESERIALIZATION_ERROR", { storeId }, "error", cause);
728
+ this.name = "DeserializationError";
729
+ Object.setPrototypeOf(this, DeserializationError.prototype);
730
+ }
731
+ };
732
+ var StorageError = class StorageError extends StoreError {
733
+ constructor(message, cause, storeId) {
734
+ super(message, "STORAGE_ERROR", { storeId }, "error", cause);
735
+ this.name = "StorageError";
736
+ Object.setPrototypeOf(this, StorageError.prototype);
737
+ }
738
+ };
739
+ var PluginError = class PluginError extends StoreError {
740
+ constructor(message, pluginName, cause) {
741
+ super(message, "PLUGIN_ERROR", { plugin: pluginName }, "error", cause);
742
+ this.name = "PluginError";
743
+ Object.setPrototypeOf(this, PluginError.prototype);
744
+ }
745
+ };
746
+ var MiddlewareError = class MiddlewareError extends StoreError {
747
+ constructor(message, middlewareName, cause) {
748
+ super(message, "MIDDLEWARE_ERROR", { middleware: middlewareName }, "error", cause);
749
+ this.name = "MiddlewareError";
750
+ Object.setPrototypeOf(this, MiddlewareError.prototype);
751
+ }
752
+ };
753
+ var SubscriptionError = class SubscriptionError extends StoreError {
754
+ constructor(message, cause, storeId) {
755
+ super(message, "SUBSCRIPTION_ERROR", { storeId }, "warning", cause);
756
+ this.name = "SubscriptionError";
757
+ Object.setPrototypeOf(this, SubscriptionError.prototype);
758
+ }
759
+ };
760
+ var TimeoutError = class TimeoutError extends StoreError {
761
+ constructor(message, storeId, action) {
762
+ super(message, "TIMEOUT_ERROR", {
763
+ storeId,
764
+ action
765
+ }, "error");
766
+ this.name = "TimeoutError";
767
+ Object.setPrototypeOf(this, TimeoutError.prototype);
768
+ }
769
+ };
770
+ const errorUtils = {
771
+ /**
772
+ * 判断是否为 Store 错误
773
+ */
774
+ isStoreError(error) {
775
+ return error instanceof StoreError;
776
+ },
777
+ /**
778
+ * 判断是否为特定类型的错误
779
+ */
780
+ isErrorCode(error, code) {
781
+ return error instanceof StoreError && error.code === code;
782
+ },
783
+ /**
784
+ * 包装错误为 Store 错误
785
+ */
786
+ wrap(error, code = "UNKNOWN_ERROR", context = {}) {
787
+ if (error instanceof StoreError) return error;
788
+ return new StoreError(error instanceof Error ? error.message : String(error), code, context, "error", error instanceof Error ? error : void 0);
789
+ },
790
+ /**
791
+ * 安全执行函数,捕获并包装错误
792
+ */
793
+ async tryCatch(fn, code = "UNKNOWN_ERROR", context = {}) {
794
+ try {
795
+ return await fn();
796
+ } catch (error) {
797
+ throw errorUtils.wrap(error, code, context);
798
+ }
799
+ },
800
+ /**
801
+ * 创建错误日志记录器
802
+ */
803
+ createLogger(prefix) {
804
+ return {
805
+ error(error) {
806
+ console.error(`[${prefix}]`, error.format());
807
+ if (error.cause) console.error(`[${prefix}] Caused by:`, error.cause);
808
+ },
809
+ warn(error) {
810
+ console.warn(`[${prefix}]`, error.format());
811
+ },
812
+ log(error) {
813
+ if (error.severity === "fatal" || error.severity === "error") this.error(error);
814
+ else this.warn(error);
815
+ }
816
+ };
817
+ }
818
+ };
819
+ //#endregion
820
+ //#region src/utils/debounce-throttle.ts
821
+ function debounce(fn, delay, immediate = false) {
822
+ let timer = null;
823
+ let lastArgs = null;
824
+ const debounced = ((...args) => {
825
+ lastArgs = args;
826
+ if (timer) clearTimeout(timer);
827
+ if (immediate && !timer) {
828
+ fn(...args);
829
+ timer = setTimeout(() => {
830
+ timer = null;
831
+ lastArgs = null;
832
+ }, delay);
833
+ } else timer = setTimeout(() => {
834
+ fn(...args);
835
+ timer = null;
836
+ lastArgs = null;
837
+ }, delay);
838
+ });
839
+ debounced.cancel = () => {
840
+ if (timer) {
841
+ clearTimeout(timer);
842
+ timer = null;
843
+ lastArgs = null;
844
+ }
845
+ };
846
+ debounced.flush = () => {
847
+ if (timer && lastArgs) {
848
+ clearTimeout(timer);
849
+ fn(...lastArgs);
850
+ timer = null;
851
+ lastArgs = null;
852
+ }
853
+ };
854
+ debounced.pending = () => timer !== null;
855
+ return debounced;
856
+ }
857
+ function throttle(fn, interval, options = {}) {
858
+ const { leading = true, trailing = true } = options;
859
+ let timer = null;
860
+ let lastTime = 0;
861
+ let lastArgs = null;
862
+ const throttled = ((...args) => {
863
+ const now = Date.now();
864
+ const remaining = interval - (now - lastTime);
865
+ lastArgs = args;
866
+ if (remaining <= 0 || remaining > interval) {
867
+ if (timer) {
868
+ clearTimeout(timer);
869
+ timer = null;
870
+ }
871
+ lastTime = now;
872
+ if (leading || lastTime !== 0) fn(...args);
873
+ lastArgs = null;
874
+ } else if (!timer && trailing) timer = setTimeout(() => {
875
+ lastTime = trailing ? Date.now() : 0;
876
+ timer = null;
877
+ if (lastArgs) {
878
+ fn(...lastArgs);
879
+ lastArgs = null;
880
+ }
881
+ }, remaining);
882
+ });
883
+ throttled.cancel = () => {
884
+ if (timer) {
885
+ clearTimeout(timer);
886
+ timer = null;
887
+ }
888
+ lastTime = 0;
889
+ lastArgs = null;
890
+ };
891
+ return throttled;
892
+ }
893
+ //#endregion
894
+ //#region src/utils/deep-clone.ts
895
+ const hasOwnProperty = Object.prototype.hasOwnProperty;
896
+ function hasOwnKey(value, key) {
897
+ return hasOwnProperty.call(value, key);
898
+ }
899
+ function isObject(value) {
900
+ return value !== null && typeof value === "object";
901
+ }
902
+ function isPlainObject(value) {
903
+ if (!isObject(value)) return false;
904
+ const proto = Object.getPrototypeOf(value);
905
+ return proto === null || proto === Object.prototype;
906
+ }
907
+ function isStructuredCloneable(value) {
908
+ if (value === null || value === void 0) return true;
909
+ if (typeof value === "boolean" || typeof value === "number" || typeof value === "string") return true;
910
+ if (typeof value === "bigint") return true;
911
+ if (typeof value === "function" || typeof value === "symbol") return false;
912
+ if (value instanceof Date || value instanceof RegExp) return true;
913
+ if (value instanceof ArrayBuffer || value instanceof DataView) return true;
914
+ if (value instanceof Map || value instanceof Set) return true;
915
+ if (ArrayBuffer.isView(value)) return true;
916
+ if (Array.isArray(value)) return value.every((item) => isStructuredCloneable(item));
917
+ if (isPlainObject(value)) return Object.values(value).every((v) => isStructuredCloneable(v));
918
+ return false;
919
+ }
920
+ function deepClone(value, options = {}) {
921
+ const { useStructuredClone: preferStructuredClone = true, cloneFunctions = false, cloneSymbols = false, maxDepth = Infinity, customCloner } = options;
922
+ if (preferStructuredClone && typeof structuredClone === "function" && isStructuredCloneable(value)) try {
923
+ return structuredClone(value);
924
+ } catch {}
925
+ const cache = /* @__PURE__ */ new WeakMap();
926
+ function cloneInternal(val, depth) {
927
+ if (val === null || val === void 0) return val;
928
+ if (typeof val === "boolean" || typeof val === "number" || typeof val === "string") return val;
929
+ if (typeof val === "bigint") return val;
930
+ if (typeof val === "symbol") return cloneSymbols ? Symbol(val.description) : val;
931
+ if (typeof val === "function") return cloneFunctions ? val.bind({}) : val;
932
+ if (depth > maxDepth) return val;
933
+ if (customCloner) {
934
+ const customResult = customCloner(val, (v) => cloneInternal(v, depth + 1));
935
+ if (customResult !== void 0) return customResult;
936
+ }
937
+ if (typeof val === "object" && val !== null) {
938
+ if (cache.has(val)) return cache.get(val);
939
+ }
940
+ if (val instanceof Date) return new Date(val.getTime());
941
+ if (val instanceof RegExp) {
942
+ const result = new RegExp(val.source, val.flags);
943
+ result.lastIndex = val.lastIndex;
944
+ return result;
945
+ }
946
+ if (val instanceof Error) {
947
+ const result = new val.constructor(val.message);
948
+ result.stack = val.stack;
949
+ result.name = val.name;
950
+ return result;
951
+ }
952
+ if (val instanceof Map) {
953
+ const result = /* @__PURE__ */ new Map();
954
+ cache.set(val, result);
955
+ val.forEach((v, k) => {
956
+ result.set(cloneInternal(k, depth + 1), cloneInternal(v, depth + 1));
957
+ });
958
+ return result;
959
+ }
960
+ if (val instanceof Set) {
961
+ const result = /* @__PURE__ */ new Set();
962
+ cache.set(val, result);
963
+ val.forEach((v) => {
964
+ result.add(cloneInternal(v, depth + 1));
965
+ });
966
+ return result;
967
+ }
968
+ if (val instanceof ArrayBuffer) return val.slice(0);
969
+ if (ArrayBuffer.isView(val) && !(val instanceof DataView)) {
970
+ const TypedArrayConstructor = val.constructor;
971
+ return new TypedArrayConstructor(val.buffer.slice(0));
972
+ }
973
+ if (Array.isArray(val)) {
974
+ const result = [];
975
+ cache.set(val, result);
976
+ for (let i = 0; i < val.length; i++) result[i] = cloneInternal(val[i], depth + 1);
977
+ return result;
978
+ }
979
+ if (isPlainObject(val)) {
980
+ const result = {};
981
+ cache.set(val, result);
982
+ const keys = Object.keys(val);
983
+ for (const key of keys) result[key] = cloneInternal(val[key], depth + 1);
984
+ if (cloneSymbols) {
985
+ const symbolKeys = Object.getOwnPropertySymbols(val);
986
+ for (const sym of symbolKeys) result[sym] = cloneInternal(val[sym], depth + 1);
987
+ }
988
+ return result;
989
+ }
990
+ return val;
991
+ }
992
+ return cloneInternal(value, 0);
993
+ }
994
+ function shallowClone(value) {
995
+ if (value === null || value === void 0) return value;
996
+ if (typeof value !== "object") return value;
997
+ if (Array.isArray(value)) return [...value];
998
+ if (value instanceof Map) return new Map(value);
999
+ if (value instanceof Set) return new Set(value);
1000
+ if (value instanceof Date) return new Date(value.getTime());
1001
+ return { ...value };
1002
+ }
1003
+ function deepMerge(target, ...sources) {
1004
+ return deepMergeWithOptions(target, {}, ...sources);
1005
+ }
1006
+ function deepMergeWithOptions(target, options, ...sources) {
1007
+ const { arrayStrategy = "replace", clone = true, maxDepth = Infinity } = options;
1008
+ function mergeInternal(targetObj, sourceObj, depth) {
1009
+ if (depth > maxDepth) return targetObj;
1010
+ for (const key of Object.keys(sourceObj)) {
1011
+ const sourceValue = sourceObj[key];
1012
+ const targetValue = targetObj[key];
1013
+ if (Array.isArray(sourceValue)) if (arrayStrategy === "concat" && Array.isArray(targetValue)) targetObj[key] = [...targetValue, ...sourceValue];
1014
+ else if (arrayStrategy === "merge" && Array.isArray(targetValue)) {
1015
+ const result2 = [...targetValue];
1016
+ sourceValue.forEach((item, index) => {
1017
+ if (isPlainObject(item) && isPlainObject(result2[index])) result2[index] = mergeInternal(result2[index], item, depth + 1);
1018
+ else result2[index] = clone ? deepClone(item) : item;
1019
+ });
1020
+ targetObj[key] = result2;
1021
+ } else targetObj[key] = clone ? deepClone(sourceValue) : sourceValue;
1022
+ else if (isPlainObject(sourceValue)) if (isPlainObject(targetValue)) targetObj[key] = mergeInternal(targetValue, sourceValue, depth + 1);
1023
+ else targetObj[key] = clone ? deepClone(sourceValue) : sourceValue;
1024
+ else targetObj[key] = clone && isObject(sourceValue) ? deepClone(sourceValue) : sourceValue;
1025
+ }
1026
+ return targetObj;
1027
+ }
1028
+ let result = target;
1029
+ for (const source of sources) if (source !== null && source !== void 0) result = mergeInternal(result, source, 0);
1030
+ return result;
1031
+ }
1032
+ function deepEqual(a, b) {
1033
+ if (a === b) return true;
1034
+ if (a === null || b === null || a === void 0 || b === void 0) return a === b;
1035
+ if (typeof a !== typeof b) return false;
1036
+ if (typeof a !== "object") return a === b;
1037
+ if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();
1038
+ if (a instanceof RegExp && b instanceof RegExp) return a.source === b.source && a.flags === b.flags;
1039
+ if (a instanceof Map && b instanceof Map) {
1040
+ if (a.size !== b.size) return false;
1041
+ for (const [key, value] of a) if (!b.has(key) || !deepEqual(value, b.get(key))) return false;
1042
+ return true;
1043
+ }
1044
+ if (a instanceof Set && b instanceof Set) {
1045
+ if (a.size !== b.size) return false;
1046
+ for (const value of a) if (!b.has(value)) return false;
1047
+ return true;
1048
+ }
1049
+ if (Array.isArray(a) && Array.isArray(b)) {
1050
+ if (a.length !== b.length) return false;
1051
+ for (let i = 0; i < a.length; i++) if (!deepEqual(a[i], b[i])) return false;
1052
+ return true;
1053
+ }
1054
+ if (isPlainObject(a) && isPlainObject(b)) {
1055
+ const keysA = Object.keys(a);
1056
+ const keysB = Object.keys(b);
1057
+ if (keysA.length !== keysB.length) return false;
1058
+ for (const key of keysA) {
1059
+ if (!hasOwnKey(b, key)) return false;
1060
+ if (!deepEqual(a[key], b[key])) return false;
1061
+ }
1062
+ return true;
1063
+ }
1064
+ return false;
1065
+ }
1066
+ function deepFreeze(obj) {
1067
+ const propNames = Object.getOwnPropertyNames(obj);
1068
+ for (const name of propNames) {
1069
+ const value = obj[name];
1070
+ if (value && typeof value === "object") deepFreeze(value);
1071
+ }
1072
+ return Object.freeze(obj);
1073
+ }
1074
+ //#endregion
1075
+ //#region src/utils/selector.ts
1076
+ const ARRAY_INDEX_RE = /^\d+$/;
1077
+ function createSelector(selector, equalityFn = Object.is) {
1078
+ let lastState;
1079
+ let lastResult;
1080
+ let initialized = false;
1081
+ return (state) => {
1082
+ if (initialized && lastState === state) return lastResult;
1083
+ const result = selector(state);
1084
+ if (!initialized || !equalityFn(result, lastResult)) lastResult = result;
1085
+ lastState = state;
1086
+ initialized = true;
1087
+ return lastResult;
1088
+ };
1089
+ }
1090
+ function createSelectorWithDeps(dependencies, combiner, options = {}) {
1091
+ const { equalityFn = Object.is, trackHitRate = false } = options;
1092
+ let lastDeps;
1093
+ let lastResult;
1094
+ let initialized = false;
1095
+ let hits = 0;
1096
+ let calls = 0;
1097
+ const selector = (state) => {
1098
+ if (trackHitRate) calls++;
1099
+ const deps = dependencies.map((dep) => dep(state));
1100
+ if (initialized && lastDeps) {
1101
+ let changed = false;
1102
+ for (let i = 0; i < deps.length; i++) if (!Object.is(deps[i], lastDeps[i])) {
1103
+ changed = true;
1104
+ break;
1105
+ }
1106
+ if (!changed) {
1107
+ if (trackHitRate) hits++;
1108
+ return lastResult;
1109
+ }
1110
+ }
1111
+ const result = combiner(...deps);
1112
+ if (!initialized || !equalityFn(result, lastResult)) lastResult = result;
1113
+ lastDeps = deps;
1114
+ initialized = true;
1115
+ return lastResult;
1116
+ };
1117
+ if (trackHitRate) selector.getHitRate = () => {
1118
+ return calls > 0 ? hits / calls : 0;
1119
+ };
1120
+ return selector;
1121
+ }
1122
+ function combineSelectors(selectors, combiner) {
1123
+ return (state) => {
1124
+ return combiner(...selectors.map((selector) => selector(state)));
1125
+ };
1126
+ }
1127
+ function createCachedSelector(selector, options = {}) {
1128
+ const { maxSize = 10 } = options;
1129
+ const cache = /* @__PURE__ */ new Map();
1130
+ const memoizedSelector = (state) => {
1131
+ if (cache.has(state)) {
1132
+ const cached = cache.get(state);
1133
+ cache.delete(state);
1134
+ cache.set(state, cached);
1135
+ return cached;
1136
+ }
1137
+ const result = selector(state);
1138
+ if (cache.size >= maxSize) {
1139
+ const firstKey = cache.keys().next().value;
1140
+ if (firstKey !== void 0) cache.delete(firstKey);
1141
+ }
1142
+ cache.set(state, result);
1143
+ return result;
1144
+ };
1145
+ memoizedSelector.clearCache = () => cache.clear();
1146
+ memoizedSelector.getCacheSize = () => cache.size;
1147
+ return memoizedSelector;
1148
+ }
1149
+ function createMemoizedSelector(selector, options = {}) {
1150
+ return createSelector(selector, options.equalityFn);
1151
+ }
1152
+ function getByPath(obj, path, defaultValue) {
1153
+ if (!path || path.length === 0) return obj;
1154
+ const keys = path.replace(/\[([^\]]+)\]/g, ".$1").split(".").filter(Boolean);
1155
+ let result = obj;
1156
+ for (const key of keys) {
1157
+ if (result === null || result === void 0) return defaultValue;
1158
+ if (typeof result !== "object") return defaultValue;
1159
+ result = result[key];
1160
+ }
1161
+ return result === void 0 ? defaultValue : result;
1162
+ }
1163
+ function setByPath(obj, path, value) {
1164
+ if (!path || path.length === 0) return false;
1165
+ const keys = path.replace(/\[([^\]]+)\]/g, ".$1").split(".").filter(Boolean);
1166
+ let current = obj;
1167
+ for (let i = 0; i < keys.length - 1; i++) {
1168
+ const key = keys[i];
1169
+ const nextKey = keys[i + 1] ?? "";
1170
+ const nextValue = current[key] ?? (ARRAY_INDEX_RE.test(nextKey) ? [] : {});
1171
+ current[key] = nextValue;
1172
+ current = current[key];
1173
+ }
1174
+ const lastKey = keys[keys.length - 1];
1175
+ current[lastKey] = value;
1176
+ return true;
1177
+ }
1178
+ function deleteByPath(obj, path) {
1179
+ if (!path || path.length === 0) return false;
1180
+ const keys = path.replace(/\[([^\]]+)\]/g, ".$1").split(".").filter(Boolean);
1181
+ let current = obj;
1182
+ for (let i = 0; i < keys.length - 1; i++) {
1183
+ const key = keys[i];
1184
+ if (current[key] === void 0 || current[key] === null) return false;
1185
+ current = current[key];
1186
+ }
1187
+ const lastKey = keys[keys.length - 1];
1188
+ if (lastKey in current) {
1189
+ if (Array.isArray(current)) {
1190
+ const index = Number.parseInt(lastKey, 10);
1191
+ if (!Number.isNaN(index)) {
1192
+ current.splice(index, 1);
1193
+ return true;
1194
+ }
1195
+ }
1196
+ delete current[lastKey];
1197
+ return true;
1198
+ }
1199
+ return false;
1200
+ }
1201
+ function hasPath(obj, path) {
1202
+ if (!path || path.length === 0) return true;
1203
+ const keys = path.replace(/\[([^\]]+)\]/g, ".$1").split(".").filter(Boolean);
1204
+ let current = obj;
1205
+ for (const key of keys) {
1206
+ if (current === null || current === void 0) return false;
1207
+ if (typeof current !== "object") return false;
1208
+ if (!(key in current)) return false;
1209
+ current = current[key];
1210
+ }
1211
+ return true;
1212
+ }
1213
+ //#endregion
1214
+ //#region src/middleware/logger.ts
1215
+ const defaultOptions$2 = {
1216
+ logState: true,
1217
+ logAction: true,
1218
+ collapsed: true,
1219
+ timestamp: true,
1220
+ level: "log"
1221
+ };
1222
+ const LOG_COLORS = {
1223
+ prevState: "color: #9E9E9E; font-weight: bold",
1224
+ action: "color: #03A9F4; font-weight: bold",
1225
+ nextState: "color: #4CAF50; font-weight: bold",
1226
+ error: "color: #F44336; font-weight: bold",
1227
+ duration: "color: #9C27B0; font-weight: normal",
1228
+ title: "color: inherit; font-weight: bold"
1229
+ };
1230
+ function formatTime(date) {
1231
+ return `${date.getHours().toString().padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}:${date.getSeconds().toString().padStart(2, "0")}.${date.getMilliseconds().toString().padStart(3, "0")}`;
1232
+ }
1233
+ function formatDuration(startTime, endTime) {
1234
+ const duration = endTime - startTime;
1235
+ if (duration < 1) return "< 1ms";
1236
+ return `${duration.toFixed(2)}ms`;
1237
+ }
1238
+ function safeCloneState(state) {
1239
+ try {
1240
+ return deepClone(state);
1241
+ } catch {
1242
+ return { ...state };
1243
+ }
1244
+ }
1245
+ function createLoggerMiddleware(options = {}) {
1246
+ const opts = {
1247
+ ...defaultOptions$2,
1248
+ ...options
1249
+ };
1250
+ const logger = opts.logger ?? console;
1251
+ return {
1252
+ name: "logger",
1253
+ priority: 0,
1254
+ handler: async (context, next) => {
1255
+ const { storeId, type, state, payload } = context;
1256
+ if (opts.filter && !opts.filter(context)) {
1257
+ await next();
1258
+ return;
1259
+ }
1260
+ const isStateChange = type.startsWith("state:");
1261
+ const isAction = type.startsWith("action:");
1262
+ if (isStateChange && !opts.logState || isAction && !opts.logAction) {
1263
+ await next();
1264
+ return;
1265
+ }
1266
+ const timestamp = opts.timestamp ? formatTime(/* @__PURE__ */ new Date()) : "";
1267
+ const prefix = `[Store: ${storeId}]`;
1268
+ const startTime = performance.now();
1269
+ const prevState = safeCloneState(state);
1270
+ const groupTitle = timestamp ? `${timestamp} ${prefix} ${type}` : `${prefix} ${type}`;
1271
+ const startGroup = () => {
1272
+ if (opts.collapsed && typeof logger.groupCollapsed === "function") logger.groupCollapsed(`%c${groupTitle}`, LOG_COLORS.title);
1273
+ else if (typeof logger.group === "function") logger.group(`%c${groupTitle}`, LOG_COLORS.title);
1274
+ };
1275
+ const endGroup = () => {
1276
+ if (typeof logger.groupEnd === "function") logger.groupEnd();
1277
+ };
1278
+ startGroup();
1279
+ try {
1280
+ const logFn = logger[opts.level ?? "log"] ?? logger.log;
1281
+ if (typeof logFn === "function") {
1282
+ logFn.call(logger, "%c prev state", LOG_COLORS.prevState, prevState);
1283
+ if (payload !== void 0) logFn.call(logger, "%c payload", LOG_COLORS.action, payload);
1284
+ }
1285
+ await next();
1286
+ const endTime = performance.now();
1287
+ if (typeof logFn === "function") {
1288
+ logFn.call(logger, "%c next state", LOG_COLORS.nextState, safeCloneState(context.state));
1289
+ logFn.call(logger, "%c duration", LOG_COLORS.duration, formatDuration(startTime, endTime));
1290
+ }
1291
+ } catch (error) {
1292
+ if (typeof logger.error === "function") logger.error("%c error", LOG_COLORS.error, error);
1293
+ throw new MiddlewareError(`\u65E5\u5FD7\u4E2D\u95F4\u4EF6\u6267\u884C\u9519\u8BEF: ${error instanceof Error ? error.message : String(error)}`, "logger", error instanceof Error ? error : void 0);
1294
+ } finally {
1295
+ endGroup();
1296
+ }
1297
+ }
1298
+ };
1299
+ }
1300
+ function createSimpleLoggerMiddleware(options = {}) {
1301
+ const { includePayload = true, format, filter } = options;
1302
+ return {
1303
+ name: "simple-logger",
1304
+ priority: 0,
1305
+ handler: async (context, next) => {
1306
+ const { storeId, type, payload } = context;
1307
+ if (filter && !filter(context)) {
1308
+ await next();
1309
+ return;
1310
+ }
1311
+ const message = format ? format(context) : `[Store: ${storeId}] ${type}`;
1312
+ if (includePayload && payload !== void 0) console.info(message, payload);
1313
+ else console.info(message);
1314
+ await next();
1315
+ }
1316
+ };
1317
+ }
1318
+ //#endregion
1319
+ //#region src/middleware/middleware-manager.ts
1320
+ function createMiddlewareManager() {
1321
+ const middlewares = /* @__PURE__ */ new Map();
1322
+ let sortedMiddlewares = null;
1323
+ const getSortedMiddlewares = () => {
1324
+ if (sortedMiddlewares === null) sortedMiddlewares = Array.from(middlewares.values()).sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100));
1325
+ return sortedMiddlewares;
1326
+ };
1327
+ const invalidateCache = () => {
1328
+ sortedMiddlewares = null;
1329
+ };
1330
+ const use = (middleware) => {
1331
+ if (middlewares.has(middleware.name)) console.warn(`[Middleware] \u4E2D\u95F4\u4EF6 "${middleware.name}" \u5DF2\u5B58\u5728\uFF0C\u5C06\u88AB\u8986\u76D6`);
1332
+ middlewares.set(middleware.name, middleware);
1333
+ invalidateCache();
1334
+ };
1335
+ const remove = (name) => {
1336
+ if (middlewares.delete(name)) invalidateCache();
1337
+ };
1338
+ const get = (name) => {
1339
+ return middlewares.get(name);
1340
+ };
1341
+ const has = (name) => {
1342
+ return middlewares.has(name);
1343
+ };
1344
+ const execute = async (context) => {
1345
+ const sorted = getSortedMiddlewares();
1346
+ if (sorted.length === 0) return;
1347
+ const dispatch = async (index) => {
1348
+ const middleware = sorted[index];
1349
+ if (!middleware) return;
1350
+ let called = false;
1351
+ const next = async () => {
1352
+ if (called) throw new Error(`[Middleware] next() called multiple times in "${middleware.name}"`);
1353
+ called = true;
1354
+ await dispatch(index + 1);
1355
+ };
1356
+ await middleware.handler(context, next);
1357
+ };
1358
+ await dispatch(0);
1359
+ };
1360
+ const getAll = () => {
1361
+ return getSortedMiddlewares();
1362
+ };
1363
+ const clear = () => {
1364
+ middlewares.clear();
1365
+ invalidateCache();
1366
+ };
1367
+ return {
1368
+ use,
1369
+ remove,
1370
+ get,
1371
+ has,
1372
+ execute,
1373
+ getAll,
1374
+ clear
1375
+ };
1376
+ }
1377
+ let globalMiddlewareManager = null;
1378
+ function getGlobalMiddlewareManager() {
1379
+ if (!globalMiddlewareManager) globalMiddlewareManager = createMiddlewareManager();
1380
+ return globalMiddlewareManager;
1381
+ }
1382
+ function setGlobalMiddlewareManager(manager) {
1383
+ globalMiddlewareManager = manager;
1384
+ }
1385
+ //#endregion
1386
+ //#region src/middleware/persist.ts
1387
+ const defaultOptions$1 = {
1388
+ keyPrefix: "ldesign-store:",
1389
+ storage: "localStorage",
1390
+ debounce: 100,
1391
+ serialize: JSON.stringify,
1392
+ deserialize: JSON.parse
1393
+ };
1394
+ function resolveOptions(options) {
1395
+ return {
1396
+ ...defaultOptions$1,
1397
+ ...options
1398
+ };
1399
+ }
1400
+ function getStorage(type) {
1401
+ if (typeof window === "undefined") return null;
1402
+ return type === "localStorage" ? localStorage : sessionStorage;
1403
+ }
1404
+ function createPersistMiddleware(options = {}) {
1405
+ const opts = resolveOptions(options);
1406
+ const storage = getStorage(opts.storage);
1407
+ const debouncedSave = /* @__PURE__ */ new Map();
1408
+ const getKey = (storeId) => {
1409
+ return `${opts.keyPrefix}${storeId}`;
1410
+ };
1411
+ const filterState = (storeId, state) => {
1412
+ const paths = opts.paths?.[storeId];
1413
+ if (!paths || paths.length === 0) return state;
1414
+ const filtered = {};
1415
+ for (const path of paths) {
1416
+ const keys = path.split(".");
1417
+ let source = state;
1418
+ let target = filtered;
1419
+ for (let i = 0; i < keys.length; i++) {
1420
+ const key = keys[i];
1421
+ if (i === keys.length - 1) target[key] = source?.[key];
1422
+ else {
1423
+ target[key] = target[key] || {};
1424
+ target = target[key];
1425
+ source = source?.[key];
1426
+ }
1427
+ }
1428
+ }
1429
+ return filtered;
1430
+ };
1431
+ const saveState = (storeId, state) => {
1432
+ if (!storage) return;
1433
+ try {
1434
+ const filteredState = filterState(storeId, state);
1435
+ const serialized = opts.serialize(filteredState);
1436
+ storage.setItem(getKey(storeId), serialized);
1437
+ } catch (error) {
1438
+ console.error(`[Persist] \u4FDD\u5B58\u72B6\u6001\u5931\u8D25 (${storeId}):`, error);
1439
+ }
1440
+ };
1441
+ const getDebouncedSave = (storeId) => {
1442
+ let fn = debouncedSave.get(storeId);
1443
+ if (!fn) {
1444
+ fn = debounce((state) => saveState(storeId, state), opts.debounce);
1445
+ debouncedSave.set(storeId, fn);
1446
+ }
1447
+ return fn;
1448
+ };
1449
+ return {
1450
+ name: "persist",
1451
+ priority: 100,
1452
+ handler: async (context, next) => {
1453
+ await next();
1454
+ const { storeId, type, state } = context;
1455
+ if (!type.startsWith("state:")) return;
1456
+ if (opts.stores && !opts.stores.includes(storeId)) return;
1457
+ getDebouncedSave(storeId)(state);
1458
+ }
1459
+ };
1460
+ }
1461
+ function restoreState(storeId, options = {}) {
1462
+ const opts = resolveOptions(options);
1463
+ const storage = getStorage(opts.storage);
1464
+ if (!storage) return null;
1465
+ try {
1466
+ const key = `${opts.keyPrefix}${storeId}`;
1467
+ const data = storage.getItem(key);
1468
+ if (data) return opts.deserialize(data);
1469
+ } catch (error) {
1470
+ console.error(`[Persist] \u6062\u590D\u72B6\u6001\u5931\u8D25 (${storeId}):`, error);
1471
+ }
1472
+ return null;
1473
+ }
1474
+ //#endregion
1475
+ //#region src/middleware/time-travel.ts
1476
+ const defaultOptions = {
1477
+ maxHistory: 100,
1478
+ enabled: true
1479
+ };
1480
+ function createTimeTravelMiddleware(options = {}) {
1481
+ const opts = {
1482
+ ...defaultOptions,
1483
+ ...options
1484
+ };
1485
+ const maxHistory = opts.maxHistory ?? defaultOptions.maxHistory ?? 100;
1486
+ const history = [];
1487
+ let currentIndex = -1;
1488
+ let isTraveling = false;
1489
+ let restoreCallback = () => {};
1490
+ const addSnapshot = (snapshot) => {
1491
+ if (!opts.enabled || isTraveling) return;
1492
+ if (currentIndex < history.length - 1) history.splice(currentIndex + 1);
1493
+ history.push(snapshot);
1494
+ currentIndex = history.length - 1;
1495
+ if (history.length > maxHistory) {
1496
+ history.shift();
1497
+ currentIndex--;
1498
+ }
1499
+ };
1500
+ const controller = {
1501
+ /**
1502
+ * 撤销操作
1503
+ * 将当前指针前移一步,恢复到上一个历史快照状态
1504
+ */
1505
+ undo: () => {
1506
+ if (!controller.canUndo()) return;
1507
+ isTraveling = true;
1508
+ currentIndex--;
1509
+ const snapshot = history[currentIndex];
1510
+ restoreCallback(snapshot.storeId, deepClone(snapshot.state));
1511
+ isTraveling = false;
1512
+ },
1513
+ /**
1514
+ * 重做操作
1515
+ * 将当前指针后移一步,恢复到下一个历史快照状态
1516
+ */
1517
+ redo: () => {
1518
+ if (!controller.canRedo()) return;
1519
+ isTraveling = true;
1520
+ currentIndex++;
1521
+ const snapshot = history[currentIndex];
1522
+ restoreCallback(snapshot.storeId, deepClone(snapshot.state));
1523
+ isTraveling = false;
1524
+ },
1525
+ /**
1526
+ * 跳转到指定历史索引
1527
+ * 将当前指针直接移动到指定位置,恢复对应的快照状态
1528
+ *
1529
+ * @param index - 目标历史索引(0-based)
1530
+ */
1531
+ goto: (index) => {
1532
+ if (index < 0 || index >= history.length) return;
1533
+ isTraveling = true;
1534
+ currentIndex = index;
1535
+ const snapshot = history[currentIndex];
1536
+ restoreCallback(snapshot.storeId, deepClone(snapshot.state));
1537
+ isTraveling = false;
1538
+ },
1539
+ /**
1540
+ * 获取完整的快照历史(返回深拷贝,防止外部修改内部历史记录)
1541
+ * @returns 历史快照数组的深拷贝
1542
+ */
1543
+ getHistory: () => deepClone(history),
1544
+ /**
1545
+ * 获取当前快照指针索引
1546
+ * @returns 当前索引值,-1 表示无快照
1547
+ */
1548
+ getCurrentIndex: () => currentIndex,
1549
+ /**
1550
+ * 判断是否可以撤销
1551
+ * 当前索引大于 0 时,说明前面还有历史快照
1552
+ * @returns 是否可以执行 undo 操作
1553
+ */
1554
+ canUndo: () => currentIndex > 0,
1555
+ /**
1556
+ * 判断是否可以重做
1557
+ * 当前索引小于历史长度 - 1 时,说明后面还有快照
1558
+ * @returns 是否可以执行 redo 操作
1559
+ */
1560
+ canRedo: () => currentIndex < history.length - 1,
1561
+ /**
1562
+ * 清除所有历史快照并重置指针
1563
+ * 通常在 Store 销毁或需要重置历史时调用
1564
+ */
1565
+ clear: () => {
1566
+ history.length = 0;
1567
+ currentIndex = -1;
1568
+ }
1569
+ };
1570
+ controller.__setRestoreCallback = (callback) => {
1571
+ restoreCallback = callback;
1572
+ };
1573
+ return {
1574
+ middleware: {
1575
+ name: "time-travel",
1576
+ priority: 50,
1577
+ /**
1578
+ * 中间件处理函数
1579
+ * 只拦截 "state:" 类型的操作(状态变更操作),其他类型直接放行
1580
+ * 正在时间旅行时也不记录快照,避免循环
1581
+ *
1582
+ * @param context - 中间件上下文,包含 storeId、操作类型、状态等信息
1583
+ * @param next - 调用下一个中间件或最终操作的函数
1584
+ */
1585
+ handler: async (context, next) => {
1586
+ const { storeId, type, state } = context;
1587
+ if (!type.startsWith("state:") || isTraveling) {
1588
+ await next();
1589
+ return;
1590
+ }
1591
+ const snapshot = {
1592
+ timestamp: Date.now(),
1593
+ state: deepClone(state),
1594
+ type,
1595
+ storeId
1596
+ };
1597
+ await next();
1598
+ addSnapshot(snapshot);
1599
+ }
1600
+ },
1601
+ controller
1602
+ };
1603
+ }
1604
+ function setRestoreCallback(controller, callback) {
1605
+ const controllerWithSetter = controller;
1606
+ if (typeof controllerWithSetter.__setRestoreCallback === "function") {
1607
+ controllerWithSetter.__setRestoreCallback(callback);
1608
+ return;
1609
+ }
1610
+ console.warn("[TimeTravel] 请使用 createTimeTravelMiddleware 返回的 controller");
1611
+ }
1612
+ //#endregion
1613
+ //#region src/middleware/validation.ts
1614
+ function createValidationMiddleware(options) {
1615
+ const { rules, onValidationError, blocking = false, patchOnly = false } = options;
1616
+ let lastErrors = [];
1617
+ async function validateState(storeId, state) {
1618
+ const storeRules = rules[storeId];
1619
+ if (!storeRules) return {
1620
+ valid: true,
1621
+ errors: []
1622
+ };
1623
+ const errors = [];
1624
+ for (const [field, fieldRules] of Object.entries(storeRules)) {
1625
+ const ruleList = Array.isArray(fieldRules) ? fieldRules : [fieldRules];
1626
+ const value = state[field];
1627
+ for (const rule of ruleList) try {
1628
+ if (!await rule.validate(value, state)) errors.push({
1629
+ storeId,
1630
+ field,
1631
+ message: rule.message,
1632
+ value
1633
+ });
1634
+ } catch {
1635
+ errors.push({
1636
+ storeId,
1637
+ field,
1638
+ message: rule.message || `Validation error on field "${field}"`,
1639
+ value
1640
+ });
1641
+ }
1642
+ }
1643
+ return {
1644
+ valid: errors.length === 0,
1645
+ errors
1646
+ };
1647
+ }
1648
+ return {
1649
+ middleware: {
1650
+ name: "validation",
1651
+ priority: 5,
1652
+ handler: async (context, next) => {
1653
+ const { storeId, type, state } = context;
1654
+ if (!(patchOnly ? type === "state:patch" : type.startsWith("state:")) || !rules[storeId]) {
1655
+ await next();
1656
+ return;
1657
+ }
1658
+ await next();
1659
+ const result = await validateState(storeId, state);
1660
+ if (!result.valid) {
1661
+ lastErrors = result.errors;
1662
+ onValidationError?.(result);
1663
+ if (blocking) throw new Error(`[Validation] ${storeId}: ${result.errors.map((e) => e.message).join("; ")}`);
1664
+ } else lastErrors = lastErrors.filter((e) => e.storeId !== storeId);
1665
+ }
1666
+ },
1667
+ validate: validateState,
1668
+ getErrors: () => [...lastErrors],
1669
+ clearErrors: () => {
1670
+ lastErrors = [];
1671
+ }
1672
+ };
1673
+ }
1674
+ //#endregion
1675
+ //#region src/plugins/define-plugin.ts
1676
+ function defineStorePlugin(options) {
1677
+ return {
1678
+ name: options.name,
1679
+ version: options.version,
1680
+ description: options.description,
1681
+ install: options.install,
1682
+ uninstall: options.uninstall,
1683
+ onStoreCreated: options.onStoreCreated,
1684
+ onStoreDisposed: options.onStoreDisposed,
1685
+ onStateChange: options.onStateChange
1686
+ };
1687
+ }
1688
+ function createPluginFactory(factory) {
1689
+ return (options) => {
1690
+ return defineStorePlugin(factory(options));
1691
+ };
1692
+ }
1693
+ function composePlugins(plugins) {
1694
+ return {
1695
+ name: "composed-plugins",
1696
+ version: "1.0.0",
1697
+ async install(context, options) {
1698
+ for (const plugin of plugins) await plugin.install(context, options);
1699
+ },
1700
+ async uninstall(context) {
1701
+ for (let i = plugins.length - 1; i >= 0; i--) await plugins[i].uninstall?.(context);
1702
+ },
1703
+ onStoreCreated(store) {
1704
+ plugins.forEach((plugin) => plugin.onStoreCreated?.(store));
1705
+ },
1706
+ onStoreDisposed(store) {
1707
+ plugins.forEach((plugin) => plugin.onStoreDisposed?.(store));
1708
+ },
1709
+ onStateChange(storeId, state, oldState) {
1710
+ plugins.forEach((plugin) => plugin.onStateChange?.(storeId, state, oldState));
1711
+ }
1712
+ };
1713
+ }
1714
+ //#endregion
1715
+ //#region src/plugins/plugin-manager.ts
1716
+ function createPluginManager() {
1717
+ const plugins = /* @__PURE__ */ new Map();
1718
+ const contexts = /* @__PURE__ */ new Map();
1719
+ const use = (plugin, options) => {
1720
+ if (plugins.has(plugin.name)) console.warn(`[Plugin] \u63D2\u4EF6 "${plugin.name}" \u5DF2\u5B58\u5728\uFF0C\u5C06\u88AB\u8986\u76D6`);
1721
+ plugins.set(plugin.name, plugin);
1722
+ const context = {
1723
+ storeManager: {
1724
+ getStore: () => null,
1725
+ hasStore: () => false,
1726
+ getStoreIds: () => []
1727
+ },
1728
+ storeId: "",
1729
+ store: null,
1730
+ options: options || {}
1731
+ };
1732
+ contexts.set(plugin.name, context);
1733
+ };
1734
+ const remove = (name) => {
1735
+ const plugin = plugins.get(name);
1736
+ const context = contexts.get(name);
1737
+ if (plugin && context) plugin.uninstall?.(context);
1738
+ plugins.delete(name);
1739
+ contexts.delete(name);
1740
+ };
1741
+ const get = (name) => {
1742
+ return plugins.get(name);
1743
+ };
1744
+ const has = (name) => {
1745
+ return plugins.has(name);
1746
+ };
1747
+ const getAll = () => {
1748
+ return new Map(plugins);
1749
+ };
1750
+ const size = () => {
1751
+ return plugins.size;
1752
+ };
1753
+ const clear = () => {
1754
+ plugins.forEach((plugin, name) => {
1755
+ const context = contexts.get(name);
1756
+ if (context) plugin.uninstall?.(context);
1757
+ });
1758
+ plugins.clear();
1759
+ contexts.clear();
1760
+ };
1761
+ return {
1762
+ use,
1763
+ remove,
1764
+ get,
1765
+ has,
1766
+ getAll,
1767
+ size,
1768
+ clear
1769
+ };
1770
+ }
1771
+ let globalPluginManager = null;
1772
+ function getGlobalPluginManager() {
1773
+ if (!globalPluginManager) globalPluginManager = createPluginManager();
1774
+ return globalPluginManager;
1775
+ }
1776
+ function setGlobalPluginManager(manager) {
1777
+ globalPluginManager = manager;
1778
+ }
1779
+ //#endregion
1780
+ //#region src/index.ts
1781
+ const version = "1.0.0";
1782
+ const name = "@composy/store-core";
1783
+ //#endregion
1784
+ exports.BaseStore = BaseStore;
1785
+ exports.DeserializationError = DeserializationError;
1786
+ exports.ErrorSeverity = ErrorSeverity;
1787
+ exports.InvalidStateError = InvalidStateError;
1788
+ exports.MiddlewareError = MiddlewareError;
1789
+ exports.PluginError = PluginError;
1790
+ exports.SerializationError = SerializationError;
1791
+ exports.StorageError = StorageError;
1792
+ exports.StoreAlreadyExistsError = StoreAlreadyExistsError;
1793
+ exports.StoreDisposedError = StoreDisposedError;
1794
+ exports.StoreError = StoreError;
1795
+ exports.StoreErrorCode = StoreErrorCode;
1796
+ exports.StoreNotFoundError = StoreNotFoundError;
1797
+ exports.SubscriptionError = SubscriptionError;
1798
+ exports.TimeoutError = TimeoutError;
1799
+ exports.batch = batch;
1800
+ exports.combineSelectors = combineSelectors;
1801
+ exports.composePlugins = composePlugins;
1802
+ exports.createAsyncAction = createAsyncAction;
1803
+ exports.createBatchManager = createBatchManager;
1804
+ exports.createCachedSelector = createCachedSelector;
1805
+ exports.createEventBus = createEventBus;
1806
+ exports.createLoggerMiddleware = createLoggerMiddleware;
1807
+ exports.createMemoizedSelector = createMemoizedSelector;
1808
+ exports.createMiddlewareManager = createMiddlewareManager;
1809
+ exports.createPersistMiddleware = createPersistMiddleware;
1810
+ exports.createPluginFactory = createPluginFactory;
1811
+ exports.createPluginManager = createPluginManager;
1812
+ exports.createPubSub = createPubSub;
1813
+ exports.createPubSubWithValue = createPubSubWithValue;
1814
+ exports.createSelector = createSelector;
1815
+ exports.createSelectorWithDeps = createSelectorWithDeps;
1816
+ exports.createSimpleLoggerMiddleware = createSimpleLoggerMiddleware;
1817
+ exports.createStore = createStore;
1818
+ exports.createStoreEngineBridge = createStoreEngineBridge;
1819
+ exports.createTimeTravelMiddleware = createTimeTravelMiddleware;
1820
+ exports.createValidationMiddleware = createValidationMiddleware;
1821
+ exports.debounce = debounce;
1822
+ exports.deepClone = deepClone;
1823
+ exports.deepEqual = deepEqual;
1824
+ exports.deepFreeze = deepFreeze;
1825
+ exports.deepMerge = deepMerge;
1826
+ exports.deepMergeWithOptions = deepMergeWithOptions;
1827
+ exports.defineStorePlugin = defineStorePlugin;
1828
+ exports.deleteByPath = deleteByPath;
1829
+ exports.errorUtils = errorUtils;
1830
+ exports.getByPath = getByPath;
1831
+ exports.getGlobalBatchManager = getGlobalBatchManager;
1832
+ exports.getGlobalMiddlewareManager = getGlobalMiddlewareManager;
1833
+ exports.getGlobalPluginManager = getGlobalPluginManager;
1834
+ exports.globalEventBus = globalEventBus;
1835
+ exports.hasPath = hasPath;
1836
+ exports.isObject = isObject;
1837
+ exports.isPlainObject = isPlainObject;
1838
+ exports.name = name;
1839
+ exports.restoreState = restoreState;
1840
+ exports.setByPath = setByPath;
1841
+ exports.setGlobalBatchManager = setGlobalBatchManager;
1842
+ exports.setGlobalMiddlewareManager = setGlobalMiddlewareManager;
1843
+ exports.setGlobalPluginManager = setGlobalPluginManager;
1844
+ exports.setRestoreCallback = setRestoreCallback;
1845
+ exports.shallowClone = shallowClone;
1846
+ exports.storeEventKeys = storeEventKeys;
1847
+ exports.storeStateKeys = storeStateKeys;
1848
+ exports.throttle = throttle;
1849
+ exports.version = version;
1850
+ });
1851
+ /*! End of @composy/store-core | Powered by @composy/builder */
1852
+ //# sourceMappingURL=index.js.map