chore: init read-star monorepo

This commit is contained in:
2026-01-16 13:06:44 +08:00
commit 1e510efe8e
508 changed files with 44803 additions and 0 deletions

View File

@ -0,0 +1,28 @@
import CryptoJS from 'crypto-js'
export class Crypto<T extends object> {
/** Secret */
secret: string
constructor(secret: string) {
this.secret = secret
}
encrypt(data: T): string {
const dataString = JSON.stringify(data)
const encrypted = CryptoJS.AES.encrypt(dataString, this.secret)
return encrypted.toString()
}
decrypt(encrypted: string) {
const decrypted = CryptoJS.AES.decrypt(encrypted, this.secret)
const dataString = decrypted.toString(CryptoJS.enc.Utf8)
try {
return JSON.parse(dataString) as T
}
catch {
// avoid parse error
return null
}
}
}

View File

@ -0,0 +1,4 @@
export * from './crypto'
export * from './klona'
export * from './nanoid'
export * from './storage'

View File

@ -0,0 +1,3 @@
import { klona as jsonClone } from 'klona/json'
export { jsonClone }

View File

@ -0,0 +1,3 @@
import { nanoid } from 'nanoid'
export { nanoid }

View File

@ -0,0 +1,78 @@
import localforage from 'localforage'
/** The storage type */
export type StorageType = 'local' | 'session'
export function createStorage<T extends object>(type: StorageType, storagePrefix: string) {
const stg = type === 'session' ? window.sessionStorage : window.localStorage
const storage = {
/**
* Set session
*
* @param key Session key
* @param value Session value
*/
set<K extends keyof T>(key: K, value: T[K]) {
const json = JSON.stringify(value)
stg.setItem(`${storagePrefix}${key as string}`, json)
},
/**
* Get session
*
* @param key Session key
*/
get<K extends keyof T>(key: K): T[K] | null {
const json = stg.getItem(`${storagePrefix}${key as string}`)
if (json) {
let storageData: T[K] | null = null
try {
storageData = JSON.parse(json)
}
catch {}
// storageData may be `false` if it is boolean type
if (storageData !== null) {
return storageData as T[K]
}
}
stg.removeItem(`${storagePrefix}${key as string}`)
return null
},
remove(key: keyof T) {
stg.removeItem(`${storagePrefix}${key as string}`)
},
clear() {
stg.clear()
},
}
return storage
}
type LocalForage<T extends object> = Omit<typeof localforage, 'getItem' | 'setItem' | 'removeItem'> & {
getItem: <K extends keyof T>(key: K, callback?: (err: any, value: T[K] | null) => void) => Promise<T[K] | null>
setItem: <K extends keyof T>(key: K, value: T[K], callback?: (err: any, value: T[K]) => void) => Promise<T[K]>
removeItem: (key: keyof T, callback?: (err: any) => void) => Promise<void>
}
type LocalforageDriver = 'local' | 'indexedDB' | 'webSQL'
export function createLocalforage<T extends object>(driver: LocalforageDriver) {
const driverMap: Record<LocalforageDriver, string> = {
local: localforage.LOCALSTORAGE,
indexedDB: localforage.INDEXEDDB,
webSQL: localforage.WEBSQL,
}
localforage.config({
driver: driverMap[driver],
})
return localforage as LocalForage<T>
}