zs-control
Version:
State management inspired by Zustand with strong TypeScript typing.
217 lines (190 loc) • 6.1 kB
text/typescript
import { jwtDecode } from "jwt-decode";
import { useEffect, useState } from "react";
import { ZObservability, ZObservabilityConfig } from "./obs/interfaces";
import { Logger } from "./obs/class/logger";
import { Metrics } from "./obs/class/metrics";
import { Tracer } from "./obs/class/tracer";
import { pipe, compose, memoize, once } from "./functions";
import { day, clock } from "./date";
import {
ZsControl,
ZsControlConfig,
TempConfig,
TempState,
EventChannel,
ZStorageConfig,
} from "./interfaces";
import { StorageType } from "./types";
import jwt from "jsonwebtoken";
export const z: ZsControl = {
createStateManagement<T>({ state, set }: ZsControlConfig<T>) {
let globalState = state(); // Estado inicial
const listeners: Array<(state: T) => void> = []; // Lista de ouvintes
const updateState = (newState: Partial<T>) => {
globalState = { ...globalState, ...newState };
listeners.forEach((listener) => listener(globalState));
};
const setFunctions = set ? set(updateState) : {};
const useStateManagement = () => {
const [localState, setLocalState] = useState(globalState);
useEffect(() => {
const listener = (updatedState: T) => {
setLocalState(updatedState);
};
listeners.push(listener);
return () => {
const index = listeners.indexOf(listener);
if (index > -1) listeners.splice(index, 1);
};
}, []);
return {
...localState,
...setFunctions,
};
};
return useStateManagement;
},
temp: <T>({ value, watch, timeDestory = 0 }: TempConfig<T>): TempState<T> => {
const [tempValue, setTempValue] = useState<T>(value);
const [resetTrigger, setResetTrigger] = useState(0);
const addValue = (add: T): T => {
const newValue = (tempValue as any) + add;
setTempValue(newValue);
if (watch()) {
destroy();
}
return newValue;
};
const destroy = () => {
setTempValue(value);
setResetTrigger((prev) => prev + 1);
};
useEffect(() => {
if (timeDestory > 0) {
const timer = setTimeout(() => {
destroy();
}, timeDestory);
return () => clearTimeout(timer);
}
}, [timeDestory, resetTrigger]);
return {
value: tempValue,
addValue,
};
},
createEventChannel<T>(): EventChannel<T> {
const subscribers: Set<(data: T) => void> = new Set();
return {
subscribe: (callback: (data: T) => void) => {
subscribers.add(callback);
},
unsubscribe: (callback: (data: T) => void) => {
subscribers.delete(callback);
},
publish: (data: T) => {
subscribers.forEach((callback) => callback(data));
},
};
},
pipe,
compose,
memoize,
once,
day: {
format: (formatString: string) => day().format(formatString),
},
clock,
};
interface ZStorageInstance<T> {
key: (key: string) => ZStorageInstance<T>;
config: (config: ZStorageConfig) => ZStorageInstance<T>;
addValueInKey: (value: Partial<T>) => void;
destroy: () => void;
jwtDecodeKey: () => { decode: any; old: any };
generateToken: (
payload: object,
secretKey: string,
expiresIn: string
) => string;
}
export const zStorage = {
setHook<T>(hook: () => T): ZStorageInstance<T> {
let storageKey = "";
let config: ZStorageConfig = { typeStorage: "localStorage" };
return {
key(key: string) {
storageKey = key;
return this;
},
config(newConfig: ZStorageConfig) {
config = { ...config, ...newConfig };
return this;
},
addValueInKey(value: Partial<T>) {
const storage = getStorage(config.typeStorage);
const existingValue = storage.getItem(storageKey);
const mergedValue = { ...JSON.parse(existingValue || "{}"), ...value };
storage.setItem(storageKey, JSON.stringify(mergedValue));
},
destroy() {
const storage = getStorage(config.typeStorage);
storage.removeItem(storageKey);
},
generateToken(
payload: object,
secretKey: string,
expiresIn: string = "1h"
) {
const token = jwt.sign(payload, secretKey, { expiresIn });
return token;
},
jwtDecodeKey() {
const storage = getStorage(config.typeStorage);
const storedValue = storage.getItem(storageKey);
if (!storedValue) {
return { decode: null, old: null };
}
try {
const decoded = jwtDecode(storedValue);
return { decode: decoded, old: storedValue };
} catch (error) {
console.error("Error decoding JWT:", error);
return { decode: null, old: storedValue };
}
},
};
function getStorage(type: StorageType) {
if (type === "localStorage") return window.localStorage;
if (type === "cookieStorage") return createCookieStorage();
if (type === "passwordStorage") throw new Error("Not implemented");
throw new Error("Invalid storage type");
}
function createCookieStorage() {
return {
getItem: (key: string) =>
document.cookie
.split("; ")
.find((row) => row.startsWith(key))
?.split("=")[1],
setItem: (key: string, value: string) => {
document.cookie = `${key}=${value}; path=/`;
},
removeItem: (key: string) => {
document.cookie = `${key}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
},
};
}
},
};
export const zObservability = {
create(config: ZObservabilityConfig): ZObservability {
const logger = new Logger(config.serviceName);
const metrics = new Metrics();
const tracer = new Tracer();
return {
logger,
metrics,
tracer,
};
},
};