@vope/utils 1.6.0-bate.3 → 1.6.0-bate.4

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/dist/index.js CHANGED
@@ -70,102 +70,15 @@ var clamp = (value, min, max) => {
70
70
  return Math.min(max, Math.max(min, value));
71
71
  };
72
72
 
73
- // node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/_freeGlobal.js
74
- var freeGlobal = typeof global == "object" && global && global.Object === Object && global;
75
- var freeGlobal_default = freeGlobal;
76
-
77
- // node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/_root.js
78
- var freeSelf = typeof self == "object" && self && self.Object === Object && self;
79
- var root = freeGlobal_default || freeSelf || Function("return this")();
80
- var root_default = root;
81
-
82
- // node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/_Symbol.js
83
- var Symbol2 = root_default.Symbol;
84
- var Symbol_default = Symbol2;
85
-
86
- // node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/_getRawTag.js
87
- var objectProto = Object.prototype;
88
- var hasOwnProperty = objectProto.hasOwnProperty;
89
- var nativeObjectToString = objectProto.toString;
90
- var symToStringTag = Symbol_default ? Symbol_default.toStringTag : void 0;
91
- function getRawTag(value) {
92
- var isOwn = hasOwnProperty.call(value, symToStringTag), tag = value[symToStringTag];
93
- try {
94
- value[symToStringTag] = void 0;
95
- var unmasked = true;
96
- } catch (e) {
97
- }
98
- var result = nativeObjectToString.call(value);
99
- if (unmasked) {
100
- if (isOwn) {
101
- value[symToStringTag] = tag;
102
- } else {
103
- delete value[symToStringTag];
104
- }
105
- }
106
- return result;
107
- }
108
- var getRawTag_default = getRawTag;
109
-
110
- // node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/_objectToString.js
111
- var objectProto2 = Object.prototype;
112
- var nativeObjectToString2 = objectProto2.toString;
113
- function objectToString(value) {
114
- return nativeObjectToString2.call(value);
115
- }
116
- var objectToString_default = objectToString;
117
-
118
- // node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/_baseGetTag.js
119
- var nullTag = "[object Null]";
120
- var undefinedTag = "[object Undefined]";
121
- var symToStringTag2 = Symbol_default ? Symbol_default.toStringTag : void 0;
122
- function baseGetTag(value) {
123
- if (value == null) {
124
- return value === void 0 ? undefinedTag : nullTag;
125
- }
126
- return symToStringTag2 && symToStringTag2 in Object(value) ? getRawTag_default(value) : objectToString_default(value);
127
- }
128
- var baseGetTag_default = baseGetTag;
129
-
130
- // node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/isObjectLike.js
131
- function isObjectLike(value) {
132
- return value != null && typeof value == "object";
133
- }
134
- var isObjectLike_default = isObjectLike;
135
-
136
- // node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/isArray.js
137
- var isArray = Array.isArray;
138
- var isArray_default = isArray;
139
-
140
- // node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/isString.js
141
- var stringTag = "[object String]";
142
- function isString(value) {
143
- return typeof value == "string" || !isArray_default(value) && isObjectLike_default(value) && baseGetTag_default(value) == stringTag;
144
- }
145
- var isString_default = isString;
146
-
147
- // node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/isBoolean.js
148
- var boolTag = "[object Boolean]";
149
- function isBoolean(value) {
150
- return value === true || value === false || isObjectLike_default(value) && baseGetTag_default(value) == boolTag;
151
- }
152
- var isBoolean_default = isBoolean;
153
-
154
- // node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/isNumber.js
155
- var numberTag = "[object Number]";
156
- function isNumber(value) {
157
- return typeof value == "number" || isObjectLike_default(value) && baseGetTag_default(value) == numberTag;
158
- }
159
- var isNumber_default = isNumber;
160
-
161
73
  // src/classnames.ts
74
+ var import_lodash_es = require("lodash-es");
162
75
  var add = (a, b) => a ? a + " " + b : b;
163
76
  var classnames = (...list) => list.reduce((caches, data) => {
164
- if (isString_default(data)) {
77
+ if ((0, import_lodash_es.isString)(data)) {
165
78
  data && (caches = add(caches, data));
166
79
  } else if (Array.isArray(data)) {
167
- data.forEach((value) => value && isString_default(value) && (caches = add(caches, value)));
168
- } else if (!isBoolean_default(data)) {
80
+ data.forEach((value) => value && (0, import_lodash_es.isString)(value) && (caches = add(caches, value)));
81
+ } else if (!(0, import_lodash_es.isBoolean)(data)) {
169
82
  for (const key in data) {
170
83
  key && data[key] && (caches = add(caches, key));
171
84
  }
@@ -237,6 +150,7 @@ var hash8object = (list, key) => list.reduce((caches, data) => {
237
150
  }, /* @__PURE__ */ new Map());
238
151
 
239
152
  // src/desens.ts
153
+ var import_lodash_es2 = require("lodash-es");
240
154
  var desensEncrypt = (plaintext, encrypt) => {
241
155
  const rules = [];
242
156
  let point = -1;
@@ -275,7 +189,7 @@ var desensReplace = (ciphertext, rules, replacer = "*") => {
275
189
  return rules.reduce((cache, { range: [start, stop], modify }) => {
276
190
  const part = ciphertext.slice(start + offset, start + offset + modify);
277
191
  const size = stop + 1 - start;
278
- const replaceValue = isString_default(replacer) ? replacer.repeat(size) : replacer[Symbol.replace](part, size);
192
+ const replaceValue = (0, import_lodash_es2.isString)(replacer) ? replacer.repeat(size) : replacer[Symbol.replace](part, size);
279
193
  cache += ciphertext.slice(from, start + offset) + replaceValue;
280
194
  from = start + offset + modify;
281
195
  offset += modify - size;
@@ -1025,10 +939,11 @@ var once = (func, thisArg) => {
1025
939
  };
1026
940
 
1027
941
  // src/parse/num.ts
942
+ var import_lodash_es3 = require("lodash-es");
1028
943
  var pow = Math.floor(Math.log10(Number.MAX_SAFE_INTEGER));
1029
944
  var re_num = /^([-+]?)0*(\d+)(?:(n)|(?:\.(\d+))?(?:[Ee]([-+]?)(\d+))?)$/;
1030
945
  var parseNum = (num) => {
1031
- if (isNumber_default(num) || typeof num === "bigint") return num;
946
+ if ((0, import_lodash_es3.isNumber)(num) || typeof num === "bigint") return num;
1032
947
  const match = num.match(re_num);
1033
948
  if (!match) return Number.NaN;
1034
949
  const [, valueSymbol, integer, bigint, decimal, powSymbol, powValue] = match;
@@ -1057,6 +972,7 @@ var parseNum = (num) => {
1057
972
  var rotateAngle = (from, angle, visit) => rotateRad(from, angle / 180 * Math.PI, visit);
1058
973
 
1059
974
  // src/serialize/url-params.ts
975
+ var import_lodash_es4 = require("lodash-es");
1060
976
  var cubes = {
1061
977
  string: (text) => text,
1062
978
  boolean: (text) => text === "true",
@@ -1081,7 +997,7 @@ var cubeURLParams = (text, serializes) => {
1081
997
  for (const [key, value] of params) {
1082
998
  const serialize = serializes[key];
1083
999
  if (!serialize) continue;
1084
- if (isString_default(serialize) && isKey(serialize, cubes)) {
1000
+ if ((0, import_lodash_es4.isString)(serialize) && isKey(serialize, cubes)) {
1085
1001
  result[key] = cubes[serialize](value);
1086
1002
  } else {
1087
1003
  result[key] = serialize.cube(value);
@@ -1099,20 +1015,21 @@ var flatURLParams = (data, serializes) => {
1099
1015
  if (!serialize) continue;
1100
1016
  params.append(
1101
1017
  key,
1102
- isString_default(serialize) && isKey(serialize, flats) ? flats[serialize](value) : serialize.flat(value)
1018
+ (0, import_lodash_es4.isString)(serialize) && isKey(serialize, flats) ? flats[serialize](value) : serialize.flat(value)
1103
1019
  );
1104
1020
  }
1105
1021
  return params.toString();
1106
1022
  };
1107
1023
 
1108
1024
  // src/style/css.ts
1025
+ var import_lodash_es5 = require("lodash-es");
1109
1026
  var hump = /[A-Z]/g;
1110
1027
  var css = (...args) => {
1111
1028
  const list = [];
1112
1029
  for (let i = 0; i < args.length; i++) {
1113
1030
  const data = args[i];
1114
1031
  if (!data) continue;
1115
- if (isString_default(data)) {
1032
+ if ((0, import_lodash_es5.isString)(data)) {
1116
1033
  list.push(data);
1117
1034
  } else if (Array.isArray(data)) {
1118
1035
  const result = css(...data);
@@ -1346,16 +1263,3 @@ var connectURLParams = (url, params, serializes) => {
1346
1263
 
1347
1264
  // src/wait.ts
1348
1265
  var wait = (delay = 0) => new Promise((resolve) => setTimeout(resolve, delay));
1349
- /*! Bundled license information:
1350
-
1351
- lodash-es/lodash.js:
1352
- (**
1353
- * @license
1354
- * Lodash (Custom Build) <https://lodash.com/>
1355
- * Build: `lodash modularize exports="es" -o ./`
1356
- * Copyright OpenJS Foundation and other contributors <https://openjsf.org/>
1357
- * Released under MIT license <https://lodash.com/license>
1358
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
1359
- * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
1360
- *)
1361
- */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vope/utils",
3
- "version": "1.6.0-bate.3",
3
+ "version": "1.6.0-bate.4",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -37,7 +37,7 @@
37
37
  "license": "ISC",
38
38
  "files": [
39
39
  "dist",
40
- "sub_*"
40
+ "sub_storage"
41
41
  ],
42
42
  "devDependencies": {
43
43
  "@babel/parser": "^7.26.9",
@@ -0,0 +1,51 @@
1
+ export interface ICrypto<From, To> {
2
+ encrypt(plain: From): To | Promise<To>;
3
+ decrypt(cipher: To): From | Promise<From>;
4
+ }
5
+ interface Options<From, To> {
6
+ /** 存储名称 */
7
+ name: string;
8
+ /** 存储认证 */
9
+ token?: string;
10
+ /** 存储期限 */
11
+ expire?: number;
12
+ /** 存储加密 */
13
+ crypto: ICrypto<From, To>;
14
+ }
15
+ /**
16
+ * 离线存储
17
+ */
18
+ export declare class OfflineStorage<From, To> {
19
+ #private;
20
+ get size(): number;
21
+ get mounted(): boolean;
22
+ constructor({ name, expire: newExpire, token: newToken, crypto, }: Options<From, To>);
23
+ ready(): Promise<this>;
24
+ /**
25
+ * 校验存储是否过期
26
+ */
27
+ validateExpire(): boolean;
28
+ /**
29
+ * 校验
30
+ */
31
+ validate(callback: (error?: Error) => void, expireMessage?: string): void;
32
+ /**
33
+ * 插入数据
34
+ */
35
+ push(data: From): Promise<number>;
36
+ /**
37
+ * 修改数据
38
+ */
39
+ update(index: number, data: From): Promise<boolean>;
40
+ /**
41
+ * 获取数据
42
+ */
43
+ get(index: number): Promise<From | null>;
44
+ /**
45
+ * 清理存储
46
+ */
47
+ clear(): Promise<void>;
48
+ static default<T>(options: string | Omit<Options<T, T>, 'crypto'>): OfflineStorage<T, T>;
49
+ static clear(token?: string, callback?: (name: string) => boolean): Promise<void>;
50
+ }
51
+ export {};
@@ -0,0 +1,255 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key2 of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key2) && key2 !== except)
16
+ __defProp(to, key2, { get: () => from[key2], enumerable: !(desc = __getOwnPropDesc(from, key2)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/storage/offline.ts
31
+ var offline_exports = {};
32
+ __export(offline_exports, {
33
+ OfflineStorage: () => OfflineStorage
34
+ });
35
+ module.exports = __toCommonJS(offline_exports);
36
+ var import_localforage = __toESM(require("localforage"), 1);
37
+ var import_lodash_es = require("lodash-es");
38
+ var import_sm_crypto = require("sm-crypto");
39
+ var NAME = "@vope/utils";
40
+ var PREFIX = NAME + "_";
41
+ var key = [25, 144, 1, 32, 25, 135, 6, 40, 32, 23, 18, 19, 32, 36, 9, 5];
42
+ var iv = [182, 59, 9, 29, 86, 64, 118, 111, 112, 101, 47, 117, 116, 105, 108, 115];
43
+ var config = {
44
+ output: "string",
45
+ mode: "cbc",
46
+ iv
47
+ };
48
+ var HEADER = "." + import_sm_crypto.sm4.encrypt(NAME, key, config);
49
+ var encrypt = (data) => {
50
+ let text = "";
51
+ for (const key2 in data) {
52
+ const value = data[key2];
53
+ if (value === void 0) continue;
54
+ text && (text += "&");
55
+ text += key2 + ":" + value;
56
+ }
57
+ return import_sm_crypto.sm4.encrypt(text, key, config);
58
+ };
59
+ var decrypt = (text) => {
60
+ const data = {};
61
+ let value;
62
+ try {
63
+ value = import_sm_crypto.sm4.decrypt(text, key, config);
64
+ } catch {
65
+ value = "";
66
+ }
67
+ value.split("&").forEach((pair) => {
68
+ const [key2, value2] = pair.split(":");
69
+ if (key2 === "expire") {
70
+ data[key2] = +value2;
71
+ } else {
72
+ data[key2] = value2;
73
+ }
74
+ });
75
+ return data;
76
+ };
77
+ var structKey = (index) => index.toString(16).padStart(8, "0");
78
+ var reductKey = (key2) => parseInt(key2, 16);
79
+ var MESSAGES = {
80
+ mount: "Please wait for the mounting to complete",
81
+ auth: "Unauthorized operation",
82
+ push: "Cannot add data to expired databases",
83
+ update: "Cannot update data to expired databases",
84
+ get: "Cannot get data from expired databases"
85
+ };
86
+ var createInstance = (name, version = 2) => import_localforage.default.createInstance({
87
+ driver: import_localforage.default.INDEXEDDB,
88
+ name,
89
+ version
90
+ });
91
+ var OfflineStorage = class _OfflineStorage {
92
+ #forage;
93
+ #expire;
94
+ #auth = false;
95
+ #crypto;
96
+ #size = 0;
97
+ #mount;
98
+ #mounted = false;
99
+ get size() {
100
+ return this.#size;
101
+ }
102
+ get mounted() {
103
+ return this.#mounted;
104
+ }
105
+ constructor({
106
+ name,
107
+ expire: newExpire,
108
+ token: newToken,
109
+ crypto
110
+ }) {
111
+ const forage = this.#forage = createInstance(import_sm_crypto.sm4.encrypt(PREFIX + name, key, config));
112
+ this.#mount = new Promise(async (resolve) => {
113
+ const keys = await forage.keys().then((keys2) => keys2).catch(() => []);
114
+ let size = 0;
115
+ let expire = newExpire;
116
+ let token = newToken;
117
+ let auth = true;
118
+ for (const key2 of keys) {
119
+ if (key2 === HEADER) {
120
+ const {
121
+ expire: oldExpire,
122
+ token: oldToken
123
+ } = decrypt(await forage.getItem(key2));
124
+ expire = oldExpire === void 0 ? newExpire : Date.now() < oldExpire ? newExpire : oldExpire;
125
+ auth = oldToken ? oldToken === newToken : true;
126
+ token = oldToken || newToken;
127
+ } else {
128
+ const value = reductKey(key2) + 1;
129
+ value > size && (size = value);
130
+ }
131
+ }
132
+ this.#size = size;
133
+ this.#expire = expire;
134
+ this.#auth = auth;
135
+ this.#crypto = crypto;
136
+ await forage.setItem(HEADER, encrypt({
137
+ expire,
138
+ token
139
+ }));
140
+ this.#mounted = true;
141
+ resolve(this);
142
+ });
143
+ }
144
+ ready() {
145
+ return this.#mount;
146
+ }
147
+ /**
148
+ * 校验存储是否过期
149
+ */
150
+ validateExpire() {
151
+ const expire = this.#expire;
152
+ return expire === void 0 || Date.now() < expire;
153
+ }
154
+ /**
155
+ * 校验
156
+ */
157
+ validate(callback, expireMessage) {
158
+ if (!this.#mounted) {
159
+ callback(new Error(MESSAGES.mount));
160
+ } else if (!this.#auth) {
161
+ callback(new Error(MESSAGES.auth));
162
+ } else if (expireMessage && !this.validateExpire()) {
163
+ callback(new Error(expireMessage));
164
+ } else {
165
+ callback();
166
+ }
167
+ }
168
+ /**
169
+ * 插入数据
170
+ */
171
+ async push(data) {
172
+ this.validate((e) => {
173
+ if (e) throw e;
174
+ }, MESSAGES.push);
175
+ const size = this.#size;
176
+ const key2 = structKey(size);
177
+ await this.#forage.setItem(key2, await this.#crypto.encrypt(data));
178
+ return this.#size = size + 1;
179
+ }
180
+ /**
181
+ * 修改数据
182
+ */
183
+ async update(index, data) {
184
+ this.validate((e) => {
185
+ if (e) throw e;
186
+ }, MESSAGES.update);
187
+ const forage = this.#forage;
188
+ const key2 = structKey(index);
189
+ const value = await forage.getItem(key2);
190
+ if (value === null) return false;
191
+ await forage.setItem(key2, await this.#crypto.encrypt(data));
192
+ return true;
193
+ }
194
+ /**
195
+ * 获取数据
196
+ */
197
+ async get(index) {
198
+ this.validate((e) => {
199
+ if (e) throw e;
200
+ }, MESSAGES.get);
201
+ const key2 = structKey(index);
202
+ const value = await this.#forage.getItem(key2);
203
+ return value === null ? null : await this.#crypto.decrypt(value);
204
+ }
205
+ /**
206
+ * 清理存储
207
+ */
208
+ async clear() {
209
+ this.validate((e) => {
210
+ if (e) throw e;
211
+ });
212
+ this.#size = 0;
213
+ await import_localforage.default.dropInstance({
214
+ name: this.#forage.config().name
215
+ });
216
+ }
217
+ static default(options) {
218
+ (0, import_lodash_es.isString)(options) && (options = { name: options });
219
+ return new _OfflineStorage({
220
+ ...options,
221
+ crypto: {
222
+ encrypt(plain) {
223
+ return plain;
224
+ },
225
+ decrypt(cipher) {
226
+ return cipher;
227
+ }
228
+ }
229
+ });
230
+ }
231
+ static async clear(token, callback) {
232
+ const size = PREFIX.length;
233
+ const databases = await indexedDB.databases();
234
+ const tasks = [];
235
+ for (const { name, version } of databases) {
236
+ if (name === void 0) continue;
237
+ let text;
238
+ try {
239
+ text = import_sm_crypto.sm4.decrypt(name, key, config);
240
+ } catch {
241
+ continue;
242
+ }
243
+ if (text.slice(0, size) !== PREFIX) continue;
244
+ const forage = createInstance(name, version);
245
+ const value = await forage.getItem(HEADER);
246
+ if (value === null || decrypt(value).token !== token || callback && callback(text.slice(size))) continue;
247
+ const idb = indexedDB.deleteDatabase(text);
248
+ tasks.push(new Promise((resolve) => {
249
+ idb.onerror = () => resolve();
250
+ idb.onsuccess = () => resolve();
251
+ }));
252
+ }
253
+ await Promise.all(tasks);
254
+ }
255
+ };
@@ -0,0 +1,223 @@
1
+ import localforage from "localforage";
2
+ import { isString } from "lodash-es";
3
+ import { sm4 } from "sm-crypto";
4
+ const NAME = "@vope/utils";
5
+ const PREFIX = NAME + "_";
6
+ const key = [25, 144, 1, 32, 25, 135, 6, 40, 32, 23, 18, 19, 32, 36, 9, 5];
7
+ const iv = [182, 59, 9, 29, 86, 64, 118, 111, 112, 101, 47, 117, 116, 105, 108, 115];
8
+ const config = {
9
+ output: "string",
10
+ mode: "cbc",
11
+ iv
12
+ };
13
+ const HEADER = "." + sm4.encrypt(NAME, key, config);
14
+ const encrypt = (data) => {
15
+ let text = "";
16
+ for (const key2 in data) {
17
+ const value = data[key2];
18
+ if (value === void 0) continue;
19
+ text && (text += "&");
20
+ text += key2 + ":" + value;
21
+ }
22
+ return sm4.encrypt(text, key, config);
23
+ };
24
+ const decrypt = (text) => {
25
+ const data = {};
26
+ let value;
27
+ try {
28
+ value = sm4.decrypt(text, key, config);
29
+ } catch {
30
+ value = "";
31
+ }
32
+ value.split("&").forEach((pair) => {
33
+ const [key2, value2] = pair.split(":");
34
+ if (key2 === "expire") {
35
+ data[key2] = +value2;
36
+ } else {
37
+ data[key2] = value2;
38
+ }
39
+ });
40
+ return data;
41
+ };
42
+ const structKey = (index) => index.toString(16).padStart(8, "0");
43
+ const reductKey = (key2) => parseInt(key2, 16);
44
+ const MESSAGES = {
45
+ mount: "Please wait for the mounting to complete",
46
+ auth: "Unauthorized operation",
47
+ push: "Cannot add data to expired databases",
48
+ update: "Cannot update data to expired databases",
49
+ get: "Cannot get data from expired databases"
50
+ };
51
+ const createInstance = (name, version = 2) => localforage.createInstance({
52
+ driver: localforage.INDEXEDDB,
53
+ name,
54
+ version
55
+ });
56
+ class OfflineStorage {
57
+ #forage;
58
+ #expire;
59
+ #auth = false;
60
+ #crypto;
61
+ #size = 0;
62
+ #mount;
63
+ #mounted = false;
64
+ get size() {
65
+ return this.#size;
66
+ }
67
+ get mounted() {
68
+ return this.#mounted;
69
+ }
70
+ constructor({
71
+ name,
72
+ expire: newExpire,
73
+ token: newToken,
74
+ crypto
75
+ }) {
76
+ const forage = this.#forage = createInstance(sm4.encrypt(PREFIX + name, key, config));
77
+ this.#mount = new Promise(async (resolve) => {
78
+ const keys = await forage.keys().then((keys2) => keys2).catch(() => []);
79
+ let size = 0;
80
+ let expire = newExpire;
81
+ let token = newToken;
82
+ let auth = true;
83
+ for (const key2 of keys) {
84
+ if (key2 === HEADER) {
85
+ const {
86
+ expire: oldExpire,
87
+ token: oldToken
88
+ } = decrypt(await forage.getItem(key2));
89
+ expire = oldExpire === void 0 ? newExpire : Date.now() < oldExpire ? newExpire : oldExpire;
90
+ auth = oldToken ? oldToken === newToken : true;
91
+ token = oldToken || newToken;
92
+ } else {
93
+ const value = reductKey(key2) + 1;
94
+ value > size && (size = value);
95
+ }
96
+ }
97
+ this.#size = size;
98
+ this.#expire = expire;
99
+ this.#auth = auth;
100
+ this.#crypto = crypto;
101
+ await forage.setItem(HEADER, encrypt({
102
+ expire,
103
+ token
104
+ }));
105
+ this.#mounted = true;
106
+ resolve(this);
107
+ });
108
+ }
109
+ ready() {
110
+ return this.#mount;
111
+ }
112
+ /**
113
+ * 校验存储是否过期
114
+ */
115
+ validateExpire() {
116
+ const expire = this.#expire;
117
+ return expire === void 0 || Date.now() < expire;
118
+ }
119
+ /**
120
+ * 校验
121
+ */
122
+ validate(callback, expireMessage) {
123
+ if (!this.#mounted) {
124
+ callback(new Error(MESSAGES.mount));
125
+ } else if (!this.#auth) {
126
+ callback(new Error(MESSAGES.auth));
127
+ } else if (expireMessage && !this.validateExpire()) {
128
+ callback(new Error(expireMessage));
129
+ } else {
130
+ callback();
131
+ }
132
+ }
133
+ /**
134
+ * 插入数据
135
+ */
136
+ async push(data) {
137
+ this.validate((e) => {
138
+ if (e) throw e;
139
+ }, MESSAGES.push);
140
+ const size = this.#size;
141
+ const key2 = structKey(size);
142
+ await this.#forage.setItem(key2, await this.#crypto.encrypt(data));
143
+ return this.#size = size + 1;
144
+ }
145
+ /**
146
+ * 修改数据
147
+ */
148
+ async update(index, data) {
149
+ this.validate((e) => {
150
+ if (e) throw e;
151
+ }, MESSAGES.update);
152
+ const forage = this.#forage;
153
+ const key2 = structKey(index);
154
+ const value = await forage.getItem(key2);
155
+ if (value === null) return false;
156
+ await forage.setItem(key2, await this.#crypto.encrypt(data));
157
+ return true;
158
+ }
159
+ /**
160
+ * 获取数据
161
+ */
162
+ async get(index) {
163
+ this.validate((e) => {
164
+ if (e) throw e;
165
+ }, MESSAGES.get);
166
+ const key2 = structKey(index);
167
+ const value = await this.#forage.getItem(key2);
168
+ return value === null ? null : await this.#crypto.decrypt(value);
169
+ }
170
+ /**
171
+ * 清理存储
172
+ */
173
+ async clear() {
174
+ this.validate((e) => {
175
+ if (e) throw e;
176
+ });
177
+ this.#size = 0;
178
+ await localforage.dropInstance({
179
+ name: this.#forage.config().name
180
+ });
181
+ }
182
+ static default(options) {
183
+ isString(options) && (options = { name: options });
184
+ return new OfflineStorage({
185
+ ...options,
186
+ crypto: {
187
+ encrypt(plain) {
188
+ return plain;
189
+ },
190
+ decrypt(cipher) {
191
+ return cipher;
192
+ }
193
+ }
194
+ });
195
+ }
196
+ static async clear(token, callback) {
197
+ const size = PREFIX.length;
198
+ const databases = await indexedDB.databases();
199
+ const tasks = [];
200
+ for (const { name, version } of databases) {
201
+ if (name === void 0) continue;
202
+ let text;
203
+ try {
204
+ text = sm4.decrypt(name, key, config);
205
+ } catch {
206
+ continue;
207
+ }
208
+ if (text.slice(0, size) !== PREFIX) continue;
209
+ const forage = createInstance(name, version);
210
+ const value = await forage.getItem(HEADER);
211
+ if (value === null || decrypt(value).token !== token || callback && callback(text.slice(size))) continue;
212
+ const idb = indexedDB.deleteDatabase(text);
213
+ tasks.push(new Promise((resolve) => {
214
+ idb.onerror = () => resolve();
215
+ idb.onsuccess = () => resolve();
216
+ }));
217
+ }
218
+ await Promise.all(tasks);
219
+ }
220
+ }
221
+ export {
222
+ OfflineStorage
223
+ };