chore: refactoring store impl

This commit is contained in:
molvqingtai 2023-12-02 04:40:06 +08:00
parent 58527eae71
commit 511338850e
15 changed files with 205 additions and 66 deletions

View file

@ -2,6 +2,6 @@
"semi": false,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 120,
"printWidth": 160,
"tailwindFunction": ["clsx"]
}

View file

@ -74,11 +74,13 @@
"remesh": "^4.2.0",
"remesh-logger": "^4.1.0",
"remesh-react": "^4.1.0",
"remesh-yjs": "^4.1.0",
"rxjs": "^7.8.1",
"sonner": "^1.2.4",
"tailwind-merge": "^2.0.0",
"type-fest": "^4.8.2",
"valibot": "^0.21.0"
"valibot": "^0.21.0",
"y-webrtc": "^10.2.6"
},
"devDependencies": {
"@commitlint/cli": "^18.4.3",

View file

@ -98,6 +98,9 @@ dependencies:
remesh-react:
specifier: ^4.1.0
version: 4.1.0(react-dom@18.2.0)(react@18.2.0)(remesh@4.2.0)(rxjs@7.8.1)
remesh-yjs:
specifier: ^4.1.0
version: 4.1.0(remesh@4.2.0)(rxjs@7.8.1)
rxjs:
specifier: ^7.8.1
version: 7.8.1
@ -113,6 +116,9 @@ dependencies:
valibot:
specifier: ^0.21.0
version: 0.21.0
y-webrtc:
specifier: ^10.2.6
version: 10.2.6(yjs@13.6.10)
devDependencies:
'@commitlint/cli':
@ -2631,7 +2637,6 @@ packages:
/base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
dev: true
/big-integer@1.6.52:
resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==}
@ -2717,7 +2722,6 @@ packages:
dependencies:
base64-js: 1.5.1
ieee754: 1.2.1
dev: true
/builtin-modules@3.3.0:
resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
@ -3505,6 +3509,10 @@ packages:
engines: {node: '>=0.12'}
dev: true
/err-code@3.0.1:
resolution: {integrity: sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==}
dev: false
/error-ex@1.3.2:
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
dependencies:
@ -4259,6 +4267,10 @@ packages:
engines: {node: '>=6.9.0'}
dev: true
/get-browser-rtc@1.1.0:
resolution: {integrity: sha512-MghbMJ61EJrRsDe7w1Bvqt3ZsBuqhce5nrn/XAwgwOXhcsz53/ltdxOse1h/8eKXj5slzxdsz56g5rzOFSGwfQ==}
dev: false
/get-caller-file@2.0.5:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
@ -4657,7 +4669,6 @@ packages:
/ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
dev: true
/ignore@5.3.0:
resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==}
@ -5075,6 +5086,10 @@ packages:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
dev: true
/isomorphic.js@0.2.5:
resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==}
dev: false
/iterator.prototype@1.1.2:
resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==}
dependencies:
@ -5227,6 +5242,14 @@ packages:
type-check: 0.4.0
dev: true
/lib0@0.2.88:
resolution: {integrity: sha512-KyroiEvCeZcZEMx5Ys+b4u4eEBbA1ch7XUaBhYpwa/nPMrzTjUhI4RfcytmQfYoTBPcdyx+FX6WFNIoNuJzJfQ==}
engines: {node: '>=16'}
hasBin: true
dependencies:
isomorphic.js: 0.2.5
dev: false
/lie@3.3.0:
resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==}
dependencies:
@ -6750,6 +6773,12 @@ packages:
resolution: {integrity: sha512-pNsHDxbGORSvuSScqNJ+3Km6QAVqk8CfsCBIEoDgpqLrkD2f3QM4I7d1ozJJ172OmIcoUcerZaNWqtLkRXTV3A==}
dev: true
/randombytes@2.1.0:
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
dependencies:
safe-buffer: 5.2.1
dev: false
/rc9@2.1.1:
resolution: {integrity: sha512-lNeOl38Ws0eNxpO3+wD1I9rkHGQyj1NU1jlzv4go2CtEnEQEUfqnIvZG7W+bC/aXdJ27n5x/yUjb6RoT9tko+Q==}
dependencies:
@ -6973,7 +7002,6 @@ packages:
inherits: 2.0.4
string_decoder: 1.3.0
util-deprecate: 1.0.2
dev: true
/readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
@ -7124,6 +7152,18 @@ packages:
use-sync-external-store: 1.2.0(react@18.2.0)
dev: false
/remesh-yjs@4.1.0(remesh@4.2.0)(rxjs@7.8.1):
resolution: {integrity: sha512-yyV1GcANEo8aqaZTYG4swVQEkKTEWd2ZTzCC/GLhFJH7BFOegBIMTEmfWDINacKWvTtb8D4Sps/eGX8TCPBhjw==}
peerDependencies:
remesh: ^4.0.0
rxjs: ^7.0.0
dependencies:
remesh: 4.2.0(rxjs@7.8.1)
rxjs: 7.8.1
tslib: 2.6.2
yjs: 13.6.10
dev: false
/remesh@4.2.0(rxjs@7.8.1):
resolution: {integrity: sha512-t2xwtFYnEwrcWddxtEb/NF7kR+x62Er52gfk+sCa4HmaQC+J5zg41pYZz6TTl4PrDghs2et1tr1dYZpbYGAu6g==}
engines: {node: '>=14.x'}
@ -7314,7 +7354,6 @@ packages:
/safe-buffer@5.2.1:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
dev: true
/safe-json-stringify@1.2.0:
resolution: {integrity: sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==}
@ -7470,6 +7509,20 @@ packages:
engines: {node: '>=14'}
dev: true
/simple-peer@9.11.1:
resolution: {integrity: sha512-D1SaWpOW8afq1CZGWB8xTfrT3FekjQmPValrqncJMX7QFl8YwhrPTZvMCANLtgBwwdS+7zURyqxDDEmY558tTw==}
dependencies:
buffer: 6.0.3
debug: 4.3.4
err-code: 3.0.1
get-browser-rtc: 1.1.0
queue-microtask: 1.2.3
randombytes: 2.1.0
readable-stream: 3.6.2
transitivePeerDependencies:
- supports-color
dev: false
/sisteransi@1.0.5:
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
dev: true
@ -7703,7 +7756,6 @@ packages:
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
dependencies:
safe-buffer: 5.2.1
dev: true
/strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
@ -8627,7 +8679,6 @@ packages:
optional: true
utf-8-validate:
optional: true
dev: true
/wxt@0.10.3(@types/node@20.10.1)(idb-keyval@6.2.1):
resolution: {integrity: sha512-2IDbcx/em7T7+f0IJN1D3Y4Hvsb34bRyOwz8nx/vTXaoysoOHG7SsR/BowTNkX0DPxUUjCdaJpzmxeWy0dHUNQ==}
@ -8710,6 +8761,35 @@ packages:
engines: {node: '>=4.0'}
dev: true
/y-protocols@1.0.6(yjs@13.6.10):
resolution: {integrity: sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q==}
engines: {node: '>=16.0.0', npm: '>=8.0.0'}
peerDependencies:
yjs: ^13.0.0
dependencies:
lib0: 0.2.88
yjs: 13.6.10
dev: false
/y-webrtc@10.2.6(yjs@13.6.10):
resolution: {integrity: sha512-1kZ4YYwksFZi8+l8mTebVX9vW6Q5MnqxMkvNU700X5dBE38usurt/JgeXSIQRpK3NwUYYb9y63Jn9FMpMH6/vA==}
engines: {node: '>=12'}
hasBin: true
peerDependencies:
yjs: ^13.6.8
dependencies:
lib0: 0.2.88
simple-peer: 9.11.1
y-protocols: 1.0.6(yjs@13.6.10)
yjs: 13.6.10
optionalDependencies:
ws: 8.14.2
transitivePeerDependencies:
- bufferutil
- supports-color
- utf-8-validate
dev: false
/y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
@ -8750,6 +8830,13 @@ packages:
yargs-parser: 21.1.1
dev: true
/yjs@13.6.10:
resolution: {integrity: sha512-1JcyQek1vaMyrDm7Fqfa+pvHg/DURSbVo4VmeN7wjnTKB/lZrfIPhdCj7d8sboK6zLfRBJXegTjc9JlaDd8/Zw==}
engines: {node: '>=16.0.0', npm: '>=8.0.0'}
dependencies:
lib0: 0.2.88
dev: false
/yocto-queue@0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}

View file

@ -4,16 +4,24 @@ import { Remesh } from 'remesh'
import { RemeshRoot } from 'remesh-react'
import { RemeshLogger } from 'remesh-logger'
import { defineContentScript, createContentScriptUi } from 'wxt/client'
import * as Y from 'yjs'
import { RemeshYjs, RemeshYjsExtern } from 'remesh-yjs'
import { WebrtcProvider } from 'y-webrtc'
import App from './App'
import { StorageIndexDBImpl } from '@/impl/Storage'
import { IndexDBStorageImpl, BrowserSyncStorageImpl } from '@/impl/Storage'
import '@/assets/styles/tailwind.css'
export default defineContentScript({
cssInjectionMode: 'ui',
matches: ['*://*.example.com/*', '*://*.google.com/*', '*://*.v2ex.com/*'],
async main(ctx) {
const doc = new Y.Doc()
// eslint-disable-next-line no-new
new WebrtcProvider(__NAME__, doc)
const store = Remesh.store({
externs: [StorageIndexDBImpl],
externs: [IndexDBStorageImpl, BrowserSyncStorageImpl, RemeshYjsExtern.impl({ doc })],
inspectors: [RemeshLogger()]
})

View file

@ -2,16 +2,21 @@ import { type ReactNode, type FC, useState, type MouseEvent, useRef } from 'reac
import { SettingsIcon, MoonIcon, SunIcon } from 'lucide-react'
import { useClickAway } from 'react-use'
import { browser } from 'wxt/browser'
import { useRemeshDomain, useRemeshQuery } from 'remesh-react'
import { Button } from '@/components/ui/Button'
import { EVENTS } from '@/constants'
import UserInfoDomain from '@/domain/UserInfo'
export interface AppButtonProps {
children?: ReactNode
}
const AppButton: FC<AppButtonProps> = ({ children }) => {
const userInfoDomain = useRemeshDomain(UserInfoDomain())
const userInfo = useRemeshQuery(userInfoDomain.query.UserInfoQuery())
console.log(userInfo)
const [open, setOpen] = useState(false)
const [isDarkMode, setIsDarkMode] = useState(window.matchMedia('(prefers-color-scheme: dark)').matches)
const menuRef = useRef<HTMLDivElement>(null)

View file

@ -1,4 +1,4 @@
import { object, string, type Output, minBytes, maxBytes, toTrimmed, union, literal, notLength } from 'valibot'
import { type Output, object, string, minBytes, maxBytes, toTrimmed, union, literal, notLength, number } from 'valibot'
import { useForm } from 'react-hook-form'
import { valibotResolver } from '@hookform/resolvers/valibot'
@ -19,24 +19,24 @@ import { Label } from '@/components/ui/Label'
// Image is encoded as base64, and the size is increased by about 33%.
const COMPRESS_SIZE = 8 * 1024 - 8 * 1024 * 0.33
const formSchema = object({
id: string(),
name: string([
toTrimmed(),
minBytes(1, 'Please enter your username.'),
maxBytes(20, 'Your username cannot exceed 20 bytes.')
]),
avatar: string([notLength(0, 'Please select your avatar.'), maxBytes(8 * 1024, 'Your avatar cannot exceed 8kb.')]),
themeMode: union([literal('system'), literal('light'), literal('dark')])
})
const defaultUserInfo: UserInfo = {
id: nanoid(),
name: '',
avatar: '',
createTime: Date.now(),
themeMode: checkSystemDarkMode() ? 'dark' : 'system'
}
const formSchema = object({
id: string(),
createTime: number(),
// Pure numeric strings will be converted to number
// Issues: https://github.com/unjs/unstorage/issues/277
name: string([toTrimmed(), minBytes(1, 'Please enter your username.'), maxBytes(20, 'Your username cannot exceed 20 bytes.')]),
avatar: string([notLength(0, 'Please select your avatar.'), maxBytes(8 * 1024, 'Your avatar cannot exceed 8kb.')]),
themeMode: union([literal('system'), literal('light'), literal('dark')], 'Please select extension theme mode.')
})
const ProfileForm = () => {
const send = useRemeshSend()
const userInfoDomain = useRemeshDomain(UserInfoDomain())
@ -73,13 +73,7 @@ const ProfileForm = () => {
render={({ field }) => (
<FormItem className="absolute left-1/2 top-0 grid -translate-x-1/2 -translate-y-1/2 justify-items-center">
<FormControl>
<AvatarSelect
compressSize={COMPRESS_SIZE}
onError={handleError}
onWarning={handleWarning}
className="shadow-lg"
{...field}
></AvatarSelect>
<AvatarSelect compressSize={COMPRESS_SIZE} onError={handleError} onWarning={handleWarning} className="shadow-lg" {...field}></AvatarSelect>
</FormControl>
<FormMessage />
</FormItem>
@ -121,9 +115,7 @@ const ProfileForm = () => {
</div>
</RadioGroup>
</FormControl>
<FormDescription>
The theme mode of the extension. If you choose the system, will follow the system theme.
</FormDescription>
<FormDescription>The theme mode of the extension. If you choose the system, will follow the system theme.</FormDescription>
<FormMessage />
</FormItem>
)}

View file

@ -4,11 +4,11 @@ import { Remesh } from 'remesh'
import { RemeshRoot } from 'remesh-react'
import { RemeshLogger } from 'remesh-logger'
import App from './App'
import { StorageBrowserSyncImpl } from '@/impl/Storage'
import { BrowserSyncStorageImpl } from '@/impl/Storage'
import '@/assets/styles/tailwind.css'
const store = Remesh.store({
externs: [StorageBrowserSyncImpl],
externs: [BrowserSyncStorageImpl],
inspectors: [RemeshLogger()]
})

View file

@ -2,12 +2,12 @@ import { Remesh } from 'remesh'
import { ListModule } from 'remesh/modules/list'
import { nanoid } from 'nanoid'
import { from, map, tap, merge } from 'rxjs'
import Storage from './externs/Storage'
import { IndexDBStorageExtern } from './externs/Storage'
const MessageListDomain = Remesh.domain({
name: 'MessageListDomain',
impl: (domain) => {
const storage = domain.getExtern(Storage)
const storage = domain.getExtern(IndexDBStorageExtern)
const storageKey = `MESSAGE_LIST` as const
const MessageListModule = ListModule<Message>(domain, {
@ -92,9 +92,7 @@ const MessageListDomain = Remesh.domain({
domain.effect({
name: 'FormStateToStorageEffect',
impl: ({ fromEvent }) => {
const changeList$ = fromEvent(ChangeListEvent).pipe(
tap(async (messages) => await storage.set<Message[]>(storageKey, messages))
)
const changeList$ = fromEvent(ChangeListEvent).pipe(tap(async (messages) => await storage.set<Message[]>(storageKey, messages)))
return merge(changeList$).pipe(map(() => null))
}
})

View file

@ -1,16 +1,17 @@
import { Remesh } from 'remesh'
import { forkJoin, from, map, merge, tap } from 'rxjs'
import Storage from './externs/Storage'
import { isEmpty } from '@/utils'
import { BrowserSyncStorageExtern } from './externs/Storage'
import { isNullish } from '@/utils'
const UserInfoDomain = Remesh.domain({
name: 'UserInfoDomain',
impl: (domain) => {
const storage = domain.getExtern(Storage)
const storage = domain.getExtern(BrowserSyncStorageExtern)
const storageKeys = {
USER_INFO_ID: 'USER_INFO_ID',
USER_INFO_NAME: 'USER_INFO_NAME',
USER_INFO_AVATAR: 'USER_INFO_AVATAR',
USER_INFO_CREATE_TIME: 'USER_INFO_CREATE_TIME',
USER_INFO_THEME_MODE: 'USER_INFO_THEME_MODE'
} as const
@ -29,12 +30,12 @@ const UserInfoDomain = Remesh.domain({
const SetUserInfoCommand = domain.command({
name: 'UserInfo.SetUserInfoCommand',
impl: (_, userInfo: UserInfo | null) => {
return [UserInfoState().new(userInfo), ChangeUserInfoEvent()]
return [UserInfoState().new(userInfo), UpdateUserInfoEvent()]
}
})
const ChangeUserInfoEvent = domain.event({
name: 'UserInfo.ChangeUserInfoEvent',
const UpdateUserInfoEvent = domain.event({
name: 'UserInfo.UpdateUserInfoEvent',
impl: ({ get }) => {
return get(UserInfoQuery())
}
@ -47,14 +48,16 @@ const UserInfoDomain = Remesh.domain({
id: from(storage.get<UserInfo['id']>(storageKeys.USER_INFO_ID)),
name: from(storage.get<UserInfo['name']>(storageKeys.USER_INFO_NAME)),
avatar: from(storage.get<UserInfo['avatar']>(storageKeys.USER_INFO_AVATAR)),
createTime: from(storage.get<UserInfo['createTime']>(storageKeys.USER_INFO_CREATE_TIME)),
themeMode: from(storage.get<UserInfo['themeMode']>(storageKeys.USER_INFO_THEME_MODE))
}).pipe(
map((userInfo) => {
if (
!isEmpty(userInfo.id) &&
!isEmpty(userInfo.name) &&
!isEmpty(userInfo.avatar) &&
!isEmpty(userInfo.themeMode)
!isNullish(userInfo.id) &&
!isNullish(userInfo.name) &&
!isNullish(userInfo.avatar) &&
!isNullish(userInfo.createTime) &&
!isNullish(userInfo.themeMode)
) {
return SetUserInfoCommand(userInfo as UserInfo)
} else {
@ -68,12 +71,13 @@ const UserInfoDomain = Remesh.domain({
domain.effect({
name: 'FormStateToStorageEffect',
impl: ({ fromEvent }) => {
const changeUserInfo$ = fromEvent(ChangeUserInfoEvent).pipe(
const changeUserInfo$ = fromEvent(UpdateUserInfoEvent).pipe(
tap(async (userInfo) => {
return await Promise.all([
storage.set<UserInfo['id'] | null>(storageKeys.USER_INFO_ID, userInfo?.id ?? null),
storage.set<UserInfo['name'] | null>(storageKeys.USER_INFO_NAME, userInfo?.name ?? null),
storage.set<UserInfo['avatar'] | null>(storageKeys.USER_INFO_AVATAR, userInfo?.avatar ?? null),
storage.set<UserInfo['createTime'] | null>(storageKeys.USER_INFO_CREATE_TIME, userInfo?.createTime ?? null),
storage.set<UserInfo['themeMode'] | null>(storageKeys.USER_INFO_THEME_MODE, userInfo?.themeMode ?? null)
])
})
@ -91,7 +95,7 @@ const UserInfoDomain = Remesh.domain({
SetUserInfoCommand
},
event: {
ChangeUserInfoEvent
UpdateUserInfoEvent
}
}
}

View file

@ -1,15 +1,22 @@
import { Remesh } from 'remesh'
import { type Promisable } from 'type-fest'
export type StorageValue = null | string | number | boolean | object
export type WatchEvent = 'update' | 'remove'
export type WatchCallback = (event: WatchEvent, key: string) => any
export type Unwatch = () => Promisable<void>
export interface Storage {
name: string
get: <T extends StorageValue>(key: string) => Promise<T | null>
set: <T extends StorageValue>(key: string, value: T) => Promise<void>
remove: (key: string) => Promise<void>
clear: () => Promise<void>
watch: (callback: WatchCallback) => Promise<Unwatch>
unwatch: Unwatch
}
const StorageExtern = Remesh.extern<Storage>({
export const IndexDBStorageExtern = Remesh.extern<Storage>({
default: {
name: 'STORAGE',
get: async () => {
@ -18,10 +25,41 @@ const StorageExtern = Remesh.extern<Storage>({
set: async () => {
throw new Error('"set" not implemented')
},
remove: async () => {
throw new Error('"remove" not implemented')
},
clear: async () => {
throw new Error('"clear" not implemented')
},
watch: () => {
throw new Error('"watch" not implemented')
},
unwatch: () => {
throw new Error('"unwatch" not implemented')
}
}
})
export default StorageExtern
export const BrowserSyncStorageExtern = Remesh.extern<Storage>({
default: {
name: 'STORAGE',
get: async () => {
throw new Error('"get" not implemented')
},
set: async () => {
throw new Error('"set" not implemented')
},
remove: async () => {
throw new Error('"remove" not implemented')
},
clear: async () => {
throw new Error('"clear" not implemented')
},
watch: () => {
throw new Error('"watch" not implemented')
},
unwatch: () => {
throw new Error('"unwatch" not implemented')
}
}
})

View file

@ -1,6 +1,6 @@
import indexedDbDriver from 'unstorage/drivers/indexedb'
import { webExtensionDriver, createStorage } from 'wxt/storage'
import StorageExtern from '@/domain/externs/Storage'
import { IndexDBStorageExtern, BrowserSyncStorageExtern } from '@/domain/externs/Storage'
import { STORAGE_NAME } from '@/constants'
const indexDBStorage = createStorage({
@ -11,16 +11,22 @@ const browserSyncStorage = createStorage({
driver: webExtensionDriver({ storageArea: 'sync' })
})
export const StorageIndexDBImpl = StorageExtern.impl({
export const IndexDBStorageImpl = IndexDBStorageExtern.impl({
name: STORAGE_NAME,
get: indexDBStorage.getItem,
set: indexDBStorage.setItem,
clear: indexDBStorage.clear
remove: indexDBStorage.removeItem,
clear: indexDBStorage.clear,
watch: indexDBStorage.watch,
unwatch: indexDBStorage.unwatch
})
export const StorageBrowserSyncImpl = StorageExtern.impl({
export const BrowserSyncStorageImpl = BrowserSyncStorageExtern.impl({
name: STORAGE_NAME,
get: browserSyncStorage.getItem,
set: browserSyncStorage.setItem,
clear: browserSyncStorage.clear
remove: browserSyncStorage.removeItem,
clear: browserSyncStorage.clear,
watch: browserSyncStorage.watch,
unwatch: browserSyncStorage.unwatch
})

View file

@ -17,5 +17,6 @@ declare interface UserInfo {
id: string
name: string
avatar: string
createTime: number
themeMode: 'system' | 'light' | 'dark'
}

View file

@ -5,5 +5,5 @@ export { default as createElement } from './createElement'
export { default as getSiteInfo } from './getSiteInfo'
export { default as chunk } from './chunk'
export { default as compressImage } from './compressImage'
export { default as isEmpty } from './isEmpty'
export { default as isNullish } from './isNullish'
export { default as checkSystemDarkMode } from './checkSystemDarkMode'

View file

@ -1,5 +0,0 @@
const isEmpty = (value: any) => {
return value === undefined || value === null
}
export default isEmpty

3
src/utils/isNullish.ts Normal file
View file

@ -0,0 +1,3 @@
const isNullish = (value: any) => value === undefined || value === null
export default isNullish