chore: upgrade wxt
This commit is contained in:
parent
9fca355c99
commit
0571682e73
18 changed files with 2195 additions and 1801 deletions
|
@ -34,6 +34,8 @@
|
||||||
"prettier/prettier": "error",
|
"prettier/prettier": "error",
|
||||||
"react/prop-types": "off",
|
"react/prop-types": "off",
|
||||||
"import/order": "error",
|
"import/order": "error",
|
||||||
|
"import/no-absolute-path": "off",
|
||||||
|
"n/no-callback-literal": "off",
|
||||||
"@typescript-eslint/naming-convention": "off",
|
"@typescript-eslint/naming-convention": "off",
|
||||||
"@typescript-eslint/no-non-null-assertion": "off",
|
"@typescript-eslint/no-non-null-assertion": "off",
|
||||||
"@typescript-eslint/explicit-function-return-type": "off",
|
"@typescript-eslint/explicit-function-return-type": "off",
|
||||||
|
@ -43,7 +45,6 @@
|
||||||
"@typescript-eslint/restrict-template-expressions": "off",
|
"@typescript-eslint/restrict-template-expressions": "off",
|
||||||
"@typescript-eslint/no-misused-promises": "off",
|
"@typescript-eslint/no-misused-promises": "off",
|
||||||
"@typescript-eslint/consistent-type-assertions": "off",
|
"@typescript-eslint/consistent-type-assertions": "off",
|
||||||
"import/no-absolute-path": "off",
|
|
||||||
"@typescript-eslint/no-base-to-string": "off",
|
"@typescript-eslint/no-base-to-string": "off",
|
||||||
"@typescript-eslint/no-unused-vars": "warn"
|
"@typescript-eslint/no-unused-vars": "warn"
|
||||||
}
|
}
|
||||||
|
|
74
package.json
74
package.json
|
@ -6,7 +6,7 @@
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "wxt",
|
"dev": "wxt",
|
||||||
"dev:signaling": "y-webrtc-signaling",
|
"dev:server": "y-webrtc-signaling",
|
||||||
"dev:firefox": "wxt -b firefox",
|
"dev:firefox": "wxt -b firefox",
|
||||||
"build": "wxt build",
|
"build": "wxt build",
|
||||||
"build:firefox": "wxt build -b firefox",
|
"build:firefox": "wxt build -b firefox",
|
||||||
|
@ -44,8 +44,8 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/molvqingtai/WebChat#readme",
|
"homepage": "https://github.com/molvqingtai/WebChat#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hookform/resolvers": "^3.3.2",
|
"@hookform/resolvers": "^3.3.4",
|
||||||
"@perfsee/jsonr": "^1.8.4",
|
"@perfsee/jsonr": "^1.12.2",
|
||||||
"@radix-ui/react-avatar": "^1.0.4",
|
"@radix-ui/react-avatar": "^1.0.4",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
||||||
"@radix-ui/react-hover-card": "^1.0.7",
|
"@radix-ui/react-hover-card": "^1.0.7",
|
||||||
|
@ -58,61 +58,61 @@
|
||||||
"@radix-ui/react-switch": "^1.0.3",
|
"@radix-ui/react-switch": "^1.0.3",
|
||||||
"@tailwindcss/typography": "^0.5.10",
|
"@tailwindcss/typography": "^0.5.10",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.1.0",
|
||||||
"date-fns": "^2.30.0",
|
"date-fns": "^3.3.1",
|
||||||
"idb-keyval": "^6.2.1",
|
"idb-keyval": "^6.2.1",
|
||||||
"lucide-react": "^0.294.0",
|
"lucide-react": "^0.336.0",
|
||||||
"nanoid": "^5.0.4",
|
"nanoid": "^5.0.6",
|
||||||
"peerjs": "^1.5.1",
|
"peerjs": "^1.5.2",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-hook-form": "^7.48.2",
|
"react-hook-form": "^7.50.1",
|
||||||
"react-markdown": "^9.0.1",
|
"react-markdown": "^9.0.1",
|
||||||
"react-nice-avatar": "^1.5.0",
|
"react-nice-avatar": "^1.5.0",
|
||||||
"react-use": "^17.4.2",
|
"react-use": "^17.5.0",
|
||||||
"remark-breaks": "^4.0.0",
|
"remark-breaks": "^4.0.0",
|
||||||
"remark-gfm": "^4.0.0",
|
"remark-gfm": "^4.0.0",
|
||||||
"remesh": "^4.2.0",
|
"remesh": "^4.2.1",
|
||||||
"remesh-logger": "^4.1.0",
|
"remesh-logger": "^4.1.0",
|
||||||
"remesh-react": "^4.1.0",
|
"remesh-react": "^4.1.2",
|
||||||
"remesh-yjs": "^4.1.0",
|
|
||||||
"rxjs": "^7.8.1",
|
"rxjs": "^7.8.1",
|
||||||
"sonner": "^1.2.4",
|
"sonner": "^1.4.0",
|
||||||
"tailwind-merge": "^2.1.0",
|
"tailwind-merge": "^2.2.1",
|
||||||
"type-fest": "^4.8.3",
|
"type-fest": "^4.10.3",
|
||||||
"valibot": "^0.22.0",
|
"unstorage": "^1.10.1",
|
||||||
"y-webrtc": "^10.2.6"
|
"valibot": "^0.29.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^18.4.3",
|
"@commitlint/cli": "^18.6.1",
|
||||||
"@commitlint/config-conventional": "^18.4.3",
|
"@commitlint/config-conventional": "^18.6.2",
|
||||||
"@types/node": "^20.10.3",
|
"@types/node": "^20.11.20",
|
||||||
"@types/react": "^18.2.41",
|
"@types/react": "^18.2.57",
|
||||||
"@types/react-dom": "^18.2.17",
|
"@types/react-dom": "^18.2.19",
|
||||||
|
"@types/webextension-polyfill": "^0.10.7",
|
||||||
"@vitejs/plugin-react": "^4.2.1",
|
"@vitejs/plugin-react": "^4.2.1",
|
||||||
"autoprefixer": "^10.4.16",
|
"autoprefixer": "^10.4.17",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^8.55.0",
|
"eslint": "^8.56.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-config-standard-with-typescript": "^40.0.0",
|
"eslint-config-standard-with-typescript": "^43.0.1",
|
||||||
"eslint-plugin-import": "^2.29.0",
|
"eslint-plugin-import": "^2.29.1",
|
||||||
"eslint-plugin-n": "^16.3.1",
|
"eslint-plugin-n": "^16.6.2",
|
||||||
"eslint-plugin-prettier": "^5.0.1",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
"eslint-plugin-promise": "^6.1.1",
|
"eslint-plugin-promise": "^6.1.1",
|
||||||
"eslint-plugin-react": "^7.33.2",
|
"eslint-plugin-react": "^7.33.2",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"eslint-plugin-tailwindcss": "^3.13.0",
|
"eslint-plugin-tailwindcss": "^3.14.3",
|
||||||
"husky": "^8.0.3",
|
"husky": "^9.0.11",
|
||||||
"lint-staged": "^15.2.0",
|
"lint-staged": "^15.2.2",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"postcss": "^8.4.32",
|
"postcss": "^8.4.35",
|
||||||
"prettier": "^3.1.0",
|
"prettier": "^3.2.5",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
"tailwindcss": "^3.3.6",
|
"tailwindcss": "^3.4.1",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"typescript": "^5.3.2",
|
"typescript": "^5.3.3",
|
||||||
"webext-bridge": "^6.0.1",
|
"webext-bridge": "^6.0.1",
|
||||||
"wxt": "^0.10.4"
|
"wxt": "^0.17.0"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.{js,jsx,ts,tsx}": "eslint --fix"
|
"*.{js,jsx,ts,tsx}": "eslint --fix"
|
||||||
|
|
3565
pnpm-lock.yaml
3565
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,5 @@
|
||||||
import { browser } from 'wxt/browser'
|
import { browser } from 'wxt/browser'
|
||||||
import { defineBackground } from 'wxt/client'
|
import { defineBackground } from 'wxt/sandbox'
|
||||||
|
|
||||||
export default defineBackground({
|
export default defineBackground({
|
||||||
// Set manifest options
|
// Set manifest options
|
||||||
|
|
|
@ -3,33 +3,34 @@ import { createRoot } from 'react-dom/client'
|
||||||
import { Remesh } from 'remesh'
|
import { Remesh } from 'remesh'
|
||||||
import { RemeshRoot } from 'remesh-react'
|
import { RemeshRoot } from 'remesh-react'
|
||||||
import { RemeshLogger } from 'remesh-logger'
|
import { RemeshLogger } from 'remesh-logger'
|
||||||
import { defineContentScript, createContentScriptUi } from 'wxt/client'
|
import { defineContentScript } from 'wxt/sandbox'
|
||||||
import * as Y from 'yjs'
|
import { createShadowRootUi } from 'wxt/client'
|
||||||
import { RemeshYjs, RemeshYjsExtern } from 'remesh-yjs'
|
|
||||||
import { WebrtcProvider } from 'y-webrtc'
|
|
||||||
import App from './App'
|
import App from './App'
|
||||||
import { IndexDBStorageImpl, BrowserSyncStorageImpl } from '@/impl/Storage'
|
import { IndexDBStorageImpl, BrowserSyncStorageImpl } from '@/impl/Storage'
|
||||||
|
import { PeerClientImpl } from '@/impl/PeerClient'
|
||||||
import '@/assets/styles/tailwind.css'
|
import '@/assets/styles/tailwind.css'
|
||||||
|
|
||||||
export default defineContentScript({
|
export default defineContentScript({
|
||||||
cssInjectionMode: 'ui',
|
cssInjectionMode: 'ui',
|
||||||
matches: ['*://*.example.com/*', '*://*.google.com/*', '*://*.v2ex.com/*'],
|
matches: ['*://*.example.com/*', '*://*.google.com/*', '*://*.v2ex.com/*'],
|
||||||
async main(ctx) {
|
async main(ctx) {
|
||||||
const doc = new Y.Doc()
|
|
||||||
// eslint-disable-next-line no-new
|
|
||||||
new WebrtcProvider(__NAME__, doc, { signaling: ['ws://localhost:4444'] })
|
|
||||||
|
|
||||||
const store = Remesh.store({
|
const store = Remesh.store({
|
||||||
externs: [IndexDBStorageImpl, BrowserSyncStorageImpl, RemeshYjsExtern.impl({ doc })],
|
externs: [IndexDBStorageImpl, BrowserSyncStorageImpl, PeerClientImpl],
|
||||||
inspectors: [RemeshLogger()]
|
inspectors: [RemeshLogger()]
|
||||||
})
|
})
|
||||||
|
|
||||||
const ui = await createContentScriptUi(ctx, {
|
const ui = await createShadowRootUi(ctx, {
|
||||||
name: __NAME__,
|
name: __NAME__,
|
||||||
type: 'overlay',
|
position: 'inline',
|
||||||
mount(container) {
|
// anchor: 'body',
|
||||||
const root = createRoot(container)
|
// append: 'first',
|
||||||
|
onMount: (container) => {
|
||||||
|
const app = document.createElement('div')
|
||||||
|
app.id = 'app'
|
||||||
|
container.append(app)
|
||||||
|
|
||||||
|
const root = createRoot(app)
|
||||||
root.render(
|
root.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<RemeshRoot store={store}>
|
<RemeshRoot store={store}>
|
||||||
|
@ -39,8 +40,8 @@ export default defineContentScript({
|
||||||
)
|
)
|
||||||
return root
|
return root
|
||||||
},
|
},
|
||||||
onRemove(root) {
|
onRemove: (root) => {
|
||||||
root.unmount()
|
root?.unmount()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
ui.mount()
|
ui.mount()
|
||||||
|
|
|
@ -8,6 +8,6 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<script type="module" src="./index.tsx"></script>
|
<script type="module" src="./main.tsx"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -2,14 +2,19 @@ import { Remesh } from 'remesh'
|
||||||
import { ListModule } from 'remesh/modules/list'
|
import { ListModule } from 'remesh/modules/list'
|
||||||
import { nanoid } from 'nanoid'
|
import { nanoid } from 'nanoid'
|
||||||
import { from, map, tap, merge } from 'rxjs'
|
import { from, map, tap, merge } from 'rxjs'
|
||||||
import { RemeshYjs } from 'remesh-yjs'
|
|
||||||
import { IndexDBStorageExtern } from './externs/Storage'
|
import { IndexDBStorageExtern } from './externs/Storage'
|
||||||
|
import { PeerClientExtern } from './externs/PeerClient'
|
||||||
|
import { callbackToObservable, stringToHex } from '@/utils'
|
||||||
|
|
||||||
|
const hostRoomId = stringToHex(document.location.host)
|
||||||
|
|
||||||
const MessageListDomain = Remesh.domain({
|
const MessageListDomain = Remesh.domain({
|
||||||
name: 'MessageListDomain',
|
name: 'MessageListDomain',
|
||||||
impl: (domain) => {
|
impl: (domain) => {
|
||||||
const storage = domain.getExtern(IndexDBStorageExtern)
|
const storage = domain.getExtern(IndexDBStorageExtern)
|
||||||
|
const peerClient = domain.getExtern(PeerClientExtern)
|
||||||
const storageKey = `MESSAGE_LIST` as const
|
const storageKey = `MESSAGE_LIST` as const
|
||||||
|
peerClient.connect(hostRoomId)
|
||||||
|
|
||||||
const MessageListModule = ListModule<Message>(domain, {
|
const MessageListModule = ListModule<Message>(domain, {
|
||||||
name: 'MessageListModule',
|
name: 'MessageListModule',
|
||||||
|
@ -100,17 +105,31 @@ const MessageListDomain = Remesh.domain({
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
RemeshYjs(domain, {
|
domain.effect({
|
||||||
key: 'MessageList',
|
name: 'FormStateToPeerClientEffect',
|
||||||
dataType: 'array',
|
impl: ({ fromEvent }) => {
|
||||||
onSend: ({ get }): Message[] => {
|
const createItem$ = fromEvent(CreateItemEvent).pipe(
|
||||||
return get(ListQuery())
|
tap(async (message) => {
|
||||||
},
|
await peerClient.sendMessage(JSON.stringify(message))
|
||||||
onReceive: (_, messages: Message[]) => {
|
})
|
||||||
return InitListCommand(messages)
|
)
|
||||||
|
return merge(createItem$).pipe(map(() => null))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// domain.effect({
|
||||||
|
// name: 'FormPeerClientToStateEffect',
|
||||||
|
// impl: () => {
|
||||||
|
// return callbackToObservable(peerClient.onMessage.bind(peerClient)).pipe(
|
||||||
|
// map((message) => {
|
||||||
|
// console.log(message)
|
||||||
|
// // debugger
|
||||||
|
// return CreateItemCommand(message)
|
||||||
|
// })
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
|
||||||
return {
|
return {
|
||||||
query: {
|
query: {
|
||||||
ItemQuery,
|
ItemQuery,
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { Remesh } from 'remesh'
|
import { Remesh } from 'remesh'
|
||||||
import { forkJoin, from, map, merge, switchMap, tap } from 'rxjs'
|
import { forkJoin, from, map, merge, switchMap, tap } from 'rxjs'
|
||||||
import { BrowserSyncStorageExtern } from './externs/Storage'
|
import { BrowserSyncStorageExtern } from './externs/Storage'
|
||||||
import { isNullish, storageToObservable } from '@/utils'
|
import { isNullish } from '@/utils'
|
||||||
|
import callbackToObservable from '@/utils/callbackToObservable'
|
||||||
|
|
||||||
const UserInfoDomain = Remesh.domain({
|
const UserInfoDomain = Remesh.domain({
|
||||||
name: 'UserInfoDomain',
|
name: 'UserInfoDomain',
|
||||||
|
@ -104,7 +105,7 @@ const UserInfoDomain = Remesh.domain({
|
||||||
domain.effect({
|
domain.effect({
|
||||||
name: 'WatchStorageToStateEffect',
|
name: 'WatchStorageToStateEffect',
|
||||||
impl: () => {
|
impl: () => {
|
||||||
return storageToObservable(storage).pipe(
|
return callbackToObservable(storage.watch, storage.unwatch).pipe(
|
||||||
switchMap(() => {
|
switchMap(() => {
|
||||||
return forkJoin({
|
return forkJoin({
|
||||||
id: from(storage.get<UserInfo['id']>(storageKeys.USER_INFO_ID)),
|
id: from(storage.get<UserInfo['id']>(storageKeys.USER_INFO_ID)),
|
||||||
|
|
25
src/domain/externs/PeerClient.ts
Normal file
25
src/domain/externs/PeerClient.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import { Remesh } from 'remesh'
|
||||||
|
|
||||||
|
export interface PeerClient {
|
||||||
|
connect: (id: string) => Promise<void>
|
||||||
|
sendMessage: (message: string) => Promise<void>
|
||||||
|
onMessage: (callback: (message: string) => void) => void
|
||||||
|
close: () => Promise<void> | void
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PeerClientExtern = Remesh.extern<PeerClient>({
|
||||||
|
default: {
|
||||||
|
connect: async () => {
|
||||||
|
throw new Error('"connect" not implemented.')
|
||||||
|
},
|
||||||
|
sendMessage: async () => {
|
||||||
|
throw new Error('"sendMessage" not implemented.')
|
||||||
|
},
|
||||||
|
onMessage: () => {
|
||||||
|
throw new Error('"onMessage" not implemented.')
|
||||||
|
},
|
||||||
|
close: () => {
|
||||||
|
throw new Error('"close" not implemented.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
|
@ -20,22 +20,22 @@ export const IndexDBStorageExtern = Remesh.extern<Storage>({
|
||||||
default: {
|
default: {
|
||||||
name: 'STORAGE',
|
name: 'STORAGE',
|
||||||
get: async () => {
|
get: async () => {
|
||||||
throw new Error('"get" not implemented')
|
throw new Error('"get" not implemented.')
|
||||||
},
|
},
|
||||||
set: async () => {
|
set: async () => {
|
||||||
throw new Error('"set" not implemented')
|
throw new Error('"set" not implemented.')
|
||||||
},
|
},
|
||||||
remove: async () => {
|
remove: async () => {
|
||||||
throw new Error('"remove" not implemented')
|
throw new Error('"remove" not implemented.')
|
||||||
},
|
},
|
||||||
clear: async () => {
|
clear: async () => {
|
||||||
throw new Error('"clear" not implemented')
|
throw new Error('"clear" not implemented.')
|
||||||
},
|
},
|
||||||
watch: () => {
|
watch: () => {
|
||||||
throw new Error('"watch" not implemented')
|
throw new Error('"watch" not implemented.')
|
||||||
},
|
},
|
||||||
unwatch: () => {
|
unwatch: () => {
|
||||||
throw new Error('"unwatch" not implemented')
|
throw new Error('"unwatch" not implemented.')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -44,22 +44,22 @@ export const BrowserSyncStorageExtern = Remesh.extern<Storage>({
|
||||||
default: {
|
default: {
|
||||||
name: 'STORAGE',
|
name: 'STORAGE',
|
||||||
get: async () => {
|
get: async () => {
|
||||||
throw new Error('"get" not implemented')
|
throw new Error('"get" not implemented.')
|
||||||
},
|
},
|
||||||
set: async () => {
|
set: async () => {
|
||||||
throw new Error('"set" not implemented')
|
throw new Error('"set" not implemented.')
|
||||||
},
|
},
|
||||||
remove: async () => {
|
remove: async () => {
|
||||||
throw new Error('"remove" not implemented')
|
throw new Error('"remove" not implemented.')
|
||||||
},
|
},
|
||||||
clear: async () => {
|
clear: async () => {
|
||||||
throw new Error('"clear" not implemented')
|
throw new Error('"clear" not implemented.')
|
||||||
},
|
},
|
||||||
watch: () => {
|
watch: () => {
|
||||||
throw new Error('"watch" not implemented')
|
throw new Error('"watch" not implemented.')
|
||||||
},
|
},
|
||||||
unwatch: () => {
|
unwatch: () => {
|
||||||
throw new Error('"unwatch" not implemented')
|
throw new Error('"unwatch" not implemented.')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
100
src/impl/PeerClient.ts
Normal file
100
src/impl/PeerClient.ts
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
import Peer, { type DataConnection } from 'peerjs'
|
||||||
|
import { nanoid } from 'nanoid'
|
||||||
|
import { PeerClientExtern } from '../domain/externs/PeerClient'
|
||||||
|
|
||||||
|
class PeerClient {
|
||||||
|
private peer: Peer | undefined
|
||||||
|
private connection: DataConnection | undefined
|
||||||
|
|
||||||
|
async connect(id: string) {
|
||||||
|
const connect = (id: string) => {
|
||||||
|
this.peer = new Peer(nanoid())
|
||||||
|
this.peer.on('connection', (e) => {
|
||||||
|
console.log('connection2', e)
|
||||||
|
})
|
||||||
|
const connection = this.peer.connect(id)
|
||||||
|
connection.on('open', () => {
|
||||||
|
console.log('connection open')
|
||||||
|
|
||||||
|
this.connection = connection
|
||||||
|
})
|
||||||
|
connection.on('error', (error) => {
|
||||||
|
console.log('error', error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.peer = new Peer(id)
|
||||||
|
this.peer.on('connection', (e) => {
|
||||||
|
console.log('connection1', e)
|
||||||
|
})
|
||||||
|
this.peer.on('open', (e) => {
|
||||||
|
console.log('open', e)
|
||||||
|
this.peer!.on('connection', (e) => {
|
||||||
|
console.log('connection1', e)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
this.peer.on('error', (error) => {
|
||||||
|
if (error.type === 'unavailable-id') {
|
||||||
|
console.log('unavailable-id')
|
||||||
|
|
||||||
|
connect(id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// return await new Promise((resolve, reject) => {
|
||||||
|
// try {
|
||||||
|
// this.peer = new Peer(id)
|
||||||
|
// this.peer.on('connection', (e) => {
|
||||||
|
// console.log('connection1', e)
|
||||||
|
// })
|
||||||
|
// this.peer
|
||||||
|
// .once('open', (e) => {
|
||||||
|
// resolve(e)
|
||||||
|
// })
|
||||||
|
// .once('error', (error) => {
|
||||||
|
// if (error.type === 'unavailable-id') {
|
||||||
|
// const connection = this.peer!.connect(id)!
|
||||||
|
// connection
|
||||||
|
// .once('open', () => {
|
||||||
|
// console.log('open')
|
||||||
|
// console.log('connection', connection)
|
||||||
|
// this.connection = connection
|
||||||
|
// resolve(id)
|
||||||
|
// })
|
||||||
|
// .once('error', (error) => {
|
||||||
|
// reject(error)
|
||||||
|
// })
|
||||||
|
// } else {
|
||||||
|
// debugger
|
||||||
|
// reject(error)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// } catch (error) {
|
||||||
|
// reject(error)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendMessage(message: string) {
|
||||||
|
return await new Promise<void>((resolve, reject) => {
|
||||||
|
if (this.connection) {
|
||||||
|
this.connection.send(message)
|
||||||
|
resolve(undefined)
|
||||||
|
} else {
|
||||||
|
reject(new Error('Connection not established.'))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMessage(callback: (message: string) => void) {
|
||||||
|
this.connection?.on('data', (data: any) => {
|
||||||
|
// callback(data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.connection?.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PeerClientImpl = PeerClientExtern.impl(new PeerClient())
|
|
@ -1,7 +1,8 @@
|
||||||
|
import { createStorage } from 'unstorage'
|
||||||
import indexedDbDriver from 'unstorage/drivers/indexedb'
|
import indexedDbDriver from 'unstorage/drivers/indexedb'
|
||||||
import { webExtensionDriver, createStorage } from 'wxt/storage'
|
|
||||||
import { IndexDBStorageExtern, BrowserSyncStorageExtern } from '@/domain/externs/Storage'
|
import { IndexDBStorageExtern, BrowserSyncStorageExtern } from '@/domain/externs/Storage'
|
||||||
import { STORAGE_NAME } from '@/constants'
|
import { STORAGE_NAME } from '@/constants'
|
||||||
|
import { webExtensionDriver } from '@/utils/webExtensionDriver'
|
||||||
|
|
||||||
const indexDBStorage = createStorage({
|
const indexDBStorage = createStorage({
|
||||||
driver: indexedDbDriver({ base: `${STORAGE_NAME}:` })
|
driver: indexedDbDriver({ base: `${STORAGE_NAME}:` })
|
||||||
|
|
18
src/utils/callbackToObservable.ts
Normal file
18
src/utils/callbackToObservable.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import { Observable } from 'rxjs'
|
||||||
|
|
||||||
|
export type Subscribe<T> = (callback: (event: T) => void) => void
|
||||||
|
|
||||||
|
const callbackToObservable = <T>(subscribe: Subscribe<T>, unsubscribe?: () => void) => {
|
||||||
|
return new Observable((subscriber) => {
|
||||||
|
subscribe((event: T) => {
|
||||||
|
subscriber.next(event)
|
||||||
|
})
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsubscribe?.()
|
||||||
|
subscriber.complete()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default callbackToObservable
|
|
@ -7,4 +7,5 @@ export { default as chunk } from './chunk'
|
||||||
export { default as compressImage } from './compressImage'
|
export { default as compressImage } from './compressImage'
|
||||||
export { default as isNullish } from './isNullish'
|
export { default as isNullish } from './isNullish'
|
||||||
export { default as checkSystemDarkMode } from './checkSystemDarkMode'
|
export { default as checkSystemDarkMode } from './checkSystemDarkMode'
|
||||||
export { default as storageToObservable } from './storageToObservable'
|
export { default as callbackToObservable } from './callbackToObservable'
|
||||||
|
export { default as stringToHex } from './stringToHex'
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
import { Observable } from 'rxjs'
|
|
||||||
import { type Storage } from '@/domain/externs/Storage'
|
|
||||||
|
|
||||||
const storageToObservable = (storage: Storage) => {
|
|
||||||
return new Observable((subscriber) => {
|
|
||||||
storage.watch((event) => {
|
|
||||||
subscriber.next(event)
|
|
||||||
})
|
|
||||||
return () => {
|
|
||||||
storage.unwatch()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export default storageToObservable
|
|
5
src/utils/stringToHex.ts
Normal file
5
src/utils/stringToHex.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
const stringToHex = (string: string) => {
|
||||||
|
return [...string].map((char) => char.charCodeAt(0).toString(16)).join('')
|
||||||
|
}
|
||||||
|
|
||||||
|
export default stringToHex
|
82
src/utils/webExtensionDriver.ts
Normal file
82
src/utils/webExtensionDriver.ts
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
import { type Driver, type WatchCallback, defineDriver } from 'unstorage'
|
||||||
|
import browser, { type Storage as BrowserStorage } from 'webextension-polyfill'
|
||||||
|
|
||||||
|
export interface WebExtensionDriverOptions {
|
||||||
|
storageArea: 'sync' | 'local' | 'managed' | 'session'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const webExtensionDriver: (opts: WebExtensionDriverOptions) => Driver = defineDriver((opts) => {
|
||||||
|
const checkPermission = () => {
|
||||||
|
if (browser.storage == null) throw Error("You must request the 'storage' permission to use webExtensionDriver")
|
||||||
|
}
|
||||||
|
|
||||||
|
const _storageListener: (changes: BrowserStorage.StorageAreaSyncOnChangedChangesType) => void = (changes) => {
|
||||||
|
Object.entries(changes).forEach(([key, { newValue }]) => {
|
||||||
|
_listeners.forEach((callback) => {
|
||||||
|
callback(newValue ? 'update' : 'remove', key)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const _listeners = new Set<WatchCallback>()
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: 'web-extension:' + opts.storageArea,
|
||||||
|
async hasItem(key) {
|
||||||
|
checkPermission()
|
||||||
|
const res = await browser.storage[opts.storageArea].get(key)
|
||||||
|
return res[key] != null
|
||||||
|
},
|
||||||
|
async getItem(key) {
|
||||||
|
checkPermission()
|
||||||
|
const res = await browser.storage[opts.storageArea].get(key)
|
||||||
|
return res[key] ?? null
|
||||||
|
},
|
||||||
|
async getItems(items) {
|
||||||
|
checkPermission()
|
||||||
|
const res = await browser.storage[opts.storageArea].get(items.map((item) => item.key))
|
||||||
|
return items.map((item) => ({
|
||||||
|
key: item.key,
|
||||||
|
value: res[item.key] ?? null
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
async setItem(key, value) {
|
||||||
|
checkPermission()
|
||||||
|
await browser.storage[opts.storageArea].set({ [key]: value ?? null })
|
||||||
|
},
|
||||||
|
async setItems(items) {
|
||||||
|
checkPermission()
|
||||||
|
const map = items.reduce<Record<string, any>>((map, item) => {
|
||||||
|
map[item.key] = item.value ?? null
|
||||||
|
return map
|
||||||
|
}, {})
|
||||||
|
await browser.storage[opts.storageArea].set(map)
|
||||||
|
},
|
||||||
|
async removeItem(key) {
|
||||||
|
checkPermission()
|
||||||
|
await browser.storage[opts.storageArea].remove(key)
|
||||||
|
},
|
||||||
|
async getKeys() {
|
||||||
|
checkPermission()
|
||||||
|
const all = await browser.storage[opts.storageArea].get()
|
||||||
|
return Object.keys(all)
|
||||||
|
},
|
||||||
|
async clear() {
|
||||||
|
checkPermission()
|
||||||
|
await browser.storage[opts.storageArea].clear()
|
||||||
|
},
|
||||||
|
watch(callback) {
|
||||||
|
checkPermission()
|
||||||
|
_listeners.add(callback)
|
||||||
|
if (_listeners.size === 1) {
|
||||||
|
browser.storage[opts.storageArea].onChanged.addListener(_storageListener)
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
_listeners.delete(callback)
|
||||||
|
if (_listeners.size === 0) {
|
||||||
|
browser.storage[opts.storageArea].onChanged.removeListener(_storageListener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
Loading…
Reference in a new issue