synapse-storage
Version:
Набор инструментов для управления состоянием и апи-запросами
250 lines (245 loc) • 8.92 kB
JavaScript
import { handleOperationError } from "../../../_utils/error-handling.util.js";
/**
* Sentinel object returned by middleware to signal that the value has not changed.
* BaseStorage checks for this by reference equality to skip subscriber notifications.
*/ const VALUE_NOT_CHANGED = Symbol('VALUE_NOT_CHANGED');
// ─── Async Middleware Module ───────────────────────────────────────────────────
class AsyncMiddlewareModule {
middlewares = [];
api;
initialized = false;
dispatchFn;
constructor(storage){
this.api = {
dispatch: async (action)=>this.dispatch(action),
getState: ()=>storage.getState(),
storage: {
doGet: storage.doGet.bind(storage),
doSet: storage.doSet.bind(storage),
doUpdate: storage.doUpdate.bind(storage),
doDelete: storage.doDelete.bind(storage),
doClear: storage.doClear.bind(storage),
doKeys: storage.doKeys.bind(storage),
notifySubscribers: storage.notifySubscribers.bind(storage)
}
};
}
async baseOperation(action) {
switch(action.type){
case 'get':
{
return this.api.storage.doGet(action.key);
}
case 'set':
{
await this.api.storage.doSet(action.key, action.value);
return this.api.storage.doGet(action.key);
}
case 'update':
{
if (Array.isArray(action.value)) {
await this.api.storage.doUpdate(action.value);
return this.api.storage.doGet('');
}
return action.value;
}
case 'delete':
{
return this.api.storage.doDelete(action.key);
}
case 'clear':
{
return this.api.storage.doClear();
}
case 'reset':
{
if (action.value) {
await this.api.storage.doClear();
await this.api.storage.doSet('', action.value);
return this.api.storage.doGet('');
}
return this.api.storage.doClear();
}
case 'init':
{
const currentState = await this.api.storage.doGet('');
if (Object.keys(currentState || {}).length > 0) {
return currentState;
}
if (action.value) {
await this.api.storage.doSet('', action.value);
return this.api.storage.doGet('');
}
return currentState;
}
case 'keys':
{
return this.api.storage.doKeys();
}
default:
{
throw new Error(`Unknown action type: ${action.type}`);
}
}
}
initializeMiddlewares() {
if (this.initialized) return;
let chain = this.baseOperation.bind(this);
for (const middleware of [
...this.middlewares
].reverse()){
const nextChain = chain;
chain = async (action)=>{
const actionWithMeta = {
...action,
metadata: {
...action.metadata,
timestamp: action.metadata?.timestamp || Date.now()
}
};
return middleware.reducer(this.api)(nextChain)(actionWithMeta);
};
}
this.dispatchFn = chain;
this.initialized = true;
}
use(middleware) {
if (middleware.setup) {
middleware.setup(this.api);
}
this.middlewares.push(middleware);
this.initialized = false;
}
async dispatch(action) {
if (!this.initialized) {
this.initializeMiddlewares();
}
try {
return await this.dispatchFn(action);
} catch (error) {
handleOperationError('AsyncMiddlewareModule: error in middleware chain', error);
}
}
}
/** @deprecated Use AsyncMiddlewareModule */ class MiddlewareModule extends AsyncMiddlewareModule {
}
// ─── Sync Middleware Module ────────────────────────────────────────────────────
class SyncMiddlewareModule {
middlewares = [];
api;
initialized = false;
dispatchFn;
constructor(storage){
this.api = {
dispatch: (action)=>this.dispatch(action),
getState: ()=>storage.getState(),
storage: {
doGet: storage.doGet.bind(storage),
doSet: storage.doSet.bind(storage),
doUpdate: storage.doUpdate.bind(storage),
doRemove: storage.doRemove.bind(storage),
doClear: storage.doClear.bind(storage),
doKeys: storage.doKeys.bind(storage),
notifySubscribers: storage.notifySubscribers.bind(storage)
}
};
}
baseOperation(action) {
switch(action.type){
case 'get':
{
return this.api.storage.doGet(action.key);
}
case 'set':
{
this.api.storage.doSet(action.key, action.value);
return this.api.storage.doGet(action.key);
}
case 'update':
{
if (Array.isArray(action.value)) {
this.api.storage.doUpdate(action.value);
return this.api.storage.doGet('');
}
return action.value;
}
case 'delete':
{
return this.api.storage.doRemove(action.key);
}
case 'clear':
{
return this.api.storage.doClear();
}
case 'reset':
{
if (action.value) {
this.api.storage.doClear();
this.api.storage.doSet('', action.value);
return this.api.storage.doGet('');
}
return this.api.storage.doClear();
}
case 'init':
{
const currentState = this.api.storage.doGet('');
if (Object.keys(currentState || {}).length > 0) {
return currentState;
}
if (action.value) {
this.api.storage.doSet('', action.value);
return this.api.storage.doGet('');
}
return currentState;
}
case 'keys':
{
return this.api.storage.doKeys();
}
default:
{
throw new Error(`Unknown action type: ${action.type}`);
}
}
}
initializeMiddlewares() {
if (this.initialized) return;
let chain = this.baseOperation.bind(this);
for (const middleware of [
...this.middlewares
].reverse()){
const nextChain = chain;
chain = (action)=>{
const actionWithMeta = {
...action,
metadata: {
...action.metadata,
timestamp: action.metadata?.timestamp || Date.now()
}
};
return middleware.reducer(this.api)(nextChain)(actionWithMeta);
};
}
this.dispatchFn = chain;
this.initialized = true;
}
use(middleware) {
if (middleware.setup) {
middleware.setup(this.api);
}
this.middlewares.push(middleware);
this.initialized = false;
}
dispatch(action) {
if (!this.initialized) {
this.initializeMiddlewares();
}
try {
return this.dispatchFn(action);
} catch (error) {
handleOperationError('SyncMiddlewareModule: error in middleware chain', error);
}
}
}
export { AsyncMiddlewareModule, MiddlewareModule, SyncMiddlewareModule, VALUE_NOT_CHANGED };
//# sourceMappingURL=middleware-module.js.map