Skip to content
This repository has been archived by the owner on Jan 8, 2024. It is now read-only.

refactor: add package y-idb #51

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
"@blocksuite/lit": "0.0.0-20231101080734-aa27dc89-nightly",
"@blocksuite/store": "0.0.0-20231101080734-aa27dc89-nightly",
"@toeverything/theme": "0.7.24",
"@toeverything/y-indexeddb": "0.10.0-canary.9",
"foxact": "^0.2.26",
"idb": "^7.1.1",
"jotai": "^2.5.1",
Expand All @@ -49,6 +48,7 @@
"react": "18.3.0-canary-8039e6d0b-20231026",
"react-dom": "18.3.0-canary-8039e6d0b-20231026",
"uuid": "^9.0.1",
"y-idb": "workspace:*",
"y-utility": "^0.1.3",
"y-utils": "workspace:*",
"yjs": "^13.6.10"
Expand Down
5 changes: 2 additions & 3 deletions packages/core/src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ export class WorkspaceManager {
const {
createIndexedDBProvider,
downloadBinary
} = await import('@toeverything/y-indexeddb')
} = await import('y-idb/browser')
this.#preloads.push(async (workspace) => {
const binary = await downloadBinary(workspace.doc.guid,
'refine-indexeddb')
Expand All @@ -225,8 +225,7 @@ export class WorkspaceManager {
}
})
this.#providers.push((workspace) => {
const provider = createIndexedDBProvider(workspace.doc,
'refine-indexeddb')
const provider = createIndexedDBProvider('refine-indexeddb', workspace.doc)
return {
connect: () => {
provider.connect()
Expand Down
3 changes: 3 additions & 0 deletions packages/core/tsconfig.src.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
"references": [
{
"path": "../jotai-inject"
},
{
"path": "../y-idb"
}
]
}
3 changes: 2 additions & 1 deletion packages/core/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ export default defineConfig({
/^y-utility/,
'uuid',
/^foxact/,
'idb'
'idb',
'y-idb/browser'
]
}
},
Expand Down
44 changes: 44 additions & 0 deletions packages/y-idb/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"name": "y-idb",
"description": "yjs persistence",
"version": "0.0.1",
"type": "module",
"author": "himself65 <[email protected]>",
"files": [
"dist"
],
"keywords": [
"yjs",
"provider",
"database",
"persistence"
],
"exports": {
"./browser": {
"types": "./dist/src/browser.d.ts",
"import": "./dist/browser.js",
"require": "./dist/browser.cjs"
}
},
"scripts": {
"build": "vite build",
"dev": "vite build --watch"
},
"publishConfig": {
"access": "public"
},
"devDependencies": {
"vite": "^4.5.0",
"vite-plugin-dts": "^3.6.3",
"vite-plugin-istanbul": "^5.0.0",
"vitest": "^0.34.6",
"yjs": "^13.6.10"

},
"dependencies": {
"idb": "^8.0.0"
},
"peerDependencies": {
"yjs": "^13"
}
}
134 changes: 134 additions & 0 deletions packages/y-idb/src/browser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import {
openDB,
type DBSchema,
type IDBPDatabase
} from 'idb'
import type {
Workspace,
ProviderAdapter,
StatusAdapter
} from './shared/type.js'
import { createLazyProvider } from './shared/lazy-provider.js'
import {
applyUpdate,
diffUpdate,
Doc,
encodeStateAsUpdate,
encodeStateVectorFromUpdate
} from 'yjs'

const mergeCount = 200

function mergeUpdates (updates: Uint8Array[]): Uint8Array {
const doc = new Doc()
for (const update of updates) {
applyUpdate(doc, update)
}
return encodeStateAsUpdate(doc)
}

interface YDB extends DBSchema {
workspace: {
key: string
value: Workspace,
indexes: {
guid: string
}
}
}

function createLazyDB (name: string): () => Promise<IDBPDatabase<YDB>> {
let lazyDBPromise: Promise<IDBPDatabase<YDB>> | null = null
return async () => {
if (lazyDBPromise !== null) {
return lazyDBPromise
}
lazyDBPromise = openDB<YDB>(name, 1, {
upgrade (db) {

Check warning on line 47 in packages/y-idb/src/browser.ts

View check run for this annotation

Codecov / codecov/patch

packages/y-idb/src/browser.ts#L47

Added line #L47 was not covered by tests
{
db.createObjectStore('workspace', {

Check warning on line 49 in packages/y-idb/src/browser.ts

View check run for this annotation

Codecov / codecov/patch

packages/y-idb/src/browser.ts#L49

Added line #L49 was not covered by tests
keyPath: 'guid'
})
}
}
})
return lazyDBPromise
}
}

export function createIndexedDBProvider (
name: string, rootDoc: Doc): ProviderAdapter & StatusAdapter {
const getDB = createLazyDB(name)
return createLazyProvider(rootDoc, {
queryDocState: async (guid, query) => {
const db = await getDB()
const tx = db.transaction('workspace', 'readonly')
const os = tx.objectStore('workspace')
const workspace = await os.get(guid)
if (workspace === undefined || workspace.updates.length === 0) {
return {
missingUpdate: new Uint8Array()
}
}

const { updates } = workspace

const update = mergeUpdates(updates.map(({ update }) => update))

const missingUpdate = query?.stateVector
? diffUpdate(update, query?.stateVector)
: update

Check warning on line 80 in packages/y-idb/src/browser.ts

View check run for this annotation

Codecov / codecov/patch

packages/y-idb/src/browser.ts#L80

Added line #L80 was not covered by tests

return { missingUpdate, stateVector: encodeStateVectorFromUpdate(update) }
},
sendDocUpdate: async (guid, update) => {
const db = await getDB()
const tx = db.transaction('workspace', 'readwrite')
const os = tx.objectStore('workspace')
const data = await os.get(guid)
if (data === undefined) {
await os.add({
guid,
updates: [],
author: name
})
} else {
if (data.updates.length > mergeCount) {
data.updates = [

Check warning on line 97 in packages/y-idb/src/browser.ts

View check run for this annotation

Codecov / codecov/patch

packages/y-idb/src/browser.ts#L97

Added line #L97 was not covered by tests
{
update: mergeUpdates(data.updates.map(({ update }) => update)),

Check warning on line 99 in packages/y-idb/src/browser.ts

View check run for this annotation

Codecov / codecov/patch

packages/y-idb/src/browser.ts#L99

Added line #L99 was not covered by tests
date: Date.now()
}
]
}
await os.put({
guid,
updates: [
...data.updates, {
date: Date.now(),
update
}
],
author: name
})
}
}
}, {
author: 'ydb'
})
}

export async function downloadBinary(
guid: string,
name: string
): Promise<Uint8Array | false> {
const getDB = createLazyDB(name)
const db = await getDB()
const tx = db.transaction('workspace', 'readonly')
const os = tx.objectStore('workspace')
const workspace = await os.get(guid)
if (!workspace) {
return false;
}
return workspace.updates.map(({ update }) => update).reduce((a, b) => mergeUpdates([a, b]))
}
Loading
Loading