@slux/storage 0.0.0-stage → 0.1.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.
- package/CHANGELOG.md +33 -0
- package/LICENSE +21 -0
- package/README.md +237 -2
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +96 -0
- package/dist/index.d.ts +96 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +71 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# @slux/storage
|
|
2
|
+
|
|
3
|
+
## 0.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 207e315: 基于 `v0.1.0` 之后的改动,完善包文档、交互示例和发布流程。
|
|
8
|
+
|
|
9
|
+
- 为 25 个包的 README 补充统一导航;文档站增加各包更新日志、版本发行说明和可在站内体验的示例入口。
|
|
10
|
+
- 整理示例应用的共享外壳与主题交互,并将示例图标替换为透明背景的 SVG。
|
|
11
|
+
- 修正自动导入 API 清单生成规则,排除需要显式调用的 `createAutoImportApis` 工厂函数,并统一 Viewfly 清单顺序。
|
|
12
|
+
- 发布工作流改为 GitHub OIDC 授信发布:预先打包各包、独立执行发布任务,并在发布成功后创建 GitHub Release 草稿。
|
|
13
|
+
|
|
14
|
+
- Updated dependencies [207e315]
|
|
15
|
+
- @slux/shared@0.1.1
|
|
16
|
+
- @slux/store@0.1.1
|
|
17
|
+
|
|
18
|
+
## 0.1.0
|
|
19
|
+
|
|
20
|
+
### Minor Changes
|
|
21
|
+
|
|
22
|
+
- 首次公开发布 slux 的 25 个包,统一版本为 0.1.0。
|
|
23
|
+
|
|
24
|
+
- 提供框架无关的响应式核心与共享工具,以及 Store、Atom、Proxy、Flux、状态机和 RxJS 六种状态组织方式。
|
|
25
|
+
- 提供持久化、历史记录、跨标签页同步、遥测和开发工具五类 Store 扩展。
|
|
26
|
+
- 提供 React、Vue、Solid、Svelte、Angular、Preact、Ripple、Inferno、Octane、Vitarx、ActView 和 Viewfly 绑定。
|
|
27
|
+
- 提供各包文档与对应示例,并接入发布检查和文档部署工作流。
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- Updated dependencies
|
|
32
|
+
- @slux/shared@0.1.0
|
|
33
|
+
- @slux/store@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,238 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @slux/storage
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
为 `@slux/store` 提供持久化中间件 `persist`:把状态写入可插拔后端,并在创建 Store 时恢复。同步与异步后端统一处理,支持字段裁剪、版本迁移、合并策略与错误观察。它作为 `@slux/store` 中间件接入,复用 Store 的公共契约,本文只写本包差异。
|
|
4
|
+
|
|
5
|
+
> 中间件的组合方式、实例归属、销毁清理链与顺序等通用约定见仓库根 [README](../../README.md) 的「Store 中间件 · 通用契约」与「本地开发」。
|
|
6
|
+
|
|
7
|
+
## 特性与适用场景
|
|
8
|
+
|
|
9
|
+
| 场景 | 是否适合 | 说明 |
|
|
10
|
+
| ---------------------------------------- | -------- | ------------------------------------------------------ |
|
|
11
|
+
| 刷新后恢复 UI 偏好、草稿、计数器 | 适合 | 创建 Store 时自动 hydration,写入后自动保存 |
|
|
12
|
+
| 需要可替换的存储介质 | 适合 | 内置 5 个后端,也可传入自定义 `StorageAdapter` |
|
|
13
|
+
| 需要版本升级后的旧数据迁移 | 适合 | `version` + `migrate`,支持同步与异步迁移 |
|
|
14
|
+
| 状态含 action 函数或不可 JSON 序列化的值 | 需处理 | 用 `partialize` 剔除,否则默认 `JSON.stringify` 会报错 |
|
|
15
|
+
| 只需要内存态、无持久化需求 | 不适合 | 直接用 `createStore` 即可 |
|
|
16
|
+
| 需要跨标签实时同步 | 不适合 | 使用 `@slux/tab-sync` |
|
|
17
|
+
| 需要撤销重做 | 不适合 | 使用 `@slux/history` |
|
|
18
|
+
|
|
19
|
+
## 安装
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
pnpm add @slux/store @slux/storage
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
- **运行时依赖**(`dependencies`):`@slux/store`、`@slux/shared`。
|
|
26
|
+
- **无 `peerDependencies`**:`@slux/core` 只是本包的开发依赖;示例里直接 import 的 `@slux/store` 建议在应用侧显式声明。
|
|
27
|
+
- **宿主能力**:`localStorage`、`sessionStorage`、`document.cookie`、`indexedDB` 由运行环境提供,不是 npm 依赖;缺失时按「专属语义与边界」降级。
|
|
28
|
+
|
|
29
|
+
## 快速开始
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { createStore } from "@slux/store";
|
|
33
|
+
import { localStorageBackend, persist } from "@slux/storage";
|
|
34
|
+
|
|
35
|
+
type Prefs = { theme: string; count: number };
|
|
36
|
+
|
|
37
|
+
const persistence = persist<Prefs>({
|
|
38
|
+
key: "prefs",
|
|
39
|
+
storage: localStorageBackend(),
|
|
40
|
+
partialize: ({ theme }) => ({ theme }),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const store = createStore<Prefs>(() => ({ theme: "light", count: 0 }), {
|
|
44
|
+
middleware: [persistence],
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
store.setState({ theme: "dark" }); // 提交后写入 localStorage,只保存 theme
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## 核心 API
|
|
51
|
+
|
|
52
|
+
### `persist<T>(options: PersistOptions<T>): PersistMiddleware<T>`
|
|
53
|
+
|
|
54
|
+
| 配置 | 类型 | 默认值 | 说明 |
|
|
55
|
+
| --------------- | ----------------------------------------------------------- | ---------------------------- | ---------------------------------------- |
|
|
56
|
+
| `key` | `string` | 必填 | 存储键 |
|
|
57
|
+
| `storage` | `StorageAdapter` | `memoryStorage()` | 同步或异步后端 |
|
|
58
|
+
| `partialize` | `(state: T) => Partial<T>` | 全部状态 | 选择要保存的字段 |
|
|
59
|
+
| `merge` | `(persisted: Partial<T>, current: T) => T` | `(p, c) => ({ ...c, ...p })` | 恢复时的合并策略,持久化字段覆盖当前字段 |
|
|
60
|
+
| `version` | `number` | `0` | 写入 envelope 的当前数据版本 |
|
|
61
|
+
| `migrate` | `(persisted, version) => Partial<T> \| Promise<Partial<T>>` | 无 | 版本不同时迁移;未提供则忽略旧数据 |
|
|
62
|
+
| `serialize` | `(envelope: PersistEnvelope<Partial<T>>) => string` | `JSON.stringify` | 序列化 `{ state, version }` |
|
|
63
|
+
| `deserialize` | `(raw: string) => PersistEnvelope<Partial<T>>` | `JSON.parse` | 反序列化;业务字段结构可在此校验 |
|
|
64
|
+
| `onError` | `(error: PersistError) => void` | 忽略 | 接收错误码、描述与原始原因 |
|
|
65
|
+
| `skipHydration` | `boolean` | `false` | 跳过 `init` 时的自动恢复,适合 SSR |
|
|
66
|
+
|
|
67
|
+
`PersistMiddleware<T>` 在满足 `@slux/store` 的 `Middleware<T>`(`name`、`init`、`onSet`、`onDestroy`)之外,还提供一组控制器方法:
|
|
68
|
+
|
|
69
|
+
| 方法 | 签名 | 说明 |
|
|
70
|
+
| -------------- | ---------------------------------------------- | -------------------------------------------------------------------- |
|
|
71
|
+
| `rehydrate` | `() => Promise<void>` | 重新读取并合并;进行中重复调用复用同一次读取,等待异步迁移完成 |
|
|
72
|
+
| `hasHydrated` | `() => boolean` | 本轮恢复结束后为 `true`,包含失败与空数据情形 |
|
|
73
|
+
| `onHydrate` | `(callback: (state: T) => void) => () => void` | 订阅每次恢复完成;已恢复时在微任务中通知当前状态;取消函数可重复调用 |
|
|
74
|
+
| `clearStorage` | `() => Promise<void>` | 等此前异步写入结束后删除当前键,不修改内存状态 |
|
|
75
|
+
|
|
76
|
+
### 五个内置后端
|
|
77
|
+
|
|
78
|
+
| 工厂 | 返回类型 | 说明 |
|
|
79
|
+
| ---------------------------- | ---------------------- | ------------------------------------------------------ |
|
|
80
|
+
| `memoryStorage()` | `MemoryStorageAdapter` | 每个实例独立的 `Map`,同步;额外提供 `clear()` |
|
|
81
|
+
| `localStorageBackend()` | `StorageAdapter` | 包装浏览器 `localStorage`,同步 |
|
|
82
|
+
| `sessionStorageBackend()` | `StorageAdapter` | 包装浏览器 `sessionStorage`,同步 |
|
|
83
|
+
| `cookieStorage(options?)` | `StorageAdapter` | 使用 `document.cookie`,键与值做 URL 编码,同步 |
|
|
84
|
+
| `indexedDBStorage(options?)` | `StorageAdapter` | 懒加载并复用连接,事务 `oncomplete` 后才确认成功,异步 |
|
|
85
|
+
|
|
86
|
+
后端配置项(均在 `types.ts` 定义):
|
|
87
|
+
|
|
88
|
+
| 配置 | 字段 | 默认值 |
|
|
89
|
+
| ------------------------- | ---------------------------------------------------------------------------------- | ----------------------------------- |
|
|
90
|
+
| `CookieStorageOptions` | `maxAge?`、`path?`、`sameSite?: "strict" \| "lax" \| "none"`、`secure?`、`domain?` | `path: "/"` |
|
|
91
|
+
| `IndexedDBStorageOptions` | `dbName?`、`storeName?`、`dbVersion?` | `"slux-storage"` / `"keyval"` / `1` |
|
|
92
|
+
|
|
93
|
+
Cookie 的 `removeItem` 用 `max-age=0` 删除,并沿用相同的 `path`、`domain`、`secure`、`sameSite`。IndexedDB 在收到 `versionchange` 事件时会释放旧连接,连接失败后允许重试。
|
|
94
|
+
|
|
95
|
+
### 自定义 `StorageAdapter`
|
|
96
|
+
|
|
97
|
+
三个方法都可以同步返回或返回 `Promise`,`persist` 会分别处理:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import type { StorageAdapter } from "@slux/storage";
|
|
101
|
+
|
|
102
|
+
const adapter: StorageAdapter = {
|
|
103
|
+
getItem: (key) => Promise.resolve(null),
|
|
104
|
+
setItem: async (key, value) => {
|
|
105
|
+
/* 保存字符串 */
|
|
106
|
+
},
|
|
107
|
+
removeItem: async (key) => {
|
|
108
|
+
/* 删除键 */
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
服务端读取请求 Cookie、写响应 Cookie 或接入自定义远端存储,都通过实现这个契约完成;浏览器后端不会自动读取服务端请求上下文。
|
|
114
|
+
|
|
115
|
+
## 专属语义与边界
|
|
116
|
+
|
|
117
|
+
**恢复(hydration)**:`init` 时若 `skipHydration` 为 `false` 自动调用 `rehydrate()`。同步后端在 `createStore` 返回前即完成恢复;异步后端先返回初始状态,`Promise` 就绪后再合并。默认 `merge` 是浅合并且持久化字段覆盖当前字段,因此**异步恢复会覆盖等待期间修改过的同名字段**;需要保留本地字段时提供 `merge`,或在 hydration 完成前暂缓编辑。
|
|
118
|
+
|
|
119
|
+
**envelope 校验**:入口只校验顶层对象含 `state`、`version` 是有限数字;缺 `version` 按 `0` 处理;`raw` 为 `null` 或空字符串视为无数据。业务字段的结构由应用自己的 `deserialize` 或 `migrate` 校验。非法 JSON、非对象、`version` 非数字都会报 `DeserializationFailed` 且保持初始状态。
|
|
120
|
+
|
|
121
|
+
**版本迁移**:`envelope.version === version` 时直接合并;版本不同且未提供 `migrate` 时忽略旧数据(仍标记 hydrated);提供 `migrate` 时,同步返回值或 `Promise` 结果都会被应用,之后的写入使用当前 `version`。
|
|
122
|
+
|
|
123
|
+
**写入时机与队列**:`onSet` 先 `next(partial)` 提交,再 `persistState()`;序列化失败只报 `SerializationFailed`,不回滚已提交的内存状态。异步 `setItem` / `removeItem` 通过 `writeTail` 按调用顺序串行,避免旧写入覆盖新值;`clearStorage()` 排在此前写入之后;一次写入失败不阻塞后续写入。
|
|
124
|
+
|
|
125
|
+
**错误**:`PERSIST_ERROR_CODE` 提供 `StorageReadFailed`、`StorageWriteFailed`、`SerializationFailed`、`DeserializationFailed`、`MigrationFailed`。删除失败归为写入错误,`partialize` 失败归为序列化错误。`onError` 回调自身抛错被隔离,不影响状态更新与其他观察器。
|
|
126
|
+
|
|
127
|
+
**销毁**:`destroy()` 后取消尚未开始的写入与删除、清空 hydration 回调、让等待中的 `rehydrate()` 立即 resolve,并忽略迟到的恢复结果。已经交给后端的操作无法撤回。
|
|
128
|
+
|
|
129
|
+
**SSR 与后端降级**:`skipHydration: true` 适合服务端。Web Storage 与 cookie 后端在 `localStorage` / `sessionStorage` / `document` 缺失、访问被拒或容量不足时返回 `null` 或忽略写入,这类被后端吞掉的错误**不会**触发 `onError`;`indexedDBStorage()` 在无 `indexedDB` 时返回 rejected Promise,由 `persist` 报告 `StorageReadFailed` / `StorageWriteFailed`。
|
|
130
|
+
|
|
131
|
+
## 自动导入
|
|
132
|
+
|
|
133
|
+
`createAutoImportApis(prefix?)` 通过 `@slux/shared` 的 `generateBatchAutoImports` 生成 `unplugin-auto-import` 的 `ImportsMap`,来源名为 `@slux/storage`。登记清单以 `src/auto-import-api.ts` 为准,共 7 项:
|
|
134
|
+
|
|
135
|
+
`PERSIST_ERROR_CODE`、`cookieStorage`、`indexedDBStorage`、`localStorageBackend`、`memoryStorage`、`persist`、`sessionStorageBackend`
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
import AutoImport from "unplugin-auto-import/vite";
|
|
139
|
+
import { createAutoImportApis } from "@slux/storage";
|
|
140
|
+
|
|
141
|
+
export default {
|
|
142
|
+
plugins: [AutoImport({ imports: [createAutoImportApis()] })],
|
|
143
|
+
};
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
传入字符串前缀会为登记项生成带前缀别名(如 `createAutoImportApis("u")` 把 `persist` 映射为 `uPersist`);前缀以小写字母结尾时 API 名首字母大写,否则直接拼接。`createAutoImportApis` 本身不登记。
|
|
147
|
+
|
|
148
|
+
## 类型导出
|
|
149
|
+
|
|
150
|
+
`src/index.ts` 通过 `export type * from "./types.js"` 导出:`StorageAdapter`、`MemoryStorageAdapter`、`PersistEnvelope<T>`、`PersistErrorCode`、`PersistError`、`PersistListener<T>`、`PersistMiddlewareAPI<T>`、`PersistSetFn<T>`、`PersistOptions<T>`、`PersistMiddleware<T>`、`CookieStorageOptions`、`IndexedDBStorageOptions`。
|
|
151
|
+
|
|
152
|
+
其中 `PersistListener` / `PersistMiddlewareAPI` / `PersistSetFn` 是 `@slux/store` 的 `Listener` / `MiddlewareAPI` / `SetFn` 别名;`PERSIST_ERROR_CODE` 是运行时常量,不属于类型导出。
|
|
153
|
+
|
|
154
|
+
## 不适用的场景
|
|
155
|
+
|
|
156
|
+
- 状态含函数、循环引用或 `BigInt` 等不可 JSON 序列化的值:默认 `serialize` 会抛错,需 `partialize` 剔除或自定义 `serialize` / `deserialize`。
|
|
157
|
+
- 要求「写入必须成功」:异步后端写入是 fire-and-forget,失败只经 `onError` 报告。
|
|
158
|
+
- 需要跨标签实时同步:使用 `@slux/tab-sync`;本包只与本地/远端存储交互。
|
|
159
|
+
- 需要持久化撤销/重做历史栈:本包只保存状态快照,历史栈本身不持久化。
|
|
160
|
+
|
|
161
|
+
## 版本、许可与反馈
|
|
162
|
+
|
|
163
|
+
| 项 | 值 | 来源 |
|
|
164
|
+
| -------- | --------------------------------------------------------- | ----------------------------------------- |
|
|
165
|
+
| 版本 | `0.1.0` | `package.json` |
|
|
166
|
+
| 许可 | MIT | `package.json` / [LICENSE](../../LICENSE) |
|
|
167
|
+
| 问题反馈 | [GitHub Issues](https://github.com/itmanyong/slux/issues) | `package.json` `bugs` |
|
|
168
|
+
|
|
169
|
+
> `pnpm add` 基于 `package.json` 的发布配置;是否已实际发布到 npm 及线上版本号无法从源码确认。
|
|
170
|
+
|
|
171
|
+
<!-- package-navigation:start -->
|
|
172
|
+
|
|
173
|
+
## 包导航
|
|
174
|
+
|
|
175
|
+
### 核心层
|
|
176
|
+
|
|
177
|
+
响应式运行时与零依赖工具,其余各层都建立在 core 之上。
|
|
178
|
+
|
|
179
|
+
| 包名 | 版本 | 在线文档 | 功能 |
|
|
180
|
+
| ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | ---------------------- |
|
|
181
|
+
| [`@slux/core`](https://github.com/itmanyong/slux/tree/main/packages/core) | [](https://www.npmjs.com/package/@slux/core) [](https://npmx.dev/package/@slux/core) | [在线文档](https://itmanyong.github.io/slux/packages/core) | 框架无关的响应式运行时 |
|
|
182
|
+
| [`@slux/shared`](https://github.com/itmanyong/slux/tree/main/packages/shared) | [](https://www.npmjs.com/package/@slux/shared) [](https://npmx.dev/package/@slux/shared) | [在线文档](https://itmanyong.github.io/slux/packages/shared) | 零依赖的共享工具 |
|
|
183
|
+
|
|
184
|
+
### 范式层
|
|
185
|
+
|
|
186
|
+
六种组织状态的方式,共享 core 的运行时,可在同一个依赖图中混用。
|
|
187
|
+
|
|
188
|
+
| 包名 | 版本 | 在线文档 | 功能 |
|
|
189
|
+
| ------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | ---------------------------------- |
|
|
190
|
+
| [`@slux/store`](https://github.com/itmanyong/slux/tree/main/packages/store) | [](https://www.npmjs.com/package/@slux/store) [](https://npmx.dev/package/@slux/store) | [在线文档](https://itmanyong.github.io/slux/packages/store) | 状态与 action 集中管理,支持中间件 |
|
|
191
|
+
| [`@slux/atom`](https://github.com/itmanyong/slux/tree/main/packages/atom) | [](https://www.npmjs.com/package/@slux/atom) [](https://npmx.dev/package/@slux/atom) | [在线文档](https://itmanyong.github.io/slux/packages/atom) | 细粒度原子状态与派生 |
|
|
192
|
+
| [`@slux/proxy`](https://github.com/itmanyong/slux/tree/main/packages/proxy) | [](https://www.npmjs.com/package/@slux/proxy) [](https://npmx.dev/package/@slux/proxy) | [在线文档](https://itmanyong.github.io/slux/packages/proxy) | 可变代理写入与只读快照 |
|
|
193
|
+
| [`@slux/flux`](https://github.com/itmanyong/slux/tree/main/packages/flux) | [](https://www.npmjs.com/package/@slux/flux) [](https://npmx.dev/package/@slux/flux) | [在线文档](https://itmanyong.github.io/slux/packages/flux) | reducer + dispatch 范式 |
|
|
194
|
+
| [`@slux/state-machine`](https://github.com/itmanyong/slux/tree/main/packages/state-machine) | [](https://www.npmjs.com/package/@slux/state-machine) [](https://npmx.dev/package/@slux/state-machine) | [在线文档](https://itmanyong.github.io/slux/packages/state-machine) | 平面有限状态机 |
|
|
195
|
+
| [`@slux/rxjs`](https://github.com/itmanyong/slux/tree/main/packages/rxjs) | [](https://www.npmjs.com/package/@slux/rxjs) [](https://npmx.dev/package/@slux/rxjs) | [在线文档](https://itmanyong.github.io/slux/packages/rxjs) | Observable 与状态双向桥接 |
|
|
196
|
+
|
|
197
|
+
### 中间件层
|
|
198
|
+
|
|
199
|
+
挂载到 Store 的横切能力,五个包共用同一套契约。
|
|
200
|
+
|
|
201
|
+
| 包名 | 版本 | 在线文档 | 功能 |
|
|
202
|
+
| ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | -------------------- |
|
|
203
|
+
| [`@slux/storage`](https://github.com/itmanyong/slux/tree/main/packages/storage) | [](https://www.npmjs.com/package/@slux/storage) [](https://npmx.dev/package/@slux/storage) | [在线文档](https://itmanyong.github.io/slux/packages/storage) | 状态持久化与恢复 |
|
|
204
|
+
| [`@slux/history`](https://github.com/itmanyong/slux/tree/main/packages/history) | [](https://www.npmjs.com/package/@slux/history) [](https://npmx.dev/package/@slux/history) | [在线文档](https://itmanyong.github.io/slux/packages/history) | 撤销与重做 |
|
|
205
|
+
| [`@slux/tab-sync`](https://github.com/itmanyong/slux/tree/main/packages/tab-sync) | [](https://www.npmjs.com/package/@slux/tab-sync) [](https://npmx.dev/package/@slux/tab-sync) | [在线文档](https://itmanyong.github.io/slux/packages/tab-sync) | 跨标签页状态同步 |
|
|
206
|
+
| [`@slux/telemetry`](https://github.com/itmanyong/slux/tree/main/packages/telemetry) | [](https://www.npmjs.com/package/@slux/telemetry) [](https://npmx.dev/package/@slux/telemetry) | [在线文档](https://itmanyong.github.io/slux/packages/telemetry) | 状态变化与订阅遥测 |
|
|
207
|
+
| [`@slux/devtools`](https://github.com/itmanyong/slux/tree/main/packages/devtools) | [](https://www.npmjs.com/package/@slux/devtools) [](https://npmx.dev/package/@slux/devtools) | [在线文档](https://itmanyong.github.io/slux/packages/devtools) | 调试工具、日志与检查 |
|
|
208
|
+
|
|
209
|
+
### 框架层
|
|
210
|
+
|
|
211
|
+
十二个绑定包都提供 core 主入口与六个范式子入口,使用框架原生响应式与生命周期。范式包是**可选** peer,只装实际使用的;`@slux/core` 与框架本身是**必需** peer。
|
|
212
|
+
|
|
213
|
+
| 包名 | 版本 | 在线文档 | 适配框架 | 适配版本 | 功能 |
|
|
214
|
+
| ------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | ----------------------------------------------- | ------------------------------------------ | ---------------------- |
|
|
215
|
+
| [`@slux/react`](https://github.com/itmanyong/slux/tree/main/packages/react) | [](https://www.npmjs.com/package/@slux/react) [](https://npmx.dev/package/@slux/react) | [在线文档](https://itmanyong.github.io/slux/packages/react) | [React](https://github.com/react/react) | `^18.0.0 ‖ ^19.0.0` | React 组件状态绑定 |
|
|
216
|
+
| [`@slux/vue`](https://github.com/itmanyong/slux/tree/main/packages/vue) | [](https://www.npmjs.com/package/@slux/vue) [](https://npmx.dev/package/@slux/vue) | [在线文档](https://itmanyong.github.io/slux/packages/vue) | [Vue](https://github.com/vuejs/core) | `>= 3.2.0` | Vue 组合式 API 绑定 |
|
|
217
|
+
| [`@slux/solid`](https://github.com/itmanyong/slux/tree/main/packages/solid) | [](https://www.npmjs.com/package/@slux/solid) [](https://npmx.dev/package/@slux/solid) | [在线文档](https://itmanyong.github.io/slux/packages/solid) | [Solid](https://github.com/solidjs/solid) | `>= 1.0.0` | Solid 细粒度响应式绑定 |
|
|
218
|
+
| [`@slux/svelte`](https://github.com/itmanyong/slux/tree/main/packages/svelte) | [](https://www.npmjs.com/package/@slux/svelte) [](https://npmx.dev/package/@slux/svelte) | [在线文档](https://itmanyong.github.io/slux/packages/svelte) | [Svelte](https://github.com/sveltejs/svelte) | `>= 4.0.0` | Svelte 原生 store 绑定 |
|
|
219
|
+
| [`@slux/angular`](https://github.com/itmanyong/slux/tree/main/packages/angular) | [](https://www.npmjs.com/package/@slux/angular) [](https://npmx.dev/package/@slux/angular) | [在线文档](https://itmanyong.github.io/slux/packages/angular) | [Angular](https://github.com/angular/angular) | `@angular/core >= 16.0.0`、`rxjs >= 7.8.0` | Angular 注入上下文绑定 |
|
|
220
|
+
| [`@slux/preact`](https://github.com/itmanyong/slux/tree/main/packages/preact) | [](https://www.npmjs.com/package/@slux/preact) [](https://npmx.dev/package/@slux/preact) | [在线文档](https://itmanyong.github.io/slux/packages/preact) | [Preact](https://github.com/preactjs/preact) | `>= 10.5.0` | Preact 组件状态绑定 |
|
|
221
|
+
| [`@slux/ripple`](https://github.com/itmanyong/slux/tree/main/packages/ripple) | [](https://www.npmjs.com/package/@slux/ripple) [](https://npmx.dev/package/@slux/ripple) | [在线文档](https://itmanyong.github.io/slux/packages/ripple) | [Ripple](https://github.com/Ripple-TS/ripple) | `>= 0.6.0` | Ripple 组件状态绑定 |
|
|
222
|
+
| [`@slux/inferno`](https://github.com/itmanyong/slux/tree/main/packages/inferno) | [](https://www.npmjs.com/package/@slux/inferno) [](https://npmx.dev/package/@slux/inferno) | [在线文档](https://itmanyong.github.io/slux/packages/inferno) | [Inferno](https://github.com/infernojs/inferno) | `>= 7.0.0` | Inferno 组件状态绑定 |
|
|
223
|
+
| [`@slux/octane`](https://github.com/itmanyong/slux/tree/main/packages/octane) | [](https://www.npmjs.com/package/@slux/octane) [](https://npmx.dev/package/@slux/octane) | [在线文档](https://itmanyong.github.io/slux/packages/octane) | [Octane](https://github.com/octanejs/octane) | `>= 0.16.0` | Octane 编译器绑定 |
|
|
224
|
+
| [`@slux/vitarx`](https://github.com/itmanyong/slux/tree/main/packages/vitarx) | [](https://www.npmjs.com/package/@slux/vitarx) [](https://npmx.dev/package/@slux/vitarx) | [在线文档](https://itmanyong.github.io/slux/packages/vitarx) | [Vitarx](https://github.com/vitarx-lib/core) | `>= 4.0.0` | Vitarx 组件状态绑定 |
|
|
225
|
+
| [`@slux/actview`](https://github.com/itmanyong/slux/tree/main/packages/actview) | [](https://www.npmjs.com/package/@slux/actview) [](https://npmx.dev/package/@slux/actview) | [在线文档](https://itmanyong.github.io/slux/packages/actview) | [ActView](https://github.com/actview/actview) | `>= 1.0.0` | ActView 组件状态绑定 |
|
|
226
|
+
| [`@slux/viewfly`](https://github.com/itmanyong/slux/tree/main/packages/viewfly) | [](https://www.npmjs.com/package/@slux/viewfly) [](https://npmx.dev/package/@slux/viewfly) | [在线文档](https://itmanyong.github.io/slux/packages/viewfly) | [Viewfly](https://github.com/viewfly/viewfly) | `>= 3.0.0` | Viewfly 组件状态绑定 |
|
|
227
|
+
|
|
228
|
+
格式差异:**Octane** 的公开入口是 TypeScript 源码,需消费端 Octane 编译器处理且不提供 CJS;**Ripple** 只发布 ESM,另有 `./server` 服务端入口。其余边界见各包文档。
|
|
229
|
+
|
|
230
|
+
### 插件层
|
|
231
|
+
|
|
232
|
+
**规划中**
|
|
233
|
+
|
|
234
|
+
| 包名 | 版本 | 在线文档 | 功能 |
|
|
235
|
+
| ---- | ---- | -------- | ---- |
|
|
236
|
+
| — | — | — | — |
|
|
237
|
+
|
|
238
|
+
<!-- package-navigation:end -->
|
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,t,r)=>{var o=(t,r)=>{for(var o in t)__webpack_require__.o(t,o)&&!__webpack_require__.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,[r]:t[o]})};o(t,"get"),o(r,"value")},__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__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__,{PERSIST_ERROR_CODE:()=>PERSIST_ERROR_CODE,cookieStorage:()=>cookieStorage,createAutoImportApis:()=>createAutoImportApis,indexedDBStorage:()=>indexedDBStorage,localStorageBackend:()=>localStorageBackend,memoryStorage:()=>memoryStorage,persist:()=>persist,sessionStorageBackend:()=>sessionStorageBackend});const PERSIST_ERROR_CODE={StorageReadFailed:"StorageReadFailed",StorageWriteFailed:"StorageWriteFailed",SerializationFailed:"SerializationFailed",DeserializationFailed:"DeserializationFailed",MigrationFailed:"MigrationFailed"};function memoryStorage(){let e=new Map;return{getItem:t=>e.get(t)??null,setItem(t,r){e.set(t,r)},removeItem(t){e.delete(t)},clear(){e.clear()}}}function readEnvelope(e){if("object"!=typeof e||null===e||!("state"in e))throw TypeError("持久化数据缺少 state");let t="version"in e?e.version:0;if("number"!=typeof t||!Number.isFinite(t))throw TypeError("持久化 version 必须是有限数字");return{state:e.state,version:t}}function persist(e){let t,r,o,a,{key:i,storage:n=memoryStorage(),version:s=0,partialize:c,migrate:_,onError:l,serialize:d=JSON.stringify,deserialize:p=JSON.parse,merge:u=(e,t)=>({...t,...e}),skipHydration:m=!1}=e,S=!1,g=!1,R=0,f=new Set;function v(e,t){if(!S)try{l?.({code:e,message:`持久化 "${i}" 失败:${e}`,cause:t})}catch{}}function I(e){if(void 0!==t&&!S&&f.has(e))try{e(t.getState())}catch{}}function y(){if(S)return;g=!0;let e=o;for(let t of(o=void 0,r=void 0,e?.(),Array.from(f)))I(t)}function E(e){let t=()=>{if(!S)try{let t=e();if(void 0!==t)return Promise.resolve(t).catch(e=>v(PERSIST_ERROR_CODE.StorageWriteFailed,e))}catch(e){v(PERSIST_ERROR_CODE.StorageWriteFailed,e)}},r=void 0===a?t():a.then(t);if(void 0!==r){let e=Promise.resolve(r);return a=e,e.then(()=>{a===e&&(a=void 0)}),e}}function k(e){if(void 0!==t&&!S){try{t.setState(u(e,t.getState()))}catch(e){v(PERSIST_ERROR_CODE.DeserializationFailed,e)}y()}}function O(e){let t;if(!S){if(null===e||""===e)return void y();try{t=readEnvelope(p(e))}catch(e){v(PERSIST_ERROR_CODE.DeserializationFailed,e),y();return}if(t.version===s)return void k(t.state);if(void 0===_)return void y();try{let e=_(t.state,t.version);null!==e&&"object"==typeof e&&"then"in e&&"function"==typeof e.then?Promise.resolve(e).then(k,e=>{v(PERSIST_ERROR_CODE.MigrationFailed,e),y()}):k(e)}catch(e){v(PERSIST_ERROR_CODE.MigrationFailed,e),y()}}}function h(){if(S||void 0===t)return Promise.resolve();if(void 0!==r)return r;g=!1,R++;let e=new Promise(e=>{o=e});r=e;try{let e=n.getItem(i);"string"==typeof e||null===e?O(e):Promise.resolve(e).then(O,e=>{v(PERSIST_ERROR_CODE.StorageReadFailed,e),y()})}catch(e){v(PERSIST_ERROR_CODE.StorageReadFailed,e),y()}return e}return{name:"persist",init(e){t=e,m||h()},onSet(e,r,o){r(o),function(){let e;if(void 0!==t&&!S){try{let r=t.getState();e=d({state:void 0===c?r:c(r),version:s})}catch(e){v(PERSIST_ERROR_CODE.SerializationFailed,e);return}E(()=>n.setItem(i,e))}}()},onDestroy(){S=!0,f.clear(),t=void 0,o?.(),o=void 0,r=void 0},rehydrate:h,hasHydrated:()=>g,onHydrate(e){if(S)return()=>{};if(f.add(e),g){let t=R;queueMicrotask(()=>{t===R&&I(e)})}return()=>{f.delete(e)}},clearStorage:()=>E(()=>n.removeItem(i))??Promise.resolve()}}function localStorageBackend(){return{getItem(e){try{return localStorage.getItem(e)}catch{return null}},setItem(e,t){try{localStorage.setItem(e,t)}catch{}},removeItem(e){try{localStorage.removeItem(e)}catch{}}}}function sessionStorageBackend(){return{getItem(e){try{return sessionStorage.getItem(e)}catch{return null}},setItem(e,t){try{sessionStorage.setItem(e,t)}catch{}},removeItem(e){try{sessionStorage.removeItem(e)}catch{}}}}function cookieStorage(e){let t=e?.maxAge,r=e?.path??"/",o=e?.sameSite,a=e?.secure,i=e?.domain;return{getItem(e){try{let t=document.cookie.split(";"),r=encodeURIComponent(e);for(let e of t){let t=e.trim();if(t.startsWith(r+"="))return decodeURIComponent(t.slice(r.length+1))}return null}catch{return null}},setItem(e,n){try{let s=`${encodeURIComponent(e)}=${encodeURIComponent(n)}`;s+=`; path=${r}`,void 0!==t&&(s+=`; max-age=${String(t)}`),void 0!==o&&(s+=`; samesite=${o}`),!0===a&&(s+="; secure"),void 0!==i&&(s+=`; domain=${i}`),document.cookie=s}catch{}},removeItem(e){try{document.cookie=`${encodeURIComponent(e)}=; max-age=0; path=${r}${void 0===i?"":`; domain=${i}`}${!0===a?"; secure":""}${void 0===o?"":`; samesite=${o}`}`}catch{}}}}function indexedDBStorage(e){let t,{dbName:r="slux-storage",storeName:o="keyval",dbVersion:a=1}=e??{};async function i(e,i){let n=await (void 0!==t?t:t=(t=new Promise((e,i)=>{let n=indexedDB.open(r,a);n.onupgradeneeded=()=>{n.result.objectStoreNames.contains(o)||n.result.createObjectStore(o)},n.onerror=()=>i(n.error??Error("IndexedDB 打开失败")),n.onsuccess=()=>{let r=n.result;r.onversionchange=()=>{r.close(),t=void 0},e(r)}})).catch(e=>{throw t=void 0,e}));return new Promise((t,r)=>{let a=n.transaction(o,e),s=i(a.objectStore(o));a.oncomplete=()=>t(s.result),a.onabort=()=>r(a.error??s.error??Error("IndexedDB 事务已中止")),a.onerror=()=>r(a.error??s.error??Error("IndexedDB 事务失败"))})}return{async getItem(e){let t=await i("readonly",t=>t.get(e));return"string"==typeof t?t:null},async setItem(e,t){await i("readwrite",r=>r.put(t,e))},async removeItem(e){await i("readwrite",t=>t.delete(e))}}}const shared_namespaceObject=require("@slux/shared"),allImportApis=["PERSIST_ERROR_CODE","cookieStorage","indexedDBStorage","localStorageBackend","memoryStorage","persist","sessionStorageBackend"],createAutoImportApis=(e="")=>(0,shared_namespaceObject.generateBatchAutoImports)([{prefix:e,fromName:"@slux/storage",imports:allImportApis}]);for(var __rspack_i in exports.PERSIST_ERROR_CODE=__webpack_exports__.PERSIST_ERROR_CODE,exports.cookieStorage=__webpack_exports__.cookieStorage,exports.createAutoImportApis=__webpack_exports__.createAutoImportApis,exports.indexedDBStorage=__webpack_exports__.indexedDBStorage,exports.localStorageBackend=__webpack_exports__.localStorageBackend,exports.memoryStorage=__webpack_exports__.memoryStorage,exports.persist=__webpack_exports__.persist,exports.sessionStorageBackend=__webpack_exports__.sessionStorageBackend,__webpack_exports__)-1===["PERSIST_ERROR_CODE","cookieStorage","createAutoImportApis","indexedDBStorage","localStorageBackend","memoryStorage","persist","sessionStorageBackend"].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/errors.ts","../src/memory-storage.ts","../src/persist.ts","../src/web-storage.ts","../src/cookie-storage.ts","../src/indexed-db-storage.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};","export const PERSIST_ERROR_CODE = {\n StorageReadFailed: \"StorageReadFailed\",\n StorageWriteFailed: \"StorageWriteFailed\",\n SerializationFailed: \"SerializationFailed\",\n DeserializationFailed: \"DeserializationFailed\",\n MigrationFailed: \"MigrationFailed\",\n} as const;\n","import type { MemoryStorageAdapter } from \"./types.js\";\nexport function memoryStorage(): MemoryStorageAdapter {\n const store = new Map<string, string>();\n\n return {\n getItem(key: string): string | null {\n return store.get(key) ?? null;\n },\n setItem(key: string, value: string): void {\n store.set(key, value);\n },\n removeItem(key: string): void {\n store.delete(key);\n },\n clear(): void {\n store.clear();\n },\n };\n}\n","import { PERSIST_ERROR_CODE } from \"./errors.js\";\nimport { memoryStorage } from \"./memory-storage.js\";\nimport type { PersistEnvelope, PersistErrorCode, PersistMiddleware, PersistMiddlewareAPI, PersistOptions } from \"./types.js\";\n\n/** 存储入口只校验 envelope;业务字段由调用方的 deserialize 或 migrate 校验。 */\nfunction readEnvelope<T>(value: unknown): PersistEnvelope<Partial<T>> {\n if (typeof value !== \"object\" || value === null || !(\"state\" in value)) {\n throw new TypeError(\"持久化数据缺少 state\");\n }\n const version = \"version\" in value ? value.version : 0;\n if (typeof version !== \"number\" || !Number.isFinite(version)) {\n throw new TypeError(\"持久化 version 必须是有限数字\");\n }\n return { state: value.state as Partial<T>, version };\n}\n\nexport function persist<T>(options: PersistOptions<T>): PersistMiddleware<T> {\n const {\n key,\n storage = memoryStorage(),\n version = 0,\n partialize,\n migrate,\n onError,\n serialize = JSON.stringify,\n deserialize = JSON.parse,\n merge = (persisted, current) => ({ ...current, ...persisted }),\n skipHydration = false,\n } = options;\n let api: PersistMiddlewareAPI<T> | undefined;\n let destroyed = false;\n let hydrated = false;\n let hydrationGeneration = 0;\n let hydration: Promise<void> | undefined;\n let finishPending: (() => void) | undefined;\n let writeTail: Promise<void> | undefined;\n const callbacks = new Set<(state: T) => void>();\n\n function report(code: PersistErrorCode, cause: unknown): void {\n if (destroyed) return;\n try {\n onError?.({ code, message: `持久化 \"${key}\" 失败:${code}`, cause });\n } catch {\n /* 错误观察器不能中断状态更新或制造未处理的 Promise。 */\n }\n }\n\n function notify(callback: (state: T) => void): void {\n if (api === undefined || destroyed || !callbacks.has(callback)) return;\n try {\n callback(api.getState());\n } catch {\n /* 单个观察器失败不能阻止其余观察器或 rehydrate 完成。 */\n }\n }\n\n function finishHydration(): void {\n if (destroyed) return;\n hydrated = true;\n const resolve = finishPending;\n finishPending = undefined;\n hydration = undefined;\n resolve?.();\n for (const callback of Array.from(callbacks)) notify(callback);\n }\n\n /** 同步后端保持同步写入;异步写入和删除共享队列,避免旧写入覆盖新值。 */\n function enqueue(operation: () => void | Promise<void>): Promise<void> | undefined {\n const run = (): void | Promise<void> => {\n if (destroyed) return;\n try {\n const result = operation();\n if (result !== undefined) return Promise.resolve(result).catch((error: unknown) => report(PERSIST_ERROR_CODE.StorageWriteFailed, error));\n } catch (error) {\n report(PERSIST_ERROR_CODE.StorageWriteFailed, error);\n }\n };\n const result = writeTail === undefined ? run() : writeTail.then(run);\n if (result !== undefined) {\n const tail = Promise.resolve(result);\n writeTail = tail;\n void tail.then(() => {\n if (writeTail === tail) writeTail = undefined;\n });\n return tail;\n }\n return undefined;\n }\n\n function persistState(): void {\n if (api === undefined || destroyed) return;\n let value: string;\n try {\n const state = api.getState();\n value = serialize({ state: partialize === undefined ? state : partialize(state), version });\n } catch (error) {\n report(PERSIST_ERROR_CODE.SerializationFailed, error);\n return;\n }\n enqueue(() => storage.setItem(key, value));\n }\n\n function applyState(state: Partial<T>): void {\n if (api === undefined || destroyed) return;\n try {\n api.setState(merge(state, api.getState()));\n } catch (error) {\n report(PERSIST_ERROR_CODE.DeserializationFailed, error);\n }\n finishHydration();\n }\n\n function handleValue(raw: string | null): void {\n if (destroyed) return;\n if (raw === null || raw === \"\") {\n finishHydration();\n return;\n }\n let envelope: PersistEnvelope<Partial<T>>;\n try {\n envelope = readEnvelope<T>(deserialize(raw));\n } catch (error) {\n report(PERSIST_ERROR_CODE.DeserializationFailed, error);\n finishHydration();\n return;\n }\n if (envelope.version === version) {\n applyState(envelope.state);\n return;\n }\n if (migrate === undefined) {\n finishHydration();\n return;\n }\n try {\n const result = migrate(envelope.state, envelope.version);\n if (result !== null && typeof result === \"object\" && \"then\" in result && typeof result.then === \"function\") {\n void Promise.resolve(result).then(applyState, (error: unknown) => {\n report(PERSIST_ERROR_CODE.MigrationFailed, error);\n finishHydration();\n });\n } else {\n applyState(result as Partial<T>);\n }\n } catch (error) {\n report(PERSIST_ERROR_CODE.MigrationFailed, error);\n finishHydration();\n }\n }\n\n function rehydrate(): Promise<void> {\n if (destroyed || api === undefined) return Promise.resolve();\n if (hydration !== undefined) return hydration;\n hydrated = false;\n hydrationGeneration++;\n const pending = new Promise<void>((resolve) => {\n finishPending = resolve;\n });\n hydration = pending;\n try {\n const result = storage.getItem(key);\n if (typeof result === \"string\" || result === null) handleValue(result);\n else\n void Promise.resolve(result).then(handleValue, (error: unknown) => {\n report(PERSIST_ERROR_CODE.StorageReadFailed, error);\n finishHydration();\n });\n } catch (error) {\n report(PERSIST_ERROR_CODE.StorageReadFailed, error);\n finishHydration();\n }\n return pending;\n }\n\n return {\n name: \"persist\",\n init(middlewareApi) {\n api = middlewareApi;\n if (!skipHydration) void rehydrate();\n },\n onSet(_api, next, partial) {\n next(partial);\n persistState();\n },\n onDestroy() {\n destroyed = true;\n callbacks.clear();\n api = undefined;\n finishPending?.();\n finishPending = undefined;\n hydration = undefined;\n },\n rehydrate,\n hasHydrated: () => hydrated,\n onHydrate(callback) {\n if (destroyed) return () => {};\n callbacks.add(callback);\n if (hydrated) {\n const generation = hydrationGeneration;\n queueMicrotask(() => {\n if (generation === hydrationGeneration) notify(callback);\n });\n }\n return () => {\n callbacks.delete(callback);\n };\n },\n clearStorage: () => enqueue(() => storage.removeItem(key)) ?? Promise.resolve(),\n };\n}\n","import type { StorageAdapter } from \"./types.js\";\nexport function localStorageBackend(): StorageAdapter {\n return {\n getItem(key: string): string | null {\n try {\n return localStorage.getItem(key);\n } catch {\n return null;\n }\n },\n setItem(key: string, value: string): void {\n try {\n localStorage.setItem(key, value);\n } catch {\n /* 后端不可用时忽略操作。 */\n }\n },\n removeItem(key: string): void {\n try {\n localStorage.removeItem(key);\n } catch {\n /* 后端不可用时忽略操作。 */\n }\n },\n };\n}\n\nexport function sessionStorageBackend(): StorageAdapter {\n return {\n getItem(key: string): string | null {\n try {\n return sessionStorage.getItem(key);\n } catch {\n return null;\n }\n },\n setItem(key: string, value: string): void {\n try {\n sessionStorage.setItem(key, value);\n } catch {\n /* 后端不可用时忽略操作。 */\n }\n },\n removeItem(key: string): void {\n try {\n sessionStorage.removeItem(key);\n } catch {\n /* 后端不可用时忽略操作。 */\n }\n },\n };\n}\n","import type { StorageAdapter, CookieStorageOptions } from \"./types.js\";\nexport function cookieStorage(options?: CookieStorageOptions): StorageAdapter {\n const maxAge = options?.maxAge;\n const path = options?.path ?? \"/\";\n const sameSite = options?.sameSite;\n const secure = options?.secure;\n const domain = options?.domain;\n\n return {\n getItem(key: string): string | null {\n try {\n const cookies = document.cookie.split(\";\");\n const encodedKey = encodeURIComponent(key);\n for (const cookie of cookies) {\n const trimmed = cookie.trim();\n if (trimmed.startsWith(encodedKey + \"=\")) {\n return decodeURIComponent(trimmed.slice(encodedKey.length + 1));\n }\n }\n return null;\n } catch {\n return null;\n }\n },\n setItem(key: string, value: string): void {\n try {\n let cookie = `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n cookie += `; path=${path}`;\n if (maxAge !== undefined) cookie += `; max-age=${String(maxAge)}`;\n if (sameSite !== undefined) cookie += `; samesite=${sameSite}`;\n if (secure === true) cookie += \"; secure\";\n if (domain !== undefined) cookie += `; domain=${domain}`;\n document.cookie = cookie;\n } catch {\n /* 后端不可用时忽略操作。 */\n }\n },\n removeItem(key: string): void {\n try {\n document.cookie = `${encodeURIComponent(key)}=; max-age=0; path=${path}${domain === undefined ? \"\" : `; domain=${domain}`}${secure === true ? \"; secure\" : \"\"}${sameSite === undefined ? \"\" : `; samesite=${sameSite}`}`;\n } catch {\n /* 后端不可用时忽略操作。 */\n }\n },\n };\n}\n","import type { IndexedDBStorageOptions, StorageAdapter } from \"./types.js\";\n\nexport function indexedDBStorage(options?: IndexedDBStorageOptions): StorageAdapter {\n const { dbName = \"slux-storage\", storeName = \"keyval\", dbVersion = 1 } = options ?? {};\n let connection: Promise<IDBDatabase> | undefined;\n\n function open(): Promise<IDBDatabase> {\n if (connection !== undefined) return connection;\n connection = new Promise<IDBDatabase>((resolve, reject) => {\n const request = indexedDB.open(dbName, dbVersion);\n request.onupgradeneeded = () => {\n if (!request.result.objectStoreNames.contains(storeName)) request.result.createObjectStore(storeName);\n };\n request.onerror = () => reject(request.error ?? new Error(\"IndexedDB 打开失败\"));\n request.onsuccess = () => {\n const db = request.result;\n db.onversionchange = () => {\n db.close();\n connection = undefined;\n };\n resolve(db);\n };\n });\n connection = connection.catch((error: unknown) => {\n connection = undefined;\n throw error;\n });\n return connection;\n }\n\n async function transact(mode: IDBTransactionMode, action: (store: IDBObjectStore) => IDBRequest): Promise<unknown> {\n const db = await open();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(storeName, mode);\n const request = action(tx.objectStore(storeName));\n // 请求成功后事务还可能回滚,只在 commit 后确认写入成功。\n tx.oncomplete = () => resolve(request.result as unknown);\n tx.onabort = () => reject(tx.error ?? request.error ?? new Error(\"IndexedDB 事务已中止\"));\n tx.onerror = () => reject(tx.error ?? request.error ?? new Error(\"IndexedDB 事务失败\"));\n });\n }\n\n return {\n async getItem(key) {\n const result = await transact(\"readonly\", (store) => store.get(key));\n return typeof result === \"string\" ? result : null;\n },\n async setItem(key, value) {\n await transact(\"readwrite\", (store) => store.put(value, key));\n },\n async removeItem(key) {\n await transact(\"readwrite\", (store) => store.delete(key));\n },\n };\n}\n","import { generateBatchAutoImports } from \"@slux/shared\";\n\nconst allImportApis: string[] = [\n \"PERSIST_ERROR_CODE\",\n \"cookieStorage\",\n \"indexedDBStorage\",\n \"localStorageBackend\",\n \"memoryStorage\",\n \"persist\",\n \"sessionStorageBackend\",\n];\n\nexport const createAutoImportApis = (prefix: string = \"\") => {\n return generateBatchAutoImports([\n {\n prefix,\n fromName: \"@slux/storage\",\n imports: allImportApis,\n },\n ]);\n};\n"],"names":["__webpack_require__","e","Object","Symbol","PERSIST_ERROR_CODE","memoryStorage","store","Map","key","value","readEnvelope","TypeError","version","Number","persist","options","api","hydration","finishPending","writeTail","storage","partialize","migrate","onError","serialize","JSON","deserialize","merge","persisted","current","skipHydration","destroyed","hydrated","hydrationGeneration","callbacks","Set","report","code","cause","notify","callback","undefined","finishHydration","resolve","Array","enqueue","operation","run","result","Promise","error","tail","applyState","state","handleValue","raw","envelope","rehydrate","pending","middlewareApi","_api","next","partial","persistState","generation","queueMicrotask","localStorageBackend","localStorage","sessionStorageBackend","sessionStorage","cookieStorage","maxAge","path","sameSite","secure","domain","cookies","document","encodedKey","encodeURIComponent","cookie","trimmed","decodeURIComponent","String","indexedDBStorage","connection","dbName","storeName","dbVersion","transact","mode","action","db","reject","request","indexedDB","Error","tx","allImportApis","createAutoImportApis","prefix","generateBatchAutoImports"],"mappings":"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"}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { Listener } from '@slux/store';
|
|
2
|
+
import type { MiddlewareAPI } from '@slux/store';
|
|
3
|
+
import type { SetFn } from '@slux/store';
|
|
4
|
+
|
|
5
|
+
export declare function cookieStorage(options?: CookieStorageOptions): StorageAdapter;
|
|
6
|
+
|
|
7
|
+
export declare type CookieStorageOptions = {
|
|
8
|
+
readonly maxAge?: number;
|
|
9
|
+
readonly path?: string;
|
|
10
|
+
readonly sameSite?: "strict" | "lax" | "none";
|
|
11
|
+
readonly secure?: boolean;
|
|
12
|
+
readonly domain?: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export declare const createAutoImportApis: (prefix?: string) => {
|
|
16
|
+
[x: string]: (string | [string, string])[];
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export declare function indexedDBStorage(options?: IndexedDBStorageOptions): StorageAdapter;
|
|
20
|
+
|
|
21
|
+
export declare type IndexedDBStorageOptions = {
|
|
22
|
+
readonly dbName?: string;
|
|
23
|
+
readonly storeName?: string;
|
|
24
|
+
readonly dbVersion?: number;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export declare function localStorageBackend(): StorageAdapter;
|
|
28
|
+
|
|
29
|
+
export declare function memoryStorage(): MemoryStorageAdapter;
|
|
30
|
+
|
|
31
|
+
export declare type MemoryStorageAdapter = {
|
|
32
|
+
clear(): void;
|
|
33
|
+
} & StorageAdapter;
|
|
34
|
+
|
|
35
|
+
export declare function persist<T>(options: PersistOptions<T>): PersistMiddleware<T>;
|
|
36
|
+
|
|
37
|
+
export declare const PERSIST_ERROR_CODE: {
|
|
38
|
+
readonly StorageReadFailed: "StorageReadFailed";
|
|
39
|
+
readonly StorageWriteFailed: "StorageWriteFailed";
|
|
40
|
+
readonly SerializationFailed: "SerializationFailed";
|
|
41
|
+
readonly DeserializationFailed: "DeserializationFailed";
|
|
42
|
+
readonly MigrationFailed: "MigrationFailed";
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export declare type PersistEnvelope<T> = {
|
|
46
|
+
readonly state: T;
|
|
47
|
+
readonly version: number;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export declare type PersistError = {
|
|
51
|
+
readonly code: PersistErrorCode;
|
|
52
|
+
readonly message: string;
|
|
53
|
+
readonly cause?: unknown;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export declare type PersistErrorCode = (typeof PERSIST_ERROR_CODE)[keyof typeof PERSIST_ERROR_CODE];
|
|
57
|
+
|
|
58
|
+
export declare type PersistListener<T> = Listener<T>;
|
|
59
|
+
|
|
60
|
+
export declare type PersistMiddleware<T> = {
|
|
61
|
+
readonly name: string;
|
|
62
|
+
readonly init?: (api: PersistMiddlewareAPI<T>) => void;
|
|
63
|
+
readonly onSet?: (api: PersistMiddlewareAPI<T>, next: PersistSetFn<T>, partial: Partial<T>) => void;
|
|
64
|
+
readonly onDestroy?: (api: PersistMiddlewareAPI<T>) => void;
|
|
65
|
+
rehydrate(): Promise<void>;
|
|
66
|
+
hasHydrated(): boolean;
|
|
67
|
+
onHydrate(callback: (state: T) => void): () => void;
|
|
68
|
+
clearStorage(): Promise<void>;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export declare type PersistMiddlewareAPI<T> = MiddlewareAPI<T>;
|
|
72
|
+
|
|
73
|
+
export declare type PersistOptions<T> = {
|
|
74
|
+
readonly key: string;
|
|
75
|
+
readonly storage?: StorageAdapter;
|
|
76
|
+
readonly partialize?: (state: T) => Partial<T>;
|
|
77
|
+
readonly merge?: (persisted: Partial<T>, current: T) => T;
|
|
78
|
+
readonly version?: number;
|
|
79
|
+
readonly migrate?: (persisted: Partial<T>, version: number) => Partial<T> | Promise<Partial<T>>;
|
|
80
|
+
readonly serialize?: (value: PersistEnvelope<Partial<T>>) => string;
|
|
81
|
+
readonly deserialize?: (value: string) => PersistEnvelope<Partial<T>>;
|
|
82
|
+
readonly onError?: (error: PersistError) => void;
|
|
83
|
+
readonly skipHydration?: boolean;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export declare type PersistSetFn<T> = SetFn<T>;
|
|
87
|
+
|
|
88
|
+
export declare function sessionStorageBackend(): StorageAdapter;
|
|
89
|
+
|
|
90
|
+
export declare type StorageAdapter = {
|
|
91
|
+
getItem(key: string): string | null | Promise<string | null>;
|
|
92
|
+
setItem(key: string, value: string): void | Promise<void>;
|
|
93
|
+
removeItem(key: string): void | Promise<void>;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export { }
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { Listener } from '@slux/store';
|
|
2
|
+
import type { MiddlewareAPI } from '@slux/store';
|
|
3
|
+
import type { SetFn } from '@slux/store';
|
|
4
|
+
|
|
5
|
+
export declare function cookieStorage(options?: CookieStorageOptions): StorageAdapter;
|
|
6
|
+
|
|
7
|
+
export declare type CookieStorageOptions = {
|
|
8
|
+
readonly maxAge?: number;
|
|
9
|
+
readonly path?: string;
|
|
10
|
+
readonly sameSite?: "strict" | "lax" | "none";
|
|
11
|
+
readonly secure?: boolean;
|
|
12
|
+
readonly domain?: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export declare const createAutoImportApis: (prefix?: string) => {
|
|
16
|
+
[x: string]: (string | [string, string])[];
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export declare function indexedDBStorage(options?: IndexedDBStorageOptions): StorageAdapter;
|
|
20
|
+
|
|
21
|
+
export declare type IndexedDBStorageOptions = {
|
|
22
|
+
readonly dbName?: string;
|
|
23
|
+
readonly storeName?: string;
|
|
24
|
+
readonly dbVersion?: number;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export declare function localStorageBackend(): StorageAdapter;
|
|
28
|
+
|
|
29
|
+
export declare function memoryStorage(): MemoryStorageAdapter;
|
|
30
|
+
|
|
31
|
+
export declare type MemoryStorageAdapter = {
|
|
32
|
+
clear(): void;
|
|
33
|
+
} & StorageAdapter;
|
|
34
|
+
|
|
35
|
+
export declare function persist<T>(options: PersistOptions<T>): PersistMiddleware<T>;
|
|
36
|
+
|
|
37
|
+
export declare const PERSIST_ERROR_CODE: {
|
|
38
|
+
readonly StorageReadFailed: "StorageReadFailed";
|
|
39
|
+
readonly StorageWriteFailed: "StorageWriteFailed";
|
|
40
|
+
readonly SerializationFailed: "SerializationFailed";
|
|
41
|
+
readonly DeserializationFailed: "DeserializationFailed";
|
|
42
|
+
readonly MigrationFailed: "MigrationFailed";
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export declare type PersistEnvelope<T> = {
|
|
46
|
+
readonly state: T;
|
|
47
|
+
readonly version: number;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export declare type PersistError = {
|
|
51
|
+
readonly code: PersistErrorCode;
|
|
52
|
+
readonly message: string;
|
|
53
|
+
readonly cause?: unknown;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export declare type PersistErrorCode = (typeof PERSIST_ERROR_CODE)[keyof typeof PERSIST_ERROR_CODE];
|
|
57
|
+
|
|
58
|
+
export declare type PersistListener<T> = Listener<T>;
|
|
59
|
+
|
|
60
|
+
export declare type PersistMiddleware<T> = {
|
|
61
|
+
readonly name: string;
|
|
62
|
+
readonly init?: (api: PersistMiddlewareAPI<T>) => void;
|
|
63
|
+
readonly onSet?: (api: PersistMiddlewareAPI<T>, next: PersistSetFn<T>, partial: Partial<T>) => void;
|
|
64
|
+
readonly onDestroy?: (api: PersistMiddlewareAPI<T>) => void;
|
|
65
|
+
rehydrate(): Promise<void>;
|
|
66
|
+
hasHydrated(): boolean;
|
|
67
|
+
onHydrate(callback: (state: T) => void): () => void;
|
|
68
|
+
clearStorage(): Promise<void>;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export declare type PersistMiddlewareAPI<T> = MiddlewareAPI<T>;
|
|
72
|
+
|
|
73
|
+
export declare type PersistOptions<T> = {
|
|
74
|
+
readonly key: string;
|
|
75
|
+
readonly storage?: StorageAdapter;
|
|
76
|
+
readonly partialize?: (state: T) => Partial<T>;
|
|
77
|
+
readonly merge?: (persisted: Partial<T>, current: T) => T;
|
|
78
|
+
readonly version?: number;
|
|
79
|
+
readonly migrate?: (persisted: Partial<T>, version: number) => Partial<T> | Promise<Partial<T>>;
|
|
80
|
+
readonly serialize?: (value: PersistEnvelope<Partial<T>>) => string;
|
|
81
|
+
readonly deserialize?: (value: string) => PersistEnvelope<Partial<T>>;
|
|
82
|
+
readonly onError?: (error: PersistError) => void;
|
|
83
|
+
readonly skipHydration?: boolean;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export declare type PersistSetFn<T> = SetFn<T>;
|
|
87
|
+
|
|
88
|
+
export declare function sessionStorageBackend(): StorageAdapter;
|
|
89
|
+
|
|
90
|
+
export declare type StorageAdapter = {
|
|
91
|
+
getItem(key: string): string | null | Promise<string | null>;
|
|
92
|
+
setItem(key: string, value: string): void | Promise<void>;
|
|
93
|
+
removeItem(key: string): void | Promise<void>;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export { }
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{generateBatchAutoImports as e}from"@slux/shared";let t={StorageReadFailed:"StorageReadFailed",StorageWriteFailed:"StorageWriteFailed",SerializationFailed:"SerializationFailed",DeserializationFailed:"DeserializationFailed",MigrationFailed:"MigrationFailed"};function r(){let e=new Map;return{getItem:t=>e.get(t)??null,setItem(t,r){e.set(t,r)},removeItem(t){e.delete(t)},clear(){e.clear()}}}function o(e){let o,i,n,a,{key:l,storage:s=r(),version:c=0,partialize:d,migrate:u,onError:m,serialize:g=JSON.stringify,deserialize:f=JSON.parse,merge:v=(e,t)=>({...t,...e}),skipHydration:S=!1}=e,y=!1,h=!1,I=0,p=new Set;function F(e,t){if(!y)try{m?.({code:e,message:`持久化 "${l}" 失败:${e}`,cause:t})}catch{}}function R(e){if(void 0!==o&&!y&&p.has(e))try{e(o.getState())}catch{}}function $(){if(y)return;h=!0;let e=n;for(let t of(n=void 0,i=void 0,e?.(),Array.from(p)))R(t)}function w(e){let r=()=>{if(!y)try{let r=e();if(void 0!==r)return Promise.resolve(r).catch(e=>F(t.StorageWriteFailed,e))}catch(e){F(t.StorageWriteFailed,e)}},o=void 0===a?r():a.then(r);if(void 0!==o){let e=Promise.resolve(o);return a=e,e.then(()=>{a===e&&(a=void 0)}),e}}function x(e){if(void 0!==o&&!y){try{o.setState(v(e,o.getState()))}catch(e){F(t.DeserializationFailed,e)}$()}}function D(e){let r;if(!y){if(null===e||""===e)return void $();try{r=function(e){if("object"!=typeof e||null===e||!("state"in e))throw TypeError("持久化数据缺少 state");let t="version"in e?e.version:0;if("number"!=typeof t||!Number.isFinite(t))throw TypeError("持久化 version 必须是有限数字");return{state:e.state,version:t}}(f(e))}catch(e){F(t.DeserializationFailed,e),$();return}if(r.version===c)return void x(r.state);if(void 0===u)return void $();try{let e=u(r.state,r.version);null!==e&&"object"==typeof e&&"then"in e&&"function"==typeof e.then?Promise.resolve(e).then(x,e=>{F(t.MigrationFailed,e),$()}):x(e)}catch(e){F(t.MigrationFailed,e),$()}}}function k(){if(y||void 0===o)return Promise.resolve();if(void 0!==i)return i;h=!1,I++;let e=new Promise(e=>{n=e});i=e;try{let e=s.getItem(l);"string"==typeof e||null===e?D(e):Promise.resolve(e).then(D,e=>{F(t.StorageReadFailed,e),$()})}catch(e){F(t.StorageReadFailed,e),$()}return e}return{name:"persist",init(e){o=e,S||k()},onSet(e,r,i){r(i),function(){let e;if(void 0!==o&&!y){try{let t=o.getState();e=g({state:void 0===d?t:d(t),version:c})}catch(e){F(t.SerializationFailed,e);return}w(()=>s.setItem(l,e))}}()},onDestroy(){y=!0,p.clear(),o=void 0,n?.(),n=void 0,i=void 0},rehydrate:k,hasHydrated:()=>h,onHydrate(e){if(y)return()=>{};if(p.add(e),h){let t=I;queueMicrotask(()=>{t===I&&R(e)})}return()=>{p.delete(e)}},clearStorage:()=>w(()=>s.removeItem(l))??Promise.resolve()}}function i(){return{getItem(e){try{return localStorage.getItem(e)}catch{return null}},setItem(e,t){try{localStorage.setItem(e,t)}catch{}},removeItem(e){try{localStorage.removeItem(e)}catch{}}}}function n(){return{getItem(e){try{return sessionStorage.getItem(e)}catch{return null}},setItem(e,t){try{sessionStorage.setItem(e,t)}catch{}},removeItem(e){try{sessionStorage.removeItem(e)}catch{}}}}function a(e){let t=e?.maxAge,r=e?.path??"/",o=e?.sameSite,i=e?.secure,n=e?.domain;return{getItem(e){try{let t=document.cookie.split(";"),r=encodeURIComponent(e);for(let e of t){let t=e.trim();if(t.startsWith(r+"="))return decodeURIComponent(t.slice(r.length+1))}return null}catch{return null}},setItem(e,a){try{let l=`${encodeURIComponent(e)}=${encodeURIComponent(a)}`;l+=`; path=${r}`,void 0!==t&&(l+=`; max-age=${String(t)}`),void 0!==o&&(l+=`; samesite=${o}`),!0===i&&(l+="; secure"),void 0!==n&&(l+=`; domain=${n}`),document.cookie=l}catch{}},removeItem(e){try{document.cookie=`${encodeURIComponent(e)}=; max-age=0; path=${r}${void 0===n?"":`; domain=${n}`}${!0===i?"; secure":""}${void 0===o?"":`; samesite=${o}`}`}catch{}}}}function l(e){let t,{dbName:r="slux-storage",storeName:o="keyval",dbVersion:i=1}=e??{};async function n(e,n){let a=await (void 0!==t?t:t=(t=new Promise((e,n)=>{let a=indexedDB.open(r,i);a.onupgradeneeded=()=>{a.result.objectStoreNames.contains(o)||a.result.createObjectStore(o)},a.onerror=()=>n(a.error??Error("IndexedDB 打开失败")),a.onsuccess=()=>{let r=a.result;r.onversionchange=()=>{r.close(),t=void 0},e(r)}})).catch(e=>{throw t=void 0,e}));return new Promise((t,r)=>{let i=a.transaction(o,e),l=n(i.objectStore(o));i.oncomplete=()=>t(l.result),i.onabort=()=>r(i.error??l.error??Error("IndexedDB 事务已中止")),i.onerror=()=>r(i.error??l.error??Error("IndexedDB 事务失败"))})}return{async getItem(e){let t=await n("readonly",t=>t.get(e));return"string"==typeof t?t:null},async setItem(e,t){await n("readwrite",r=>r.put(t,e))},async removeItem(e){await n("readwrite",t=>t.delete(e))}}}let s=["PERSIST_ERROR_CODE","cookieStorage","indexedDBStorage","localStorageBackend","memoryStorage","persist","sessionStorageBackend"],c=(t="")=>e([{prefix:t,fromName:"@slux/storage",imports:s}]);export{t as PERSIST_ERROR_CODE,a as cookieStorage,c as createAutoImportApis,l as indexedDBStorage,i as localStorageBackend,r as memoryStorage,o as persist,n as sessionStorageBackend};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/errors.ts","../src/memory-storage.ts","../src/persist.ts","../src/web-storage.ts","../src/cookie-storage.ts","../src/indexed-db-storage.ts","../src/auto-import-api.ts"],"sourcesContent":["export const PERSIST_ERROR_CODE = {\n StorageReadFailed: \"StorageReadFailed\",\n StorageWriteFailed: \"StorageWriteFailed\",\n SerializationFailed: \"SerializationFailed\",\n DeserializationFailed: \"DeserializationFailed\",\n MigrationFailed: \"MigrationFailed\",\n} as const;\n","import type { MemoryStorageAdapter } from \"./types.js\";\nexport function memoryStorage(): MemoryStorageAdapter {\n const store = new Map<string, string>();\n\n return {\n getItem(key: string): string | null {\n return store.get(key) ?? null;\n },\n setItem(key: string, value: string): void {\n store.set(key, value);\n },\n removeItem(key: string): void {\n store.delete(key);\n },\n clear(): void {\n store.clear();\n },\n };\n}\n","import { PERSIST_ERROR_CODE } from \"./errors.js\";\nimport { memoryStorage } from \"./memory-storage.js\";\nimport type { PersistEnvelope, PersistErrorCode, PersistMiddleware, PersistMiddlewareAPI, PersistOptions } from \"./types.js\";\n\n/** 存储入口只校验 envelope;业务字段由调用方的 deserialize 或 migrate 校验。 */\nfunction readEnvelope<T>(value: unknown): PersistEnvelope<Partial<T>> {\n if (typeof value !== \"object\" || value === null || !(\"state\" in value)) {\n throw new TypeError(\"持久化数据缺少 state\");\n }\n const version = \"version\" in value ? value.version : 0;\n if (typeof version !== \"number\" || !Number.isFinite(version)) {\n throw new TypeError(\"持久化 version 必须是有限数字\");\n }\n return { state: value.state as Partial<T>, version };\n}\n\nexport function persist<T>(options: PersistOptions<T>): PersistMiddleware<T> {\n const {\n key,\n storage = memoryStorage(),\n version = 0,\n partialize,\n migrate,\n onError,\n serialize = JSON.stringify,\n deserialize = JSON.parse,\n merge = (persisted, current) => ({ ...current, ...persisted }),\n skipHydration = false,\n } = options;\n let api: PersistMiddlewareAPI<T> | undefined;\n let destroyed = false;\n let hydrated = false;\n let hydrationGeneration = 0;\n let hydration: Promise<void> | undefined;\n let finishPending: (() => void) | undefined;\n let writeTail: Promise<void> | undefined;\n const callbacks = new Set<(state: T) => void>();\n\n function report(code: PersistErrorCode, cause: unknown): void {\n if (destroyed) return;\n try {\n onError?.({ code, message: `持久化 \"${key}\" 失败:${code}`, cause });\n } catch {\n /* 错误观察器不能中断状态更新或制造未处理的 Promise。 */\n }\n }\n\n function notify(callback: (state: T) => void): void {\n if (api === undefined || destroyed || !callbacks.has(callback)) return;\n try {\n callback(api.getState());\n } catch {\n /* 单个观察器失败不能阻止其余观察器或 rehydrate 完成。 */\n }\n }\n\n function finishHydration(): void {\n if (destroyed) return;\n hydrated = true;\n const resolve = finishPending;\n finishPending = undefined;\n hydration = undefined;\n resolve?.();\n for (const callback of Array.from(callbacks)) notify(callback);\n }\n\n /** 同步后端保持同步写入;异步写入和删除共享队列,避免旧写入覆盖新值。 */\n function enqueue(operation: () => void | Promise<void>): Promise<void> | undefined {\n const run = (): void | Promise<void> => {\n if (destroyed) return;\n try {\n const result = operation();\n if (result !== undefined) return Promise.resolve(result).catch((error: unknown) => report(PERSIST_ERROR_CODE.StorageWriteFailed, error));\n } catch (error) {\n report(PERSIST_ERROR_CODE.StorageWriteFailed, error);\n }\n };\n const result = writeTail === undefined ? run() : writeTail.then(run);\n if (result !== undefined) {\n const tail = Promise.resolve(result);\n writeTail = tail;\n void tail.then(() => {\n if (writeTail === tail) writeTail = undefined;\n });\n return tail;\n }\n return undefined;\n }\n\n function persistState(): void {\n if (api === undefined || destroyed) return;\n let value: string;\n try {\n const state = api.getState();\n value = serialize({ state: partialize === undefined ? state : partialize(state), version });\n } catch (error) {\n report(PERSIST_ERROR_CODE.SerializationFailed, error);\n return;\n }\n enqueue(() => storage.setItem(key, value));\n }\n\n function applyState(state: Partial<T>): void {\n if (api === undefined || destroyed) return;\n try {\n api.setState(merge(state, api.getState()));\n } catch (error) {\n report(PERSIST_ERROR_CODE.DeserializationFailed, error);\n }\n finishHydration();\n }\n\n function handleValue(raw: string | null): void {\n if (destroyed) return;\n if (raw === null || raw === \"\") {\n finishHydration();\n return;\n }\n let envelope: PersistEnvelope<Partial<T>>;\n try {\n envelope = readEnvelope<T>(deserialize(raw));\n } catch (error) {\n report(PERSIST_ERROR_CODE.DeserializationFailed, error);\n finishHydration();\n return;\n }\n if (envelope.version === version) {\n applyState(envelope.state);\n return;\n }\n if (migrate === undefined) {\n finishHydration();\n return;\n }\n try {\n const result = migrate(envelope.state, envelope.version);\n if (result !== null && typeof result === \"object\" && \"then\" in result && typeof result.then === \"function\") {\n void Promise.resolve(result).then(applyState, (error: unknown) => {\n report(PERSIST_ERROR_CODE.MigrationFailed, error);\n finishHydration();\n });\n } else {\n applyState(result as Partial<T>);\n }\n } catch (error) {\n report(PERSIST_ERROR_CODE.MigrationFailed, error);\n finishHydration();\n }\n }\n\n function rehydrate(): Promise<void> {\n if (destroyed || api === undefined) return Promise.resolve();\n if (hydration !== undefined) return hydration;\n hydrated = false;\n hydrationGeneration++;\n const pending = new Promise<void>((resolve) => {\n finishPending = resolve;\n });\n hydration = pending;\n try {\n const result = storage.getItem(key);\n if (typeof result === \"string\" || result === null) handleValue(result);\n else\n void Promise.resolve(result).then(handleValue, (error: unknown) => {\n report(PERSIST_ERROR_CODE.StorageReadFailed, error);\n finishHydration();\n });\n } catch (error) {\n report(PERSIST_ERROR_CODE.StorageReadFailed, error);\n finishHydration();\n }\n return pending;\n }\n\n return {\n name: \"persist\",\n init(middlewareApi) {\n api = middlewareApi;\n if (!skipHydration) void rehydrate();\n },\n onSet(_api, next, partial) {\n next(partial);\n persistState();\n },\n onDestroy() {\n destroyed = true;\n callbacks.clear();\n api = undefined;\n finishPending?.();\n finishPending = undefined;\n hydration = undefined;\n },\n rehydrate,\n hasHydrated: () => hydrated,\n onHydrate(callback) {\n if (destroyed) return () => {};\n callbacks.add(callback);\n if (hydrated) {\n const generation = hydrationGeneration;\n queueMicrotask(() => {\n if (generation === hydrationGeneration) notify(callback);\n });\n }\n return () => {\n callbacks.delete(callback);\n };\n },\n clearStorage: () => enqueue(() => storage.removeItem(key)) ?? Promise.resolve(),\n };\n}\n","import type { StorageAdapter } from \"./types.js\";\nexport function localStorageBackend(): StorageAdapter {\n return {\n getItem(key: string): string | null {\n try {\n return localStorage.getItem(key);\n } catch {\n return null;\n }\n },\n setItem(key: string, value: string): void {\n try {\n localStorage.setItem(key, value);\n } catch {\n /* 后端不可用时忽略操作。 */\n }\n },\n removeItem(key: string): void {\n try {\n localStorage.removeItem(key);\n } catch {\n /* 后端不可用时忽略操作。 */\n }\n },\n };\n}\n\nexport function sessionStorageBackend(): StorageAdapter {\n return {\n getItem(key: string): string | null {\n try {\n return sessionStorage.getItem(key);\n } catch {\n return null;\n }\n },\n setItem(key: string, value: string): void {\n try {\n sessionStorage.setItem(key, value);\n } catch {\n /* 后端不可用时忽略操作。 */\n }\n },\n removeItem(key: string): void {\n try {\n sessionStorage.removeItem(key);\n } catch {\n /* 后端不可用时忽略操作。 */\n }\n },\n };\n}\n","import type { StorageAdapter, CookieStorageOptions } from \"./types.js\";\nexport function cookieStorage(options?: CookieStorageOptions): StorageAdapter {\n const maxAge = options?.maxAge;\n const path = options?.path ?? \"/\";\n const sameSite = options?.sameSite;\n const secure = options?.secure;\n const domain = options?.domain;\n\n return {\n getItem(key: string): string | null {\n try {\n const cookies = document.cookie.split(\";\");\n const encodedKey = encodeURIComponent(key);\n for (const cookie of cookies) {\n const trimmed = cookie.trim();\n if (trimmed.startsWith(encodedKey + \"=\")) {\n return decodeURIComponent(trimmed.slice(encodedKey.length + 1));\n }\n }\n return null;\n } catch {\n return null;\n }\n },\n setItem(key: string, value: string): void {\n try {\n let cookie = `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n cookie += `; path=${path}`;\n if (maxAge !== undefined) cookie += `; max-age=${String(maxAge)}`;\n if (sameSite !== undefined) cookie += `; samesite=${sameSite}`;\n if (secure === true) cookie += \"; secure\";\n if (domain !== undefined) cookie += `; domain=${domain}`;\n document.cookie = cookie;\n } catch {\n /* 后端不可用时忽略操作。 */\n }\n },\n removeItem(key: string): void {\n try {\n document.cookie = `${encodeURIComponent(key)}=; max-age=0; path=${path}${domain === undefined ? \"\" : `; domain=${domain}`}${secure === true ? \"; secure\" : \"\"}${sameSite === undefined ? \"\" : `; samesite=${sameSite}`}`;\n } catch {\n /* 后端不可用时忽略操作。 */\n }\n },\n };\n}\n","import type { IndexedDBStorageOptions, StorageAdapter } from \"./types.js\";\n\nexport function indexedDBStorage(options?: IndexedDBStorageOptions): StorageAdapter {\n const { dbName = \"slux-storage\", storeName = \"keyval\", dbVersion = 1 } = options ?? {};\n let connection: Promise<IDBDatabase> | undefined;\n\n function open(): Promise<IDBDatabase> {\n if (connection !== undefined) return connection;\n connection = new Promise<IDBDatabase>((resolve, reject) => {\n const request = indexedDB.open(dbName, dbVersion);\n request.onupgradeneeded = () => {\n if (!request.result.objectStoreNames.contains(storeName)) request.result.createObjectStore(storeName);\n };\n request.onerror = () => reject(request.error ?? new Error(\"IndexedDB 打开失败\"));\n request.onsuccess = () => {\n const db = request.result;\n db.onversionchange = () => {\n db.close();\n connection = undefined;\n };\n resolve(db);\n };\n });\n connection = connection.catch((error: unknown) => {\n connection = undefined;\n throw error;\n });\n return connection;\n }\n\n async function transact(mode: IDBTransactionMode, action: (store: IDBObjectStore) => IDBRequest): Promise<unknown> {\n const db = await open();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(storeName, mode);\n const request = action(tx.objectStore(storeName));\n // 请求成功后事务还可能回滚,只在 commit 后确认写入成功。\n tx.oncomplete = () => resolve(request.result as unknown);\n tx.onabort = () => reject(tx.error ?? request.error ?? new Error(\"IndexedDB 事务已中止\"));\n tx.onerror = () => reject(tx.error ?? request.error ?? new Error(\"IndexedDB 事务失败\"));\n });\n }\n\n return {\n async getItem(key) {\n const result = await transact(\"readonly\", (store) => store.get(key));\n return typeof result === \"string\" ? result : null;\n },\n async setItem(key, value) {\n await transact(\"readwrite\", (store) => store.put(value, key));\n },\n async removeItem(key) {\n await transact(\"readwrite\", (store) => store.delete(key));\n },\n };\n}\n","import { generateBatchAutoImports } from \"@slux/shared\";\n\nconst allImportApis: string[] = [\n \"PERSIST_ERROR_CODE\",\n \"cookieStorage\",\n \"indexedDBStorage\",\n \"localStorageBackend\",\n \"memoryStorage\",\n \"persist\",\n \"sessionStorageBackend\",\n];\n\nexport const createAutoImportApis = (prefix: string = \"\") => {\n return generateBatchAutoImports([\n {\n prefix,\n fromName: \"@slux/storage\",\n imports: allImportApis,\n },\n ]);\n};\n"],"names":["PERSIST_ERROR_CODE","memoryStorage","store","Map","key","value","persist","options","api","hydration","finishPending","writeTail","storage","version","partialize","migrate","onError","serialize","JSON","deserialize","merge","persisted","current","skipHydration","destroyed","hydrated","hydrationGeneration","callbacks","Set","report","code","cause","notify","callback","undefined","finishHydration","resolve","Array","enqueue","operation","run","result","Promise","error","tail","applyState","state","handleValue","raw","envelope","readEnvelope","TypeError","Number","rehydrate","pending","middlewareApi","_api","next","partial","persistState","generation","queueMicrotask","localStorageBackend","localStorage","sessionStorageBackend","sessionStorage","cookieStorage","maxAge","path","sameSite","secure","domain","cookies","document","encodedKey","encodeURIComponent","cookie","trimmed","decodeURIComponent","String","indexedDBStorage","connection","dbName","storeName","dbVersion","transact","mode","action","db","reject","request","indexedDB","Error","tx","allImportApis","createAutoImportApis","prefix","generateBatchAutoImports"],"mappings":"wDAAO,IAAMA,EAAqB,CAChC,kBAAmB,oBACnB,mBAAoB,qBACpB,oBAAqB,sBACrB,sBAAuB,wBACvB,gBAAiB,iBACnB,ECLO,SAASC,IACd,IAAMC,EAAQ,IAAIC,IAElB,MAAO,CACL,QAAQC,GACCF,EAAM,GAAG,CAACE,IAAQ,KAE3B,QAAQA,CAAW,CAAEC,CAAa,EAChCH,EAAM,GAAG,CAACE,EAAKC,EACjB,EACA,WAAWD,CAAW,EACpBF,EAAM,MAAM,CAACE,EACf,EACA,QACEF,EAAM,KAAK,EACb,CACF,CACF,CCFO,SAASI,EAAWC,CAA0B,EACnD,IAYIC,EAIAC,EACAC,EACAC,EAlBE,CACJP,IAAAA,CAAG,CACHQ,QAAAA,EAAUX,GAAe,CACzBY,QAAAA,EAAU,CAAC,CACXC,WAAAA,CAAU,CACVC,QAAAA,CAAO,CACPC,QAAAA,CAAO,CACPC,UAAAA,EAAYC,KAAK,SAAS,CAC1BC,YAAAA,EAAcD,KAAK,KAAK,CACxBE,MAAAA,EAAQ,CAACC,EAAWC,IAAa,EAAE,GAAGA,CAAO,CAAE,GAAGD,CAAS,AAAC,EAAE,CAC9DE,cAAAA,EAAgB,EAAK,CACtB,CAAGhB,EAEAiB,EAAY,GACZC,EAAW,GACXC,EAAsB,EAIpBC,EAAY,IAAIC,IAEtB,SAASC,EAAOC,CAAsB,CAAEC,CAAc,EACpD,IAAIP,EACJ,GAAI,CACFR,IAAU,CAAEc,KAAAA,EAAM,QAAS,CAAC,KAAK,EAAE1B,EAAI,KAAK,EAAE0B,EAAK,CAAC,CAAEC,MAAAA,CAAM,EAC9D,CAAE,KAAM,CAER,CACF,CAEA,SAASC,EAAOC,CAA4B,EAC1C,GAAIzB,AAAQ0B,SAAR1B,IAAqBgB,GAAcG,EAAU,GAAG,CAACM,GACrD,GAAI,CACFA,EAASzB,EAAI,QAAQ,GACvB,CAAE,KAAM,CAER,CACF,CAEA,SAAS2B,IACP,GAAIX,EAAW,OACfC,EAAW,GACX,IAAMW,EAAU1B,EAIhB,IAAK,IAAMuB,KAHXvB,EAAgBwB,OAChBzB,EAAYyB,OACZE,MACuBC,MAAM,IAAI,CAACV,IAAYK,EAAOC,EACvD,CAGA,SAASK,EAAQC,CAAqC,EACpD,IAAMC,EAAM,KACV,IAAIhB,EACJ,GAAI,CACF,IAAMiB,EAASF,IACf,GAAIE,AAAWP,SAAXO,EAAsB,OAAOC,QAAQ,OAAO,CAACD,GAAQ,KAAK,CAAC,AAACE,GAAmBd,EAAO7B,EAAmB,kBAAkB,CAAE2C,GACnI,CAAE,MAAOA,EAAO,CACdd,EAAO7B,EAAmB,kBAAkB,CAAE2C,EAChD,CACF,EACMF,EAAS9B,AAAcuB,SAAdvB,EAA0B6B,IAAQ7B,EAAU,IAAI,CAAC6B,GAChE,GAAIC,AAAWP,SAAXO,EAAsB,CACxB,IAAMG,EAAOF,QAAQ,OAAO,CAACD,GAK7B,OAJA9B,EAAYiC,EACPA,EAAK,IAAI,CAAC,KACTjC,IAAciC,GAAMjC,CAAAA,EAAYuB,MAAQ,CAC9C,GACOU,CACT,CAEF,CAeA,SAASC,EAAWC,CAAiB,EACnC,GAAItC,AAAQ0B,SAAR1B,IAAqBgB,GACzB,GAAI,CACFhB,EAAI,QAAQ,CAACY,EAAM0B,EAAOtC,EAAI,QAAQ,IACxC,CAAE,MAAOmC,EAAO,CACdd,EAAO7B,EAAmB,qBAAqB,CAAE2C,EACnD,CACAR,IACF,CAEA,SAASY,EAAYC,CAAkB,MAMjCC,EALJ,IAAIzB,GACJ,GAAIwB,AAAQ,OAARA,GAAgBA,AAAQ,KAARA,EAAY,YAC9Bb,IAIF,GAAI,CACFc,EAAWC,AAnHjB,SAAyB7C,CAAc,EACrC,GAAI,AAAiB,UAAjB,OAAOA,GAAsBA,AAAU,OAAVA,GAAkB,CAAE,WAAWA,CAAI,EAClE,MAAM,AAAI8C,UAAU,iBAEtB,IAAMtC,EAAU,YAAaR,EAAQA,EAAM,OAAO,CAAG,EACrD,GAAI,AAAmB,UAAnB,OAAOQ,GAAwB,CAACuC,OAAO,QAAQ,CAACvC,GAClD,MAAM,AAAIsC,UAAU,uBAEtB,MAAO,CAAE,MAAO9C,EAAM,KAAK,CAAgBQ,QAAAA,CAAQ,CACrD,EA0GiCM,EAAY6B,GACzC,CAAE,MAAOL,EAAO,CACdd,EAAO7B,EAAmB,qBAAqB,CAAE2C,GACjDR,IACA,MACF,CACA,GAAIc,EAAS,OAAO,GAAKpC,EAAS,YAChCgC,EAAWI,EAAS,KAAK,EAG3B,GAAIlC,AAAYmB,SAAZnB,EAAuB,YACzBoB,IAGF,GAAI,CACF,IAAMM,EAAS1B,EAAQkC,EAAS,KAAK,CAAEA,EAAS,OAAO,CACnDR,AAAW,QAAXA,GAAmB,AAAkB,UAAlB,OAAOA,GAAuB,SAAUA,GAAU,AAAuB,YAAvB,OAAOA,EAAO,IAAI,CACpFC,QAAQ,OAAO,CAACD,GAAQ,IAAI,CAACI,EAAY,AAACF,IAC7Cd,EAAO7B,EAAmB,eAAe,CAAE2C,GAC3CR,GACF,GAEAU,EAAWJ,EAEf,CAAE,MAAOE,EAAO,CACdd,EAAO7B,EAAmB,eAAe,CAAE2C,GAC3CR,GACF,EACF,CAEA,SAASkB,IACP,GAAI7B,GAAahB,AAAQ0B,SAAR1B,EAAmB,OAAOkC,QAAQ,OAAO,GAC1D,GAAIjC,AAAcyB,SAAdzB,EAAyB,OAAOA,EACpCgB,EAAW,GACXC,IACA,IAAM4B,EAAU,IAAIZ,QAAc,AAACN,IACjC1B,EAAgB0B,CAClB,GACA3B,EAAY6C,EACZ,GAAI,CACF,IAAMb,EAAS7B,EAAQ,OAAO,CAACR,EAC3B,AAAkB,WAAlB,OAAOqC,GAAuBA,AAAW,OAAXA,EAAiBM,EAAYN,GAExDC,QAAQ,OAAO,CAACD,GAAQ,IAAI,CAACM,EAAa,AAACJ,IAC9Cd,EAAO7B,EAAmB,iBAAiB,CAAE2C,GAC7CR,GACF,EACJ,CAAE,MAAOQ,EAAO,CACdd,EAAO7B,EAAmB,iBAAiB,CAAE2C,GAC7CR,GACF,CACA,OAAOmB,CACT,CAEA,MAAO,CACL,KAAM,UACN,KAAKC,CAAa,EAChB/C,EAAM+C,EACF,AAAChC,GAAoB8B,GAC3B,EACA,MAAMG,CAAI,CAAEC,CAAI,CAAEC,CAAO,EACvBD,EAAKC,GACLC,AA7FJ,eAEMtD,EADJ,GAAIG,AAAQ0B,SAAR1B,IAAqBgB,GAEzB,GAAI,CACF,IAAMsB,EAAQtC,EAAI,QAAQ,GAC1BH,EAAQY,EAAU,CAAE,MAAOH,AAAeoB,SAAfpB,EAA2BgC,EAAQhC,EAAWgC,GAAQjC,QAAAA,CAAQ,EAC3F,CAAE,MAAO8B,EAAO,CACdd,EAAO7B,EAAmB,mBAAmB,CAAE2C,GAC/C,MACF,CACAL,EAAQ,IAAM1B,EAAQ,OAAO,CAACR,EAAKC,IACrC,GAmFE,EACA,YACEmB,EAAY,GACZG,EAAU,KAAK,GACfnB,EAAM0B,OACNxB,MACAA,EAAgBwB,OAChBzB,EAAYyB,MACd,EACAmB,UAAAA,EACA,YAAa,IAAM5B,EACnB,UAAUQ,CAAQ,EAChB,GAAIT,EAAW,MAAO,KAAO,EAE7B,GADAG,EAAU,GAAG,CAACM,GACVR,EAAU,CACZ,IAAMmC,EAAalC,EACnBmC,eAAe,KACTD,IAAelC,GAAqBM,EAAOC,EACjD,EACF,CACA,MAAO,KACLN,EAAU,MAAM,CAACM,EACnB,CACF,EACA,aAAc,IAAMK,EAAQ,IAAM1B,EAAQ,UAAU,CAACR,KAASsC,QAAQ,OAAO,EAC/E,CACF,CChNO,SAASoB,IACd,MAAO,CACL,QAAQ1D,CAAW,EACjB,GAAI,CACF,OAAO2D,aAAa,OAAO,CAAC3D,EAC9B,CAAE,KAAM,CACN,OAAO,IACT,CACF,EACA,QAAQA,CAAW,CAAEC,CAAa,EAChC,GAAI,CACF0D,aAAa,OAAO,CAAC3D,EAAKC,EAC5B,CAAE,KAAM,CAER,CACF,EACA,WAAWD,CAAW,EACpB,GAAI,CACF2D,aAAa,UAAU,CAAC3D,EAC1B,CAAE,KAAM,CAER,CACF,CACF,CACF,CAEO,SAAS4D,IACd,MAAO,CACL,QAAQ5D,CAAW,EACjB,GAAI,CACF,OAAO6D,eAAe,OAAO,CAAC7D,EAChC,CAAE,KAAM,CACN,OAAO,IACT,CACF,EACA,QAAQA,CAAW,CAAEC,CAAa,EAChC,GAAI,CACF4D,eAAe,OAAO,CAAC7D,EAAKC,EAC9B,CAAE,KAAM,CAER,CACF,EACA,WAAWD,CAAW,EACpB,GAAI,CACF6D,eAAe,UAAU,CAAC7D,EAC5B,CAAE,KAAM,CAER,CACF,CACF,CACF,CClDO,SAAS8D,EAAc3D,CAA8B,EAC1D,IAAM4D,EAAS5D,GAAS,OAClB6D,EAAO7D,GAAS,MAAQ,IACxB8D,EAAW9D,GAAS,SACpB+D,EAAS/D,GAAS,OAClBgE,EAAShE,GAAS,OAExB,MAAO,CACL,QAAQH,CAAW,EACjB,GAAI,CACF,IAAMoE,EAAUC,SAAS,MAAM,CAAC,KAAK,CAAC,KAChCC,EAAaC,mBAAmBvE,GACtC,IAAK,IAAMwE,KAAUJ,EAAS,CAC5B,IAAMK,EAAUD,EAAO,IAAI,GAC3B,GAAIC,EAAQ,UAAU,CAACH,EAAa,KAClC,OAAOI,mBAAmBD,EAAQ,KAAK,CAACH,EAAW,MAAM,CAAG,GAEhE,CACA,OAAO,IACT,CAAE,KAAM,CACN,OAAO,IACT,CACF,EACA,QAAQtE,CAAW,CAAEC,CAAa,EAChC,GAAI,CACF,IAAIuE,EAAS,CAAC,EAAED,mBAAmBvE,GAAK,CAAC,EAAEuE,mBAAmBtE,GAAO,CAAC,CACtEuE,GAAU,CAAC,OAAO,EAAER,EAAK,CAAC,CACtBD,AAAWjC,SAAXiC,GAAsBS,CAAAA,GAAU,CAAC,UAAU,EAAEG,OAAOZ,GAAQ,CAAC,AAAD,EAC5DE,AAAanC,SAAbmC,GAAwBO,CAAAA,GAAU,CAAC,WAAW,EAAEP,EAAS,CAAC,AAAD,EACzDC,AAAW,KAAXA,GAAiBM,CAAAA,GAAU,UAAS,EACpCL,AAAWrC,SAAXqC,GAAsBK,CAAAA,GAAU,CAAC,SAAS,EAAEL,EAAO,CAAC,AAAD,EACvDE,SAAS,MAAM,CAAGG,CACpB,CAAE,KAAM,CAER,CACF,EACA,WAAWxE,CAAW,EACpB,GAAI,CACFqE,SAAS,MAAM,CAAG,CAAC,EAAEE,mBAAmBvE,GAAK,mBAAmB,EAAEgE,EAAK,EAAEG,AAAWrC,SAAXqC,EAAuB,GAAK,CAAC,SAAS,EAAEA,EAAO,CAAC,CAAC,EAAED,AAAW,KAAXA,EAAkB,WAAa,GAAG,EAAED,AAAanC,SAAbmC,EAAyB,GAAK,CAAC,WAAW,EAAEA,EAAS,CAAC,CAAC,CAAC,AAC1N,CAAE,KAAM,CAER,CACF,CACF,CACF,CC3CO,SAASW,EAAiBzE,CAAiC,EAChE,IACI0E,EADE,CAAEC,OAAAA,EAAS,cAAc,CAAEC,UAAAA,EAAY,QAAQ,CAAEC,UAAAA,EAAY,CAAC,CAAE,CAAG7E,GAAW,CAAC,EA2BrF,eAAe8E,EAASC,CAAwB,CAAEC,CAA6C,EAC7F,IAAMC,EAAK,MAxBX,CAAIP,AAAe/C,SAAf+C,EAAiCA,EAgBrCA,EAAaA,AAfbA,CAAAA,EAAa,IAAIvC,QAAqB,CAACN,EAASqD,KAC9C,IAAMC,EAAUC,UAAU,IAAI,CAACT,EAAQE,EACvCM,CAAAA,EAAQ,eAAe,CAAG,KACpB,AAACA,EAAQ,MAAM,CAAC,gBAAgB,CAAC,QAAQ,CAACP,IAAYO,EAAQ,MAAM,CAAC,iBAAiB,CAACP,EAC7F,EACAO,EAAQ,OAAO,CAAG,IAAMD,EAAOC,EAAQ,KAAK,EAAI,AAAIE,MAAM,mBAC1DF,EAAQ,SAAS,CAAG,KAClB,IAAMF,EAAKE,EAAQ,MAAM,AACzBF,CAAAA,EAAG,eAAe,CAAG,KACnBA,EAAG,KAAK,GACRP,EAAa/C,MACf,EACAE,EAAQoD,EACV,CACF,EAAC,EACuB,KAAK,CAAC,AAAC7C,IAE7B,MADAsC,EAAa/C,OACPS,CACR,EAnB+C,EAyB/C,OAAO,IAAID,QAAQ,CAACN,EAASqD,KAC3B,IAAMI,EAAKL,EAAG,WAAW,CAACL,EAAWG,GAC/BI,EAAUH,EAAOM,EAAG,WAAW,CAACV,GAEtCU,CAAAA,EAAG,UAAU,CAAG,IAAMzD,EAAQsD,EAAQ,MAAM,EAC5CG,EAAG,OAAO,CAAG,IAAMJ,EAAOI,EAAG,KAAK,EAAIH,EAAQ,KAAK,EAAI,AAAIE,MAAM,oBACjEC,EAAG,OAAO,CAAG,IAAMJ,EAAOI,EAAG,KAAK,EAAIH,EAAQ,KAAK,EAAI,AAAIE,MAAM,kBACnE,EACF,CAEA,MAAO,CACL,MAAM,QAAQxF,CAAG,EACf,IAAMqC,EAAS,MAAM4C,EAAS,WAAY,AAACnF,GAAUA,EAAM,GAAG,CAACE,IAC/D,MAAO,AAAkB,UAAlB,OAAOqC,EAAsBA,EAAS,IAC/C,EACA,MAAM,QAAQrC,CAAG,CAAEC,CAAK,EACtB,MAAMgF,EAAS,YAAa,AAACnF,GAAUA,EAAM,GAAG,CAACG,EAAOD,GAC1D,EACA,MAAM,WAAWA,CAAG,EAClB,MAAMiF,EAAS,YAAa,AAACnF,GAAUA,EAAM,MAAM,CAACE,GACtD,CACF,CACF,CCpDA,IAAM0F,EAA0B,CAC9B,qBACA,gBACA,mBACA,sBACA,gBACA,UACA,wBACD,CAEYC,EAAuB,CAACC,EAAiB,EAAE,GAC/CC,EAAyB,CAC9B,CACED,OAAAA,EACA,SAAU,gBACV,QAASF,CACX,EACD,S"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,74 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slux/storage",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "支持同步和异步后端的 Store 持久化中间件",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"keywords": [
|
|
7
|
+
"slux",
|
|
8
|
+
"persistence",
|
|
9
|
+
"middleware",
|
|
10
|
+
"localstorage",
|
|
11
|
+
"indexeddb"
|
|
12
|
+
],
|
|
13
|
+
"author": "itmanyong <itmanyong@gmail.com>",
|
|
14
|
+
"contributors": [
|
|
15
|
+
"itmanyong <itmanyong@gmail.com>"
|
|
16
|
+
],
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"homepage": "https://www.npmjs.com/package/@slux/storage",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/itmanyong/slux.git",
|
|
25
|
+
"directory": "packages/storage"
|
|
26
|
+
},
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/itmanyong/slux/issues"
|
|
29
|
+
},
|
|
30
|
+
"type": "module",
|
|
31
|
+
"files": [
|
|
32
|
+
"dist",
|
|
33
|
+
"README.md",
|
|
34
|
+
"CHANGELOG.md",
|
|
35
|
+
"package.json"
|
|
36
|
+
],
|
|
37
|
+
"main": "./dist/index.cjs",
|
|
38
|
+
"module": "./dist/index.js",
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"exports": {
|
|
41
|
+
".": {
|
|
42
|
+
"import": {
|
|
43
|
+
"types": "./dist/index.d.ts",
|
|
44
|
+
"default": "./dist/index.js"
|
|
45
|
+
},
|
|
46
|
+
"require": {
|
|
47
|
+
"types": "./dist/index.d.cts",
|
|
48
|
+
"default": "./dist/index.cjs"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"./package.json": "./package.json"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@slux/store": "0.1.1",
|
|
55
|
+
"@slux/shared": "0.1.1"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"rstack": "0.9.0",
|
|
59
|
+
"typescript": "7.1.0-beta",
|
|
60
|
+
"@slux/core": "0.1.1",
|
|
61
|
+
"jsdom": "30.1.3",
|
|
62
|
+
"fake-indexeddb": "6.2.7",
|
|
63
|
+
"@types/jsdom": "21.1.7"
|
|
64
|
+
},
|
|
65
|
+
"scripts": {
|
|
66
|
+
"dev": "rs lib -w",
|
|
67
|
+
"build": "rs lib",
|
|
68
|
+
"test": "rs test",
|
|
69
|
+
"lint": "rs lint",
|
|
70
|
+
"fmt": "rs fmt",
|
|
71
|
+
"typecheck": "tsc --noEmit",
|
|
72
|
+
"clean": "rm -rf dist node_modules .turbo"
|
|
73
|
+
}
|
|
6
74
|
}
|