taozen
Version:
一个轻量级的任务管理库
1,205 lines (1,177 loc) • 117 kB
JavaScript
'use strict';
var react = require('react');
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
var __assign$1 = function() {
__assign$1 = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign$1.apply(this, arguments);
};
function __rest(s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
}
function __awaiter$1(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
function __generator$1(thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
}
function __values(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
}
function __read$1(o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
}
function __spreadArray(to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, [])).next());
});
}
function __generator(thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
}
function __read(o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
/**
* IndexedDB 存储适配器
*/
var IndexedDBAdapter = /** @class */ (function () {
function IndexedDBAdapter(config) {
this.db = null;
this.databaseName = config.database;
this.objectStoreName = config.object || "echo-state";
this.name = config.name;
}
/**
* 获取当前数据库名称
*/
IndexedDBAdapter.prototype.getDatabaseName = function () {
return this.databaseName;
};
/**
* 获取当前对象仓库名称
*/
IndexedDBAdapter.prototype.getObjectStoreName = function () {
return this.objectStoreName;
};
IndexedDBAdapter.prototype.init = function () {
return __awaiter(this, void 0, void 0, function () {
var _a;
var _this = this;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
if (this.db)
return [2 /*return*/];
_a = this;
return [4 /*yield*/, new Promise(function (resolve, reject) {
var request = indexedDB.open(_this.databaseName, 1);
request.onerror = function () { return reject(request.error); };
request.onsuccess = function () { return resolve(request.result); };
request.onupgradeneeded = function (event) {
var db = event.target.result;
if (!db.objectStoreNames.contains(_this.objectStoreName)) {
db.createObjectStore(_this.objectStoreName);
}
};
})];
case 1:
_a.db = _b.sent();
return [2 /*return*/];
}
});
});
};
IndexedDBAdapter.prototype.getItem = function () {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.init()];
case 1:
_a.sent();
return [2 /*return*/, new Promise(function (resolve, reject) {
var transaction = _this.db.transaction(_this.objectStoreName, "readonly");
var store = transaction.objectStore(_this.objectStoreName);
var request = store.get(_this.name);
request.onsuccess = function () { return resolve(request.result); };
request.onerror = function () { return reject(request.error); };
})];
}
});
});
};
IndexedDBAdapter.prototype.setItem = function (value) {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.init()];
case 1:
_a.sent();
return [2 /*return*/, new Promise(function (resolve, reject) {
var transaction = _this.db.transaction(_this.objectStoreName, "readwrite");
var store = transaction.objectStore(_this.objectStoreName);
var request = store.put(value, _this.name);
request.onsuccess = function () { return resolve(); };
request.onerror = function () { return reject(request.error); };
})];
}
});
});
};
IndexedDBAdapter.prototype.removeItem = function () {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.init()];
case 1:
_a.sent();
return [2 /*return*/, new Promise(function (resolve, reject) {
var transaction = _this.db.transaction(_this.objectStoreName, "readwrite");
var store = transaction.objectStore(_this.objectStoreName);
var request = store.delete(_this.name);
request.onsuccess = function () { return resolve(); };
request.onerror = function () { return reject(request.error); };
})];
}
});
});
};
IndexedDBAdapter.prototype.destroy = function () {
this.removeItem();
this.close();
indexedDB.deleteDatabase(this.databaseName);
};
IndexedDBAdapter.prototype.close = function () {
var _a;
(_a = this.db) === null || _a === void 0 ? void 0 : _a.close();
this.db = null;
};
return IndexedDBAdapter;
}());
/**
* LocalStorage 存储适配器
*/
var LocalStorageAdapter = /** @class */ (function () {
function LocalStorageAdapter(config) {
this.config = config;
}
Object.defineProperty(LocalStorageAdapter.prototype, "name", {
get: function () {
return this.config.name;
},
enumerable: false,
configurable: true
});
LocalStorageAdapter.prototype.init = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/];
});
});
};
LocalStorageAdapter.prototype.getItem = function () {
return __awaiter(this, void 0, void 0, function () {
var value;
return __generator(this, function (_a) {
value = localStorage.getItem(this.name);
return [2 /*return*/, value ? JSON.parse(value) : null];
});
});
};
LocalStorageAdapter.prototype.setItem = function (value) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
localStorage.setItem(this.name, JSON.stringify(value));
return [2 /*return*/];
});
});
};
LocalStorageAdapter.prototype.removeItem = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
localStorage.removeItem(this.name);
return [2 /*return*/];
});
});
};
LocalStorageAdapter.prototype.destroy = function () {
this.removeItem();
};
LocalStorageAdapter.prototype.close = function () {
// LocalStorage 不需要特殊关闭
};
return LocalStorageAdapter;
}());
/**
* Echo 状态管理类
* 一个轻量级的状态管理库,支持多种存储模式和状态管理功能
*
* 特性:
* - 支持多种存储模式(临时、LocalStorage、IndexedDB)
* - 支持跨窗口状态同步
* - 支持 React Hooks 集成
* - 支持状态订阅
* - 支持选择器
*/
var Echo = /** @class */ (function () {
function Echo(defaultState) {
this.defaultState = defaultState;
/** 是否已经完成初始化 */
this.isInitialized = false;
/** 监听器集合 */
this.listeners = new Set();
/** 存储适配器 */
this.storageAdapter = null;
/** 跨窗口同步通道 */
this.syncChannel = null;
/** 是否正在恢复状态 */
this.isHydrating = false;
/** 用于 React Hooks 的 hook 函数 */
this.hookRef = null;
// 确保类型安全,处理null情况
if (defaultState === null) {
this.state = null;
}
else if (typeof defaultState === "object" && defaultState !== null) {
this.state = __assign({}, defaultState);
}
else {
this.state = defaultState;
}
this.readyPromise = Promise.resolve();
this.hookRef = this.createHook();
}
Echo.prototype.hydrate = function () {
return __awaiter(this, void 0, void 0, function () {
var savedState, error_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!this.storageAdapter)
return [2 /*return*/];
_a.label = 1;
case 1:
_a.trys.push([1, 6, , 7]);
return [4 /*yield*/, this.storageAdapter.getItem()];
case 2:
savedState = _a.sent();
if (!savedState) return [3 /*break*/, 3];
this.isHydrating = true;
this.set(savedState);
this.isHydrating = false;
return [3 /*break*/, 5];
case 3:
if (this.defaultState === null) {
this.state = null;
}
else if (typeof this.defaultState === "object" &&
this.defaultState !== null) {
this.state = __assign({}, this.defaultState);
}
else {
this.state = this.defaultState;
}
return [4 /*yield*/, this.storageAdapter.setItem(this.state)];
case 4:
_a.sent();
_a.label = 5;
case 5:
this.isInitialized = true;
return [3 /*break*/, 7];
case 6:
error_1 = _a.sent();
console.error("Echo Core: 状态恢复失败", error_1);
return [3 /*break*/, 7];
case 7: return [2 /*return*/];
}
});
});
};
Echo.prototype.getDatabaseName = function () {
if (!this.storageAdapter) {
throw new Error("Echo Core: 请先设置存储模式");
}
if (!(this.storageAdapter instanceof IndexedDBAdapter)) {
throw new Error("Echo Core: getDatabaseName 方法仅限于 IndexedDB 方案使用");
}
return this.storageAdapter.getDatabaseName();
};
Echo.prototype.initSync = function (name) {
var _this = this;
try {
this.syncChannel = new BroadcastChannel("echo-".concat(name));
this.syncChannel.onmessage = function (event) { return __awaiter(_this, void 0, void 0, function () {
var newState;
var _a, _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
if (!(((_a = event.data) === null || _a === void 0 ? void 0 : _a.type) === "state-update")) return [3 /*break*/, 3];
this.set(event.data.state, { isFromSync: true, replace: true });
if (!this.storageAdapter) return [3 /*break*/, 2];
return [4 /*yield*/, this.storageAdapter.setItem(event.data.state)];
case 1:
_c.sent();
_c.label = 2;
case 2: return [3 /*break*/, 5];
case 3:
if (!(((_b = event.data) === null || _b === void 0 ? void 0 : _b.type) === "state-delete")) return [3 /*break*/, 5];
// 使用类型安全的方式处理状态删除
if (typeof this.state === "object" && this.state !== null) {
newState = __assign({}, this.state);
if (newState && typeof newState === "object") {
delete newState[event.data.key];
this.set(newState, { isFromSync: true, replace: true });
}
}
else if (typeof this.state === "string") {
this.set("", { isFromSync: true, replace: true });
}
else if (typeof this.state === "number") {
this.set(-1, { isFromSync: true, replace: true });
}
if (!this.storageAdapter) return [3 /*break*/, 5];
return [4 /*yield*/, this.storageAdapter.setItem(this.state)];
case 4:
_c.sent();
_c.label = 5;
case 5: return [2 /*return*/];
}
});
}); };
}
catch (error) {
console.warn("Echo Core: 跨窗口同步初始化失败", error);
}
};
// 辅助方法,根据类型返回对应的空值
Echo.prototype.getEmptyValueForType = function (value) {
if (typeof value === "string") {
return "";
}
if (typeof value === "number") {
return -1;
}
return value;
};
Echo.prototype.set = function (nextState, options) {
var _this = this;
if (options === void 0) { options = {}; }
var oldState = this.state;
// 处理函数式更新
var newState = typeof nextState === "function"
? nextState(this.state)
: nextState;
// 处理null情况
var finalState;
if (options.replace) {
finalState = newState;
}
else if (this.state === null) {
finalState = newState;
}
else if (typeof this.state === "object" && this.state !== null) {
finalState = __assign(__assign({}, this.state), newState);
}
else {
finalState = newState;
}
var hasChanged = !this.isEqual(oldState, finalState);
if (!hasChanged)
return;
this.state = finalState;
if (!this.isHydrating && this.storageAdapter) {
this.storageAdapter.setItem(this.state).catch(function (error) {
console.error("Echo Core: 状态保存失败", error);
});
}
if (this.syncChannel && !options.isFromSync && !this.isHydrating) {
this.syncChannel.postMessage({
type: "state-update",
state: this.state,
});
}
this.listeners.forEach(function (listener) { return listener(_this.state); });
};
Echo.prototype.isEqual = function (obj1, obj2) {
var _this = this;
// 处理相同引用
if (obj1 === obj2)
return true;
// 处理null或非对象情况
if (obj1 === null && obj2 === null)
return true;
if (obj1 === null || obj2 === null)
return false;
if (typeof obj1 !== "object" || typeof obj2 !== "object")
return false;
var keys1 = Object.keys(obj1);
var keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length)
return false;
return keys1.every(function (key) { return keys2.includes(key) && _this.isEqual(obj1[key], obj2[key]); });
};
Echo.prototype.delete = function (key) {
var _this = this;
var oldState = this.state;
// 如果状态为null,直接返回
if (this.state === null)
return;
if (typeof this.state === "object" && this.state !== null) {
var newState = __assign({}, this.state);
delete newState[key];
this.state = newState;
}
else if (typeof this.state === "string" ||
typeof this.state === "number") {
this.state = this.getEmptyValueForType(this.state);
}
var hasChanged = !this.isEqual(oldState, this.state);
if (!hasChanged)
return;
if (!this.isHydrating && this.storageAdapter) {
this.storageAdapter.setItem(this.state).catch(function (error) {
console.error("Echo Core: 状态保存失败", error);
});
}
if (this.syncChannel && !this.isHydrating) {
this.syncChannel.postMessage({
type: "state-delete",
key: key,
});
}
this.listeners.forEach(function (listener) { return listener(_this.state); });
};
Echo.prototype.ready = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, this.readyPromise];
});
});
};
Echo.prototype.getCurrent = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.ready()];
case 1:
_a.sent();
return [2 /*return*/, this.state];
}
});
});
};
Object.defineProperty(Echo.prototype, "current", {
get: function () {
// 只有在使用IndexedDB且未初始化时才抛出错误
if (this.storageAdapter instanceof IndexedDBAdapter &&
!this.isInitialized) {
throw new Error("Echo Core: 请使用 getCurrent() 方法或等待 ready() Promise 完成");
}
return this.state;
},
enumerable: false,
configurable: true
});
Echo.prototype.reset = function () {
this.set(this.defaultState, { replace: true });
};
Echo.prototype.subscribe = function (listener) {
var _this = this;
this.listeners.add(listener);
return function () {
_this.listeners.delete(listener);
};
};
Echo.prototype.addListener = function (listener) {
this.listeners.add(listener);
};
Echo.prototype.removeListener = function (listener) {
this.listeners.delete(listener);
};
Echo.prototype.createHook = function () {
var self = this;
return function useEchoCore(selector) {
var _a = __read(react.useState(self.isInitialized ? self.state : null), 2), state = _a[0], setState = _a[1];
var _b = __read(react.useState({}), 2), forceUpdate = _b[1];
react.useEffect(function () {
// 每次组件挂载或重新渲染时,检查初始化状态
var isMounted = true;
// 立即设置当前状态(如果已初始化)
if (self.isInitialized) {
setState(self.state);
}
// 无论如何都等待ready完成,以处理可能的存储模式切换
self.ready().then(function () {
if (isMounted) {
setState(self.state);
forceUpdate({});
}
});
return function () {
isMounted = false;
};
}, []);
react.useEffect(function () {
var listener = function () {
setState(self.state);
forceUpdate({});
};
self.addListener(listener);
return function () {
self.removeListener(listener);
};
}, []);
if (state === null) {
return selector
? selector(self.defaultState)
: self.defaultState;
}
return selector ? selector(state) : state;
};
};
Echo.prototype.use = function (selector) {
if (!this.hookRef) {
throw new Error("Hook 未初始化");
}
return this.hookRef(selector);
};
/**
* 切换存储键名(仅限于 IndexedDB 方案使用)
* @param name 新的存储键名
* @returns 当前实例,用于链式调用
*/
Echo.prototype.switch = function (name) {
var _this = this;
if (!this.storageAdapter) {
throw new Error("Echo Core: 请先设置存储模式");
}
// 仅限于 IndexedDB 方案使用
if (!(this.storageAdapter instanceof IndexedDBAdapter)) {
throw new Error("Echo Core: switch 方法仅限于 IndexedDB 方案使用");
}
// 获取当前配置
var hasSync = !!this.syncChannel;
// 保存当前数据库和对象仓库名称
var database = this.storageAdapter.getDatabaseName();
var object = this.storageAdapter.getObjectStoreName();
// 清理当前资源
this.cleanup();
// 使用新配置重新初始化,保持相同的数据库和对象仓库
this.storageAdapter = new IndexedDBAdapter({
name: name,
database: database,
object: object,
sync: hasSync,
});
// 使用标准的 hydrate 方法,它会在没有持久化值时使用默认状态
var hydratePromise = this.hydrate();
this.readyPromise = hydratePromise;
// 如果之前有同步,重新初始化同步
if (hasSync) {
this.initSync(name);
}
// 确保在hydrate完成后通知所有监听器,与indexed()方法行为保持一致
hydratePromise
.then(function () {
if (_this.isInitialized) {
_this.listeners.forEach(function (listener) { return listener(_this.state); });
}
})
.catch(function (error) {
console.error("Echo Core: 切换存储键名失败", error);
});
return this;
};
/**
* 使用 LocalStorage 模式
* @param config 存储配置
*/
Echo.prototype.localStorage = function (config) {
this.cleanup();
this.storageAdapter = new LocalStorageAdapter(config);
this.readyPromise = this.hydrate();
if (config.sync) {
this.initSync(config.name);
}
return this;
};
/**
* 使用 IndexedDB 模式
* @param config IndexedDB 配置
*/
Echo.prototype.indexed = function (config) {
var _this = this;
this.cleanup();
this.storageAdapter = new IndexedDBAdapter(config);
// 保存当前Promise以便可以等待它完成
var hydratePromise = this.hydrate();
this.readyPromise = hydratePromise;
if (config.sync) {
this.initSync(config.name);
}
// 确保在hydrate完成后通知所有监听器
hydratePromise
.then(function () {
// 只有在初始化完成后才通知监听器
if (_this.isInitialized) {
_this.listeners.forEach(function (listener) { return listener(_this.state); });
}
})
.catch(function (error) {
console.error("Echo Core: 数据库初始化失败", error);
});
return this;
};
/**
* 使用临时存储模式(不持久化)
*/
Echo.prototype.temporary = function () {
this.cleanup();
this.readyPromise = Promise.resolve();
this.isInitialized = true;
return this;
};
/**
* 清理资源,
* 持久化数据不会消失
*/
Echo.prototype.cleanup = function () {
var _a, _b;
(_a = this.syncChannel) === null || _a === void 0 ? void 0 : _a.close();
this.syncChannel = null;
(_b = this.storageAdapter) === null || _b === void 0 ? void 0 : _b.close();
this.storageAdapter = null;
this.isInitialized = false;
};
/**
* 销毁实例,
* 持久化数据也会消失
*/
Echo.prototype.destroy = function () {
var _a;
this.cleanup();
(_a = this.storageAdapter) === null || _a === void 0 ? void 0 : _a.destroy();
};
return Echo;
}());
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var charsLength = chars.length;
/**
* 生成一个唯一的ID
* @returns 16位唯一ID,前8位基于时间戳,后8位基于密码学安全的随机数,包含大小写字母和数字
*/
var gen = {
id: function () {
var timestamp = Date.now();
// 优化时间戳部分的生成
var timeArray = new Uint8Array(8);
for (var i = 0; i < 8; i++) {
timeArray[i] = ((timestamp >> (i * 4)) ^ (timestamp >> (i * 2))) & 0x3f;
}
// 生成随机部分
var randomArray = new Uint8Array(8);
crypto.getRandomValues(randomArray);
// 合并并转换为字符
return Array.from(__spreadArray(__spreadArray([], __read$1(randomArray), false), __read$1(timeArray), false), function (byte) { return chars[byte % charsLength]; }).join("");
},
};
// Zen类 - 表示任务中的单个执行步骤
var Zen = /** @class */ (function () {
/**
* 创建一个新的执行步骤
* @param id - 步骤唯一标识
* @param name - 步骤名称
* @param executor - 步骤执行器函数
* @param task - 所属的 Task 实例
* @param config - 步骤配置
*/
function Zen(name, // 步骤名称
task // 所属任务实例
) {
var _this = this;
this.name = name;
this.task = task;
this.status = "pending"; // 步骤状态
this.dependencies = new Set(); // 依赖的其他步骤ID集合
this.cleanupFunctions = []; // 清理函数数组
this.executor = function () {
return Promise.resolve({});
}; // 步骤执行器
this.config = {}; // 步骤配置
// 获取步骤信息的方法
this.getId = function () { return _this.id; }; // 获取步骤ID
this.getName = function () { return _this.name; }; // 获取步骤名称
this.getStatus = function () { return _this.status; }; // 获取步骤状态
this.getResult = function () { return _this.result; }; // 获取步骤结果
this.getError = function () { return _this.error; }; // 获取错误信息
this.getDependencies = function () { return Array.from(_this.dependencies); }; // 获取依赖列表
this.getStartTime = function () { return _this.startTime; }; // 获取开始时间
this.getEndTime = function () { return _this.endTime; }; // 获取结束时间
this.id = gen.id();
this.name = name;
this.task = task;
}
Object.defineProperty(Zen.prototype, "result", {
// 获取步骤执行结果 - 只有在完成状态才返回
get: function () {
if (this.status !== "completed")
return undefined;
return this.value;
},
enumerable: false,
configurable: true
});
/**
* 设置当前步骤依赖的其他步骤
* @param zens - 依赖的步骤数组
* @returns this - 返回当前实例以支持链式调用
*/
Zen.prototype.after = function () {
var _this = this;
var zens = [];
for (var _i = 0; _i < arguments.length; _i++) {
zens[_i] = arguments[_i];
}
zens.forEach(function (zen) { return _this.dependencies.add(zen.getId()); });
return this;
};
/**
* 设置取消回调函数
* @param callback - 取消回调函数
* @returns this - 返回当前实例以支持链式调用
*/
Zen.prototype.cancel = function (callback) {
this.config.onCancel = callback;
return this;
};
Zen.prototype.exe = function (executor) {
this.executor = executor;
return this;
};
/**
* 添加清理函数
* @param cleanup - 清理函数
*/
Zen.prototype.addCleanup = function (cleanup) {
this.cleanupFunctions.push(cleanup);
};
/**
* 执行清理函数
*/
Zen.prototype.executeCleanup = function () {
var _this = this;
this.cleanupFunctions.forEach(function (cleanup) {
try {
cleanup();
}
catch (error) {
console.error("Error during cleanup for zen ".concat(_this.name, ":"), error);
}
});
this.cleanupFunctions = [];
};
/**
* 包装依赖结果为ZenInput
* @param depResults - 依赖步骤的执行结果
* @returns ZenInput - 包装后的输入对象
*/
Zen.prototype.wrapDependencyResults = function (depResults) {
return {
get: function (step) {
return depResults[step.getId()];
},
getById: function (stepId) {
return depResults[stepId];
},
getRaw: function () {
return depResults;
},
};
};
/**
* 内部执行方法
* @param signal - 中断信号
* @returns Promise<TOutput> - 执行结果
* @private
*/
Zen.prototype._execute = function (signal) {
return __awaiter$1(this, void 0, void 0, function () {
var dependencyResults, error_1, zenInput, result, error_2, error_3;
return __generator$1(this, function (_a) {
switch (_a.label) {
case 0:
// 检查是否正在运行
if (this.status === "running") {
throw new Error("Zen ".concat(this.name, " is already running"));
}
// 检查任务是否已被取消
if (signal.aborted) {
this.status = "cancelled";
throw new Error("Task cancelled before execution");
}
_a.label = 1;
case 1:
_a.trys.push([1, 15, 17, 18]);
// 设置状态为正在执行
this.status = "running";
this.startTime = Date.now();
this.endTime = undefined;
this.error = undefined;
dependencyResults = void 0;
_a.label = 2;
case 2:
_a.trys.push([2, 4, , 5]);
return [4 /*yield*/, this.waitForDependencies()];
case 3:
dependencyResults = _a.sent();
return [3 /*break*/, 5];
case 4:
error_1 = _a.sent();
this.status = "failed";
this.error =
error_1 instanceof Error
? error_1
: new Error("Failed to resolve dependencies: ".concat(String(error_1)));
this.endTime = Date.now();
throw this.error;
case 5:
zenInput = this.wrapDependencyResults(dependencyResults);
result = void 0;
_a.label = 6;
case 6:
_a.trys.push([6, 13, , 14]);
if (!this.config.retry) return [3 /*break*/, 8];
return [4 /*yield*/, this.executeWithRetry(zenInput, signal, this.config.retry)];
case 7:
result = _a.sent();
return [3 /*break*/, 12];
case 8:
if (!(this.config.timeout && this.config.timeout > 0)) return [3 /*break*/, 10];
return [4 /*yield*/, this.executeWithTimeout(zenInput, signal)];
case 9:
result = _a.sent();
return [3 /*break*/, 12];
case 10: return [4 /*yield*/, this.executeCore(zenInput, signal)];
case 11:
result = _a.sent();
_a.label = 12;
case 12: return [3 /*break*/, 14];
case 13:
error_2 = _a.sent();
// 记录详细错误
console.error("\u6267\u884CZen\u6B65\u9AA4 ".concat(this.name, " (").concat(this.id, ") \u5931\u8D25:"), error_2);
throw error_2;
case 14:
// 更新状态和结果
this.status = "completed";
this.value = result;
this.endTime = Date.now();
return [2 /*return*/, result];
case 15:
error_3 = _a.sent();
// 处理执行错误
this.endTime = Date.now();
return [4 /*yield*/, this.handleZenError(error_3)];
case 16:
_a.sent();
throw error_3 instanceof Error ? error_3 : new Error(String(error_3));
case 17:
// 清理临时资源
this.executeCleanup();
return [7 /*endfinally*/];
case 18: return [2 /*return*/];
}
});
});
};
/**
* 核心执行逻辑
* @param zenInput - 输入参数,包含依赖结果
* @param signal - 中断信号
* @returns Promise<TOutput> - 执行结果
* @private
*/
Zen.prototype.executeCore = function (zenInput, signal) {
return __awaiter$1(this, void 0, void 0, function () {
var abortController, wrappedExecutor, result, error_4;
var _this = this;
return __generator$1(this, function (_a) {
switch (_a.label) {
case 0:
abortController = new AbortController();
_a.label = 1;
case 1:
_a.trys.push([1, 3, 4, 5]);
// 如果已经取消,直接返回取消状态
if (signal.aborted || this.status === "cancelled") {
throw new Error("Task cancelled");
}
wrappedExecutor = function () { return __awaiter$1(_this, void 0, void 0, function () {
var _this = this;
return __generator$1(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, new Promise(function (resolve, reject) {
// 设置清理函数
var abortHandler = function () {
if (_this.status !== "cancelled") {
_this.status = "cancelled";
}
reject(new Error("Task cancelled"));
};
// 监听取消信号
signal.addEventListener("abort", abortHandler);
_this.addCleanup(function () {
return signal.removeEventListener("abort", abortHandler);
});
// 执行实际的任务
_this.executor(zenInput)
.then(resolve)
.catch(reject);
})];
case 1: return [2 /*return*/, _a.sent()];
}
});
}); };
return [4 /*yield*/, wrappedExecutor()];
case 2:
result = _a.sent();
// 设置执行结果和状态
this.value = result;
this.status = "completed";
return [2 /*return*/, result];
case 3:
error_4 = _a.sent();
if (error_4 instanceof Error && error_4.message === "Task cancelled") {
this.status = "cancelled";
}
throw error_4;
case 4:
abortController.abort();
return [7 /*endfinally*/];
case 5: return [2 /*return*/];
}
});
});
};
/**
* 重试执行逻辑
* @param zenInput - 输入参数
* @param signal - 中断信号
* @param config - 重试配置
* @returns Promise<TOutput> - 执行结果
*/
Zen.prototype.executeWithRetry = function (zenInput, signal, config) {
return __awaiter$1(this, void 0, void 0, function () {
var retryConfig, lastError, isTaskCancelled, _loop_1, this_1, attempt, state_1;
var _this = this;
return __generator$1(this, function (_a) {
switch (_a.label) {
case 0:
retryConfig = {
maxAttempts: Math.max(1, config.maxAttempts || 3),
initialDelay: Math.max(0, config.initialDelay || 1000),
backoffFactor: Math.max(1, config.backoffFactor || 2),
maxDelay: Math.max(0, config.maxDelay || 30000),
};
isTaskCancelled = false;
_loop_1 = function (attempt) {
var _b, error_5, delay_1;
return __generator$1(this, function (_c) {
switch (_c.label) {
case 0:
// 检查是否已取消
if (signal.aborted) {
isTaskCancelled = true;
throw new Error("Task cancelled during retry");
}
_c.label = 1;
case 1:
_c.trys.push([1, 3, , 5]);
// 记录重试尝试
if (attempt > 1) {
console.log("Zen ".concat(this_1.name, " (").concat(this_1.id, "): \u7B2C ").concat(attempt, "/").concat(retryConfig.maxAttempts, " \u6B21\u91CD\u8BD5"));
}
_b = {};
return [4 /*yield*/, this_1.executeCore(zenInput, signal)];
case 2: return [2 /*return*/, (_b.value = _c.sent(), _b)];
case 3:
error_5 = _c.sent();
lastError = error_5 instanceof Error ? error_5 : new Error(String(error_5));
// 检查是否任务被取消,如果已取消则不再重试
if (error_5 instanceof Error &&
(error_5.message === "Task cancelled" ||
error_5.message === "Task cancelled before execution")) {
isTaskCancelled = true;
return [2 /*return*/, "break"];
}
// 判断是否已达到最大重试次数
if (attempt === retryConfig.maxAttempts) {
console.error("Zen ".concat(this_1.name, " (").concat(this_1.id, "): \u5DF2\u8FBE\u5230\u6700\u5927\u91CD\u8BD5\u6B21\u6570 (").concat(retryConfig.maxAttempts, ")\uFF0C\u4E0D\u518D\u91CD\u8BD5"));
return [2 /*return*/, "break"];
}
delay_1 = Math.min(retryConfig.initialDelay *
Math.pow(retryConfig.backoffFactor, attempt - 1), retryConfig.maxDelay);
// 发出重试事件
try {
this_1.task.emit({