@slux/flux 0.0.0-stage → 0.1.0
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.
- package/CHANGELOG.md +18 -0
- package/LICENSE +21 -0
- package/README.md +161 -2
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +36 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +66 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# @slux/flux
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 首次公开发布 slux 的 25 个包,统一版本为 0.1.0。
|
|
8
|
+
|
|
9
|
+
- 提供框架无关的响应式核心与共享工具,以及 Store、Atom、Proxy、Flux、状态机和 RxJS 六种状态组织方式。
|
|
10
|
+
- 提供持久化、历史记录、跨标签页同步、遥测和开发工具五类 Store 扩展。
|
|
11
|
+
- 提供 React、Vue、Solid、Svelte、Angular、Preact、Ripple、Inferno、Octane、Vitarx、ActView 和 Viewfly 绑定。
|
|
12
|
+
- 提供各包文档与对应示例,并接入发布检查和文档部署工作流。
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- Updated dependencies
|
|
17
|
+
- @slux/core@0.1.0
|
|
18
|
+
- @slux/shared@0.1.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 itmanyong
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,162 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @slux/flux
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
基于 `@slux/core` 的 reducer + dispatch 状态范式层。内部只持有一个 core `Signal<State>` 作为状态与通知源:`dispatch(action)` 同步经过中间件链与 reducer,把 reducer 返回的完整新状态写入该 signal;依赖追踪、批处理与相等性判定全部复用 core。**不依赖 Redux,也不是 Redux 的兼容实现**。
|
|
4
|
+
|
|
5
|
+
## 特性与适用场景
|
|
6
|
+
|
|
7
|
+
| 场景 | 是否适合 | 说明 |
|
|
8
|
+
| ---------------------------------------------------------- | -------- | -------------------------------------------------------------------------- |
|
|
9
|
+
| 状态流转适合写成 `(state, action) => state`,action 可枚举 | 适合 | 状态与 action 类型由 `FluxReducer` 约束,reducer 返回完整新状态 |
|
|
10
|
+
| 需要在派发前/后拦截、替换或阻断 action | 适合 | `options.middleware` 是独立的 dispatch 管道 |
|
|
11
|
+
| 想和 `computed` / `effect` / `batch` 组合 | 适合 | `FluxStore` 满足 core 的 `Subscribable<State>` |
|
|
12
|
+
| 需要细粒度字段订阅、浅合并、draft 草稿修改 | 不适合 | 本包是整状态替换,见「关键语义与边界」;改用 `@slux/store` / `@slux/proxy` |
|
|
13
|
+
| 需要 thunk、异步 action、内置持久化或时间旅行 | 不适合 | 本包不内置,异步完成后自行派发普通 action |
|
|
14
|
+
|
|
15
|
+
## 安装
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
pnpm add @slux/flux
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
| 项 | 值 | 来源 |
|
|
22
|
+
| ------------------ | ---------------------------------------------------------------------- | ------------------------ |
|
|
23
|
+
| 版本 | `0.1.0` | `package.json` |
|
|
24
|
+
| `dependencies` | `@slux/core` `workspace:*`、`@slux/shared` `workspace:*` | `package.json` |
|
|
25
|
+
| `peerDependencies` | 无 | `package.json` |
|
|
26
|
+
| 模块格式 | ESM(`dist/index.js`)+ CJS(`dist/index.cjs`),带 `.d.ts` / `.d.cts` | `package.json` `exports` |
|
|
27
|
+
| 许可 | MIT | `package.json` |
|
|
28
|
+
|
|
29
|
+
`@slux/core`、`@slux/shared` 是本包 `dependencies`,安装时一并带入;下文示例直接 `import` 了 `@slux/core` 的 `computed` / `batch`,**应用代码直接 import 的依赖应显式声明**,可写成 `pnpm add @slux/core @slux/flux`。Node.js 版本要求与跨包通用约定见仓库根 [README.md](../../README.md)。
|
|
30
|
+
|
|
31
|
+
## 快速开始
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { batch, computed } from "@slux/core";
|
|
35
|
+
import { createFluxStore, type FluxReducer } from "@slux/flux";
|
|
36
|
+
|
|
37
|
+
type State = { count: number };
|
|
38
|
+
type Action = { type: "add"; amount: number } | { type: "reset" };
|
|
39
|
+
|
|
40
|
+
const reducer: FluxReducer<State, Action> = (state, action) => (action.type === "add" ? { count: state.count + action.amount } : { count: 0 });
|
|
41
|
+
|
|
42
|
+
const store = createFluxStore(reducer, { count: 0 });
|
|
43
|
+
const doubled = computed(() => store.get().count * 2);
|
|
44
|
+
const stop = store.subscribe((state) => console.log("count:", state.count));
|
|
45
|
+
|
|
46
|
+
batch(() => {
|
|
47
|
+
store.dispatch({ type: "add", amount: 1 });
|
|
48
|
+
store.dispatch({ type: "add", amount: 2 });
|
|
49
|
+
}); // 订阅只收到 count: 3
|
|
50
|
+
|
|
51
|
+
console.log(doubled.get()); // 6
|
|
52
|
+
stop();
|
|
53
|
+
store.destroy();
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## 核心 API
|
|
57
|
+
|
|
58
|
+
`createFluxStore<State, Action extends FluxAction>(reducer, initialState, options?): FluxStore<State, Action>`
|
|
59
|
+
|
|
60
|
+
`FluxAction` 即 `{ readonly type: string }`。`reducer` 是 `(state, action) => State`,`initialState` 是初始状态,`options.middleware` 是可选的只读中间件数组。返回值满足 `Subscribable<State>`,可放进 core 的依赖图。
|
|
61
|
+
|
|
62
|
+
### `FluxStore<State, Action>` 方法
|
|
63
|
+
|
|
64
|
+
| 方法 | 签名 | 行为 |
|
|
65
|
+
| --------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------ |
|
|
66
|
+
| `get()` | `() => State` | 返回当前状态;在 `computed` / `effect` 内读取会收集依赖 |
|
|
67
|
+
| `getState()` | `() => State` | 与 `get()` 是同一个函数 |
|
|
68
|
+
| `getInitialState()` | `() => State` | 返回创建时传入的初始状态引用,不随 `dispatch` 改变 |
|
|
69
|
+
| `subscribe(callback)` | `(cb: (state: State) => void) => () => void` | 订阅**后续**变化,不立即调用;回调只接收当前状态(无 `prevState`);返回幂等取消函数 |
|
|
70
|
+
| `dispatch(action)` | `(action: Action) => Action` | 同步经过中间件链与 reducer;默认返回原 action,中间件可返回另一个 `Action` |
|
|
71
|
+
| `destroy()` | `() => void` | 幂等;取消本实例全部订阅,之后 `dispatch` 被忽略、新增订阅为空实现,读取仍可用 |
|
|
72
|
+
|
|
73
|
+
### 状态与 reducer 语义
|
|
74
|
+
|
|
75
|
+
| 规则 | 说明 |
|
|
76
|
+
| -------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
77
|
+
| 完整替换 | reducer 返回**完整新状态**,不浅合并旧字段、不接收可修改草稿、不应原地修改旧状态 |
|
|
78
|
+
| 初始化 | 直接采用 `initialState`,**不会**用内部虚构 action 调用 reducer |
|
|
79
|
+
| 状态类型 | 支持基础值、对象、`undefined` 与函数;函数状态通过 `source.set(() => nextState)` 作为返回值写入,不会被 core 当成 recipe 执行 |
|
|
80
|
+
| 相等判定 | 沿用 core 默认 `Object.is`:`NaN` 视为相等、`0` 与 `-0` 视为不同;与旧状态相同则不通知 |
|
|
81
|
+
|
|
82
|
+
### Dispatch 中间件
|
|
83
|
+
|
|
84
|
+
`FluxMiddleware<State, Action>` 的形式是 `api => next => action => Action`。
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import { createFluxStore, type FluxMiddleware } from "@slux/flux";
|
|
88
|
+
|
|
89
|
+
type Action = { type: "add"; amount: number };
|
|
90
|
+
const doublePositive: FluxMiddleware<number, Action> = () => (next) => (action) =>
|
|
91
|
+
action.amount <= 0 ? action : next({ ...action, amount: action.amount * 2 });
|
|
92
|
+
|
|
93
|
+
const store = createFluxStore((state: number, action: Action) => state + action.amount, 0, { middleware: [doublePositive] });
|
|
94
|
+
store.dispatch({ type: "add", amount: 2 }); // 4
|
|
95
|
+
store.dispatch({ type: "add", amount: -1 }); // 被阻断,仍为 4
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
| 约定 | 说明 |
|
|
99
|
+
| ---------------------- | -------------------------------------------------------------------- |
|
|
100
|
+
| `api.getState()` | 读取当前状态 |
|
|
101
|
+
| `api.dispatch(action)` | 始终重新进入**完整**中间件链,不是从当前 `next` 之后开始 |
|
|
102
|
+
| `next(action)` | 交给下一环,最内层是 reducer 提交;省略 `next` 即阻断本次提交 |
|
|
103
|
+
| 顺序 | 数组第一项在最外层:`A before → B before → 写入 → B after → A after` |
|
|
104
|
+
| 返回值 | 中间件可拦截、替换 action 或返回另一个合法 `Action` |
|
|
105
|
+
|
|
106
|
+
该契约与 `@slux/store` 的**状态写入中间件不兼容**,两者不能互换。中间件初始化期间禁止 `dispatch`(管道尚未组装完毕,会抛错)。本包不内置 thunk、异步 action 或持久化。
|
|
107
|
+
|
|
108
|
+
## 关键语义与边界
|
|
109
|
+
|
|
110
|
+
- **依赖收集**:`get()` / `getState()` 就是 core `signal.get`,在 `computed` / `effect` 内读取会收集依赖;**仅调用 `dispatch` 不会**把 `effect` 订阅到 Flux 状态。
|
|
111
|
+
- **通知时机**:`dispatch → 中间件 → reducer → signal.set → core 通知`。`subscribe` 不立即调用回调;单次 `dispatch` 在返回前同步完成通知。
|
|
112
|
+
- **批处理**:`@slux/core` 的 `batch` 可合并多次 `dispatch` 的通知;批内读取立即得到最新状态,批次结束只通知最终值。订阅回调没有 `prevState` 参数。
|
|
113
|
+
- **错误**:
|
|
114
|
+
- reducer 抛错 → 不提交状态、不通知,`reducing` 锁在 `finally` 中释放,之后仍可正常派发。
|
|
115
|
+
- reducer 执行期间递归 `dispatch` → 抛 `Error("Cannot dispatch while the reducer is executing")`。
|
|
116
|
+
- 中间件初始化期间 `dispatch` → 抛 `Error("Cannot dispatch while middleware is initializing")`。
|
|
117
|
+
- 订阅回调抛错 → 不回滚已提交状态、不阻断其他回调,错误向调用方抛出。
|
|
118
|
+
- **订阅回调可再次 `dispatch`**:通知阶段 `reducing` 已复位,新通知由 core 在当前轮结束后继续派发;监听器内 `destroy()` 可终止本轮余下通知。
|
|
119
|
+
- **清理**:`destroy()` 取消本实例订阅、清除批内待派发通知;**外部创建的 `computed` / `effect` 仍由调用方清理**。销毁后 `dispatch` 静默忽略(返回原 action),异步任务不会自动取消,其完成后的 `dispatch` 无效。
|
|
120
|
+
- **异步**:不内置 thunk 或异步 action;异步工作完成后派发普通 action 即可,中间件自行持有的外部资源由调用方清理。
|
|
121
|
+
|
|
122
|
+
## 自动导入
|
|
123
|
+
|
|
124
|
+
`createAutoImportApis(prefix?)` 返回 `unplugin-auto-import` 的 `ImportsMap`。登记清单以 `src/auto-import-api.ts` 的 `allImportApis` 为准,当前只有 `createFluxStore`,来源名为 `@slux/flux`(`createAutoImportApis` 本身不登记)。
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
import AutoImport from "unplugin-auto-import/vite";
|
|
128
|
+
import { createAutoImportApis } from "@slux/flux";
|
|
129
|
+
|
|
130
|
+
export default {
|
|
131
|
+
plugins: [AutoImport({ imports: [createAutoImportApis()] })],
|
|
132
|
+
};
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
默认无前缀;传入**以小写字母结尾**的前缀时,别名会把 API 名首字母大写(如 `createAutoImportApis("u")` → `uCreateFluxStore`)。大小写规则由 `@slux/shared` 的 `generateBatchAutoImports` / `createAutoImports` 决定。
|
|
136
|
+
|
|
137
|
+
## 类型导出
|
|
138
|
+
|
|
139
|
+
以 `src/index.ts` 的 `export type` 为准,共 7 个:
|
|
140
|
+
|
|
141
|
+
| 类型 | 用途 |
|
|
142
|
+
| ---------------------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
143
|
+
| `FluxAction` | `{ readonly type: string }`,action 的基础约束 |
|
|
144
|
+
| `FluxReducer<State, Action>` | `(state, action) => State` |
|
|
145
|
+
| `FluxDispatch<Action>` | `(action: Action) => Action` |
|
|
146
|
+
| `FluxMiddlewareAPI<State, Action>` | 中间件可见的 `{ getState(): State; dispatch: FluxDispatch<Action> }` |
|
|
147
|
+
| `FluxMiddleware<State, Action>` | `api => next => dispatch` 的中间件定义 |
|
|
148
|
+
| `FluxStore<State, Action>` | `createFluxStore` 返回类型:`Subscribable<State>` 加上 `getState` / `getInitialState` / `dispatch` / `destroy` |
|
|
149
|
+
| `FluxStoreOptions<State, Action>` | `{ readonly middleware?: readonly FluxMiddleware<State, Action>[] }` |
|
|
150
|
+
|
|
151
|
+
## 不适用的场景 / 与其他包分工
|
|
152
|
+
|
|
153
|
+
- 与 `@slux/core`:core 是响应式运行时(signal / computed / effect / batch / Scope);本包只叠加 reducer + dispatch 范式层。
|
|
154
|
+
- 与 `@slux/store`:store 是「状态与 action 同对象 + 浅合并 + 状态写入中间件」;本包是「整状态替换 + dispatch 管道中间件」,**两套中间件契约互不兼容**。
|
|
155
|
+
- 需要细粒度字段订阅或草稿式局部修改,用 `@slux/store` / `@slux/proxy`;需要 Redux DevTools、时间旅行不在本包范围。
|
|
156
|
+
- 框架绑定只读本实例、写入仍走 `dispatch(action)` 等通用约定见仓库根 [README.md](../../README.md) 的「框架适配 · 通用约定」一节。
|
|
157
|
+
|
|
158
|
+
## 版本、许可与反馈
|
|
159
|
+
|
|
160
|
+
- 版本:`0.1.0`(`package.json`)。
|
|
161
|
+
- 许可:MIT,见仓库根 [LICENSE](../../LICENSE)。
|
|
162
|
+
- 问题反馈:`https://github.com/itmanyong/slux/issues`(`package.json` `bugs.url`)。
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const __rslib_import_meta_url__="u"<typeof document?new(require("url".replace("",""))).URL("file:"+__filename).href:document.currentScript&&document.currentScript.src||new URL("main.js",document.baseURI).href;var __webpack_require__={};__webpack_require__.d=(e,r,t)=>{var _=(r,t)=>{for(var _ in r)__webpack_require__.o(r,_)&&!__webpack_require__.o(e,_)&&Object.defineProperty(e,_,{enumerable:!0,[t]:r[_]})};_(r,"get"),_(t,"value")},__webpack_require__.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),__webpack_require__.r=e=>{"u">typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__={};__webpack_require__.r(__webpack_exports__),__webpack_require__.d(__webpack_exports__,{createAutoImportApis:()=>createAutoImportApis,createFluxStore:()=>createFluxStore});const core_namespaceObject=require("@slux/core");function createFluxStore(e,r,t){let _=(0,core_namespaceObject.signal)(r),o=r,a=new Set,c=!1,i=!1,p=!0,u=r=>{let t;if(c)return r;if(i)throw Error("Cannot dispatch while the reducer is executing");i=!0;try{t=e(o,r)}finally{i=!1}return o=t,"function"==typeof t?_.set(()=>t):_.set(t),r},s=e=>{if(c)return e;if(i)throw Error("Cannot dispatch while the reducer is executing");if(p)throw Error("Cannot dispatch while middleware is initializing");return u(e)},n={get:_.get,getState:_.get,getInitialState:()=>r,dispatch:s,subscribe(e){if(c)return()=>{};let r=_.subscribe(e),t=()=>{r(),a.delete(t)};return a.add(t),t},destroy(){if(!c)for(let e of(c=!0,a))e()}},l={getState:_.get,dispatch:s},b=(t?.middleware??[]).map(e=>e(l));for(let e=b.length-1;e>=0;e--)u=b[e](u);return p=!1,n}const shared_namespaceObject=require("@slux/shared"),allImportApis=["createFluxStore"],createAutoImportApis=(e="")=>(0,shared_namespaceObject.generateBatchAutoImports)([{prefix:e,fromName:"@slux/flux",imports:allImportApis}]);for(var __rspack_i in exports.createAutoImportApis=__webpack_exports__.createAutoImportApis,exports.createFluxStore=__webpack_exports__.createFluxStore,__webpack_exports__)-1===["createAutoImportApis","createFluxStore"].indexOf(__rspack_i)&&(exports[__rspack_i]=__webpack_exports__[__rspack_i]);Object.defineProperty(exports,"__esModule",{value:!0});
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["webpack://webpack/runtime/define_property_getters","webpack://webpack/runtime/has_own_property","webpack://webpack/runtime/make_namespace_object","../src/create-flux-store.ts","../src/auto-import-api.ts"],"sourcesContent":["__webpack_require__.d = (exports, getters, values) => {\n\tvar define = (defs, kind) => {\n\t\tfor(var key in defs) {\n\t\t\tif(__webpack_require__.o(defs, key) && !__webpack_require__.o(exports, key)) {\n\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, [kind]: defs[key] });\n\t\t\t}\n\t\t}\n\t};\n\tdefine(getters, \"get\");\n\tdefine(values, \"value\");\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { signal } from \"@slux/core\";\nimport type { FluxAction, FluxDispatch, FluxReducer, FluxStore, FluxStoreOptions } from \"./types.js\";\n\nexport function createFluxStore<State, Action extends FluxAction>(\n reducer: FluxReducer<State, Action>,\n initialState: State,\n options?: FluxStoreOptions<State, Action>,\n): FluxStore<State, Action> {\n const source = signal(initialState);\n let currentState = initialState;\n const subscriptions = new Set<() => void>();\n let destroyed = false;\n let reducing = false;\n let initializing = true;\n\n const reduce: FluxDispatch<Action> = (action) => {\n if (destroyed) return action;\n if (reducing) throw new Error(\"Cannot dispatch while the reducer is executing\");\n let nextState: State;\n reducing = true;\n try {\n nextState = reducer(currentState, action);\n } finally {\n reducing = false;\n }\n currentState = nextState;\n // 函数状态必须作为返回值写入,不能被 signal 当作 recipe 调用。\n if (typeof nextState === \"function\") source.set(() => nextState);\n else source.set(nextState);\n return action;\n };\n let chain = reduce;\n const dispatch: FluxDispatch<Action> = (action) => {\n if (destroyed) return action;\n if (reducing) throw new Error(\"Cannot dispatch while the reducer is executing\");\n if (initializing) throw new Error(\"Cannot dispatch while middleware is initializing\");\n return chain(action);\n };\n const api: FluxStore<State, Action> = {\n get: source.get,\n getState: source.get,\n getInitialState: () => initialState,\n dispatch,\n subscribe(callback) {\n if (destroyed) return () => {};\n const unsubscribe = source.subscribe(callback);\n const stop = () => {\n unsubscribe();\n subscriptions.delete(stop);\n };\n subscriptions.add(stop);\n return stop;\n },\n destroy() {\n if (destroyed) return;\n destroyed = true;\n for (const stop of subscriptions) stop();\n },\n };\n\n const middlewareAPI = { getState: source.get, dispatch };\n const middleware = (options?.middleware ?? []).map((entry) => entry(middlewareAPI));\n for (let index = middleware.length - 1; index >= 0; index--) {\n chain = middleware[index]!(chain);\n }\n initializing = false;\n return api;\n}\n","import { generateBatchAutoImports } from \"@slux/shared\";\n\nconst allImportApis: string[] = [\"createFluxStore\"];\n\nexport const createAutoImportApis = (prefix: string = \"\") => {\n return generateBatchAutoImports([\n {\n prefix,\n fromName: \"@slux/flux\",\n imports: allImportApis,\n },\n ]);\n};\n"],"names":["__webpack_require__","e","Object","Symbol","createFluxStore","reducer","initialState","options","source","signal","currentState","subscriptions","Set","destroyed","reducing","initializing","chain","action","nextState","Error","dispatch","api","callback","unsubscribe","stop","middlewareAPI","middleware","entry","index","allImportApis","createAutoImportApis","prefix","generateBatchAutoImports"],"mappings":"wPAAAA,CAAAA,oBAAoB,CAAC,CAAG,CAACC,EAAS,EAAS,KAC1C,IAAI,EAAS,CAAC,EAAM,KACnB,IAAI,IAAI,KAAO,EACXD,oBAAoB,CAAC,CAAC,EAAM,IAAQ,CAACA,oBAAoB,CAAC,CAACC,EAAS,IACtEC,OAAO,cAAc,CAACD,EAAS,EAAK,CAAE,WAAY,GAAM,CAAC,EAAK,CAAE,CAAI,CAAC,EAAI,AAAC,EAG7E,EACA,EAAO,EAAS,OAChB,EAAO,EAAQ,QAChB,ECVAD,oBAAoB,CAAC,CAAG,CAAC,EAAK,IAAUE,OAAO,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,EAAK,GCClFF,oBAAoB,CAAC,CAAG,AAACC,IACrB,AAAkB,IAAlB,OAAOE,QAA0BA,OAAO,WAAW,EACrDD,OAAO,cAAc,CAACD,EAASE,OAAO,WAAW,CAAE,CAAE,MAAO,QAAS,GAEtED,OAAO,cAAc,CAACD,EAAS,aAAc,CAAE,MAAO,EAAK,EAC5D,E,sPCHO,SAASG,gBACdC,CAAmC,CACnCC,CAAmB,CACnBC,CAAyC,EAEzC,IAAMC,EAASC,AAAAA,GAAAA,qBAAAA,MAAAA,AAAAA,EAAOH,GAClBI,EAAeJ,EACbK,EAAgB,IAAIC,IACtBC,EAAY,GACZC,EAAW,GACXC,EAAe,GAkBfC,EAhBiC,AAACC,QAGhCC,EAFJ,GAAIL,EAAW,OAAOI,EACtB,GAAIH,EAAU,MAAM,AAAIK,MAAM,kDAE9BL,EAAW,GACX,GAAI,CACFI,EAAYb,EAAQK,EAAcO,EACpC,QAAU,CACRH,EAAW,EACb,CAKA,OAJAJ,EAAeQ,EAEX,AAAqB,YAArB,OAAOA,EAA0BV,EAAO,GAAG,CAAC,IAAMU,GACjDV,EAAO,GAAG,CAACU,GACTD,CACT,EAEMG,EAAiC,AAACH,IACtC,GAAIJ,EAAW,OAAOI,EACtB,GAAIH,EAAU,MAAM,AAAIK,MAAM,kDAC9B,GAAIJ,EAAc,MAAM,AAAII,MAAM,oDAClC,OAAOH,EAAMC,EACf,EACMI,EAAgC,CACpC,IAAKb,EAAO,GAAG,CACf,SAAUA,EAAO,GAAG,CACpB,gBAAiB,IAAMF,EACvBc,SAAAA,EACA,UAAUE,CAAQ,EAChB,GAAIT,EAAW,MAAO,KAAO,EAC7B,IAAMU,EAAcf,EAAO,SAAS,CAACc,GAC/BE,EAAO,KACXD,IACAZ,EAAc,MAAM,CAACa,EACvB,EAEA,OADAb,EAAc,GAAG,CAACa,GACXA,CACT,EACA,UACE,IAAIX,EAEJ,IAAK,IAAMW,KADXX,EAAY,GACOF,GAAea,GACpC,CACF,EAEMC,EAAgB,CAAE,SAAUjB,EAAO,GAAG,CAAEY,SAAAA,CAAS,EACjDM,EAAcnB,AAAAA,CAAAA,GAAS,YAAc,EAAC,EAAG,GAAG,CAAC,AAACoB,GAAUA,EAAMF,IACpE,IAAK,IAAIG,EAAQF,EAAW,MAAM,CAAG,EAAGE,GAAS,EAAGA,IAClDZ,EAAQU,CAAU,CAACE,EAAM,CAAEZ,GAG7B,OADAD,EAAe,GACRM,CACT,C,qDCjEMQ,cAA0B,CAAC,kBAAkB,CAEtCC,qBAAuB,CAACC,EAAiB,EAAE,GAC/CC,AAAAA,GAAAA,uBAAAA,wBAAAA,AAAAA,EAAyB,CAC9B,CACED,OAAAA,EACA,SAAU,aACV,QAASF,aACX,EACD,E"}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Subscribable } from '@slux/core';
|
|
2
|
+
|
|
3
|
+
export declare const createAutoImportApis: (prefix?: string) => {
|
|
4
|
+
[x: string]: (string | [string, string])[];
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export declare function createFluxStore<State, Action extends FluxAction>(reducer: FluxReducer<State, Action>, initialState: State, options?: FluxStoreOptions<State, Action>): FluxStore<State, Action>;
|
|
8
|
+
|
|
9
|
+
export declare type FluxAction = {
|
|
10
|
+
readonly type: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export declare type FluxDispatch<Action extends FluxAction> = (action: Action) => Action;
|
|
14
|
+
|
|
15
|
+
/** 独立的 dispatch 管道,与 @slux/store 的状态写入中间件不兼容。 */
|
|
16
|
+
export declare type FluxMiddleware<State, Action extends FluxAction> = (api: FluxMiddlewareAPI<State, Action>) => (next: FluxDispatch<Action>) => FluxDispatch<Action>;
|
|
17
|
+
|
|
18
|
+
export declare type FluxMiddlewareAPI<State, Action extends FluxAction> = {
|
|
19
|
+
getState(): State;
|
|
20
|
+
dispatch: FluxDispatch<Action>;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export declare type FluxReducer<State, Action extends FluxAction> = (state: State, action: Action) => State;
|
|
24
|
+
|
|
25
|
+
export declare type FluxStore<State, Action extends FluxAction> = Subscribable<State> & {
|
|
26
|
+
getState(): State;
|
|
27
|
+
getInitialState(): State;
|
|
28
|
+
dispatch: FluxDispatch<Action>;
|
|
29
|
+
destroy(): void;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export declare type FluxStoreOptions<State, Action extends FluxAction> = {
|
|
33
|
+
readonly middleware?: readonly FluxMiddleware<State, Action>[];
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export { }
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Subscribable } from '@slux/core';
|
|
2
|
+
|
|
3
|
+
export declare const createAutoImportApis: (prefix?: string) => {
|
|
4
|
+
[x: string]: (string | [string, string])[];
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export declare function createFluxStore<State, Action extends FluxAction>(reducer: FluxReducer<State, Action>, initialState: State, options?: FluxStoreOptions<State, Action>): FluxStore<State, Action>;
|
|
8
|
+
|
|
9
|
+
export declare type FluxAction = {
|
|
10
|
+
readonly type: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export declare type FluxDispatch<Action extends FluxAction> = (action: Action) => Action;
|
|
14
|
+
|
|
15
|
+
/** 独立的 dispatch 管道,与 @slux/store 的状态写入中间件不兼容。 */
|
|
16
|
+
export declare type FluxMiddleware<State, Action extends FluxAction> = (api: FluxMiddlewareAPI<State, Action>) => (next: FluxDispatch<Action>) => FluxDispatch<Action>;
|
|
17
|
+
|
|
18
|
+
export declare type FluxMiddlewareAPI<State, Action extends FluxAction> = {
|
|
19
|
+
getState(): State;
|
|
20
|
+
dispatch: FluxDispatch<Action>;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export declare type FluxReducer<State, Action extends FluxAction> = (state: State, action: Action) => State;
|
|
24
|
+
|
|
25
|
+
export declare type FluxStore<State, Action extends FluxAction> = Subscribable<State> & {
|
|
26
|
+
getState(): State;
|
|
27
|
+
getInitialState(): State;
|
|
28
|
+
dispatch: FluxDispatch<Action>;
|
|
29
|
+
destroy(): void;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export declare type FluxStoreOptions<State, Action extends FluxAction> = {
|
|
33
|
+
readonly middleware?: readonly FluxMiddleware<State, Action>[];
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export { }
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{signal as e}from"@slux/core";import{generateBatchAutoImports as t}from"@slux/shared";function r(t,r,i){let o=e(r),n=r,l=new Set,u=!1,a=!1,s=!0,f=e=>{let r;if(u)return e;if(a)throw Error("Cannot dispatch while the reducer is executing");a=!0;try{r=t(n,e)}finally{a=!1}return n=r,"function"==typeof r?o.set(()=>r):o.set(r),e},c=e=>{if(u)return e;if(a)throw Error("Cannot dispatch while the reducer is executing");if(s)throw Error("Cannot dispatch while middleware is initializing");return f(e)},d={get:o.get,getState:o.get,getInitialState:()=>r,dispatch:c,subscribe(e){if(u)return()=>{};let t=o.subscribe(e),r=()=>{t(),l.delete(r)};return l.add(r),r},destroy(){if(!u)for(let e of(u=!0,l))e()}},h={getState:o.get,dispatch:c},g=(i?.middleware??[]).map(e=>e(h));for(let e=g.length-1;e>=0;e--)f=g[e](f);return s=!1,d}let i=["createFluxStore"],o=(e="")=>t([{prefix:e,fromName:"@slux/flux",imports:i}]);export{o as createAutoImportApis,r as createFluxStore};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/create-flux-store.ts","../src/auto-import-api.ts"],"sourcesContent":["import { signal } from \"@slux/core\";\nimport type { FluxAction, FluxDispatch, FluxReducer, FluxStore, FluxStoreOptions } from \"./types.js\";\n\nexport function createFluxStore<State, Action extends FluxAction>(\n reducer: FluxReducer<State, Action>,\n initialState: State,\n options?: FluxStoreOptions<State, Action>,\n): FluxStore<State, Action> {\n const source = signal(initialState);\n let currentState = initialState;\n const subscriptions = new Set<() => void>();\n let destroyed = false;\n let reducing = false;\n let initializing = true;\n\n const reduce: FluxDispatch<Action> = (action) => {\n if (destroyed) return action;\n if (reducing) throw new Error(\"Cannot dispatch while the reducer is executing\");\n let nextState: State;\n reducing = true;\n try {\n nextState = reducer(currentState, action);\n } finally {\n reducing = false;\n }\n currentState = nextState;\n // 函数状态必须作为返回值写入,不能被 signal 当作 recipe 调用。\n if (typeof nextState === \"function\") source.set(() => nextState);\n else source.set(nextState);\n return action;\n };\n let chain = reduce;\n const dispatch: FluxDispatch<Action> = (action) => {\n if (destroyed) return action;\n if (reducing) throw new Error(\"Cannot dispatch while the reducer is executing\");\n if (initializing) throw new Error(\"Cannot dispatch while middleware is initializing\");\n return chain(action);\n };\n const api: FluxStore<State, Action> = {\n get: source.get,\n getState: source.get,\n getInitialState: () => initialState,\n dispatch,\n subscribe(callback) {\n if (destroyed) return () => {};\n const unsubscribe = source.subscribe(callback);\n const stop = () => {\n unsubscribe();\n subscriptions.delete(stop);\n };\n subscriptions.add(stop);\n return stop;\n },\n destroy() {\n if (destroyed) return;\n destroyed = true;\n for (const stop of subscriptions) stop();\n },\n };\n\n const middlewareAPI = { getState: source.get, dispatch };\n const middleware = (options?.middleware ?? []).map((entry) => entry(middlewareAPI));\n for (let index = middleware.length - 1; index >= 0; index--) {\n chain = middleware[index]!(chain);\n }\n initializing = false;\n return api;\n}\n","import { generateBatchAutoImports } from \"@slux/shared\";\n\nconst allImportApis: string[] = [\"createFluxStore\"];\n\nexport const createAutoImportApis = (prefix: string = \"\") => {\n return generateBatchAutoImports([\n {\n prefix,\n fromName: \"@slux/flux\",\n imports: allImportApis,\n },\n ]);\n};\n"],"names":["createFluxStore","reducer","initialState","options","source","signal","currentState","subscriptions","Set","destroyed","reducing","initializing","chain","action","nextState","Error","dispatch","api","callback","unsubscribe","stop","middlewareAPI","middleware","entry","index","allImportApis","createAutoImportApis","prefix","generateBatchAutoImports"],"mappings":"4FAGO,SAASA,EACdC,CAAmC,CACnCC,CAAmB,CACnBC,CAAyC,EAEzC,IAAMC,EAASC,EAAOH,GAClBI,EAAeJ,EACbK,EAAgB,IAAIC,IACtBC,EAAY,GACZC,EAAW,GACXC,EAAe,GAkBfC,EAhBiC,AAACC,QAGhCC,EAFJ,GAAIL,EAAW,OAAOI,EACtB,GAAIH,EAAU,MAAM,AAAIK,MAAM,kDAE9BL,EAAW,GACX,GAAI,CACFI,EAAYb,EAAQK,EAAcO,EACpC,QAAU,CACRH,EAAW,EACb,CAKA,OAJAJ,EAAeQ,EAEX,AAAqB,YAArB,OAAOA,EAA0BV,EAAO,GAAG,CAAC,IAAMU,GACjDV,EAAO,GAAG,CAACU,GACTD,CACT,EAEMG,EAAiC,AAACH,IACtC,GAAIJ,EAAW,OAAOI,EACtB,GAAIH,EAAU,MAAM,AAAIK,MAAM,kDAC9B,GAAIJ,EAAc,MAAM,AAAII,MAAM,oDAClC,OAAOH,EAAMC,EACf,EACMI,EAAgC,CACpC,IAAKb,EAAO,GAAG,CACf,SAAUA,EAAO,GAAG,CACpB,gBAAiB,IAAMF,EACvBc,SAAAA,EACA,UAAUE,CAAQ,EAChB,GAAIT,EAAW,MAAO,KAAO,EAC7B,IAAMU,EAAcf,EAAO,SAAS,CAACc,GAC/BE,EAAO,KACXD,IACAZ,EAAc,MAAM,CAACa,EACvB,EAEA,OADAb,EAAc,GAAG,CAACa,GACXA,CACT,EACA,UACE,IAAIX,EAEJ,IAAK,IAAMW,KADXX,EAAY,GACOF,GAAea,GACpC,CACF,EAEMC,EAAgB,CAAE,SAAUjB,EAAO,GAAG,CAAEY,SAAAA,CAAS,EACjDM,EAAcnB,AAAAA,CAAAA,GAAS,YAAc,EAAC,EAAG,GAAG,CAAC,AAACoB,GAAUA,EAAMF,IACpE,IAAK,IAAIG,EAAQF,EAAW,MAAM,CAAG,EAAGE,GAAS,EAAGA,IAClDZ,EAAQU,CAAU,CAACE,EAAM,CAAEZ,GAG7B,OADAD,EAAe,GACRM,CACT,CCjEA,IAAMQ,EAA0B,CAAC,kBAAkB,CAEtCC,EAAuB,CAACC,EAAiB,EAAE,GAC/CC,EAAyB,CAC9B,CACED,OAAAA,EACA,SAAU,aACV,QAASF,CACX,EACD,S"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,69 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slux/flux",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "基于 slux core 的 reducer 与 dispatch 范式层",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"keywords": [
|
|
7
|
+
"slux",
|
|
8
|
+
"flux",
|
|
9
|
+
"reducer",
|
|
10
|
+
"state-management"
|
|
11
|
+
],
|
|
12
|
+
"author": "itmanyong <itmanyong@gmail.com>",
|
|
13
|
+
"contributors": [
|
|
14
|
+
"itmanyong <itmanyong@gmail.com>"
|
|
15
|
+
],
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"homepage": "https://www.npmjs.com/package/@slux/flux",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/itmanyong/slux.git",
|
|
24
|
+
"directory": "packages/flux"
|
|
25
|
+
},
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/itmanyong/slux/issues"
|
|
28
|
+
},
|
|
29
|
+
"type": "module",
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"README.md",
|
|
33
|
+
"CHANGELOG.md",
|
|
34
|
+
"package.json"
|
|
35
|
+
],
|
|
36
|
+
"main": "./dist/index.cjs",
|
|
37
|
+
"module": "./dist/index.js",
|
|
38
|
+
"types": "./dist/index.d.ts",
|
|
39
|
+
"exports": {
|
|
40
|
+
".": {
|
|
41
|
+
"import": {
|
|
42
|
+
"types": "./dist/index.d.ts",
|
|
43
|
+
"default": "./dist/index.js"
|
|
44
|
+
},
|
|
45
|
+
"require": {
|
|
46
|
+
"types": "./dist/index.d.cts",
|
|
47
|
+
"default": "./dist/index.cjs"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"./package.json": "./package.json"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@slux/core": "0.1.0",
|
|
54
|
+
"@slux/shared": "0.1.0"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"rstack": "0.9.0",
|
|
58
|
+
"typescript": "7.1.0-beta"
|
|
59
|
+
},
|
|
60
|
+
"scripts": {
|
|
61
|
+
"dev": "rs lib -w",
|
|
62
|
+
"build": "rs lib",
|
|
63
|
+
"test": "rs test",
|
|
64
|
+
"lint": "rs lint",
|
|
65
|
+
"fmt": "rs fmt",
|
|
66
|
+
"typecheck": "tsc --noEmit",
|
|
67
|
+
"clean": "rm -rf dist node_modules .turbo"
|
|
68
|
+
}
|
|
6
69
|
}
|