perf: move PouchDB/IndexedDB operations to a Web Worker

All database reads and writes now run off the main thread via a
dedicated worker, eliminating IndexedDB overhead from the frame budget.

- Create data.worker.ts exposing the Data class via Comlink
- Refactor data.ts to export a Comlink-wrapped proxy and a standalone
  generateId() pure function (workers can't expose sync methods cleanly)
- Update all 10 call sites to import generateId directly instead of
  calling data.generateId()

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Julien Calixte
2026-04-04 11:27:45 +02:00
parent 1b5e23e3d4
commit b003a3e008
14 changed files with 225 additions and 231 deletions

View File

@@ -33,6 +33,7 @@
"@vueuse/core": "^13.6.0", "@vueuse/core": "^13.6.0",
"@vueuse/router": "^13.6.0", "@vueuse/router": "^13.6.0",
"arktype": "^2.1.29", "arktype": "^2.1.29",
"comlink": "^4.4.2",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"events": "^3.3.0", "events": "^3.3.0",
"font-color-contrast": "^11.1.0", "font-color-contrast": "^11.1.0",

66
pnpm-lock.yaml generated
View File

@@ -53,6 +53,9 @@ importers:
arktype: arktype:
specifier: ^2.1.29 specifier: ^2.1.29
version: 2.1.29 version: 2.1.29
comlink:
specifier: ^4.4.2
version: 4.4.2
date-fns: date-fns:
specifier: ^4.1.0 specifier: ^4.1.0
version: 4.1.0 version: 4.1.0
@@ -1053,12 +1056,6 @@ packages:
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
'@eslint-community/eslint-utils@4.4.0':
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
'@eslint-community/eslint-utils@4.7.0': '@eslint-community/eslint-utils@4.7.0':
resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==} resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -1069,10 +1066,6 @@ packages:
resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
'@eslint-community/regexpp@4.6.2':
resolution: {integrity: sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
'@eslint/eslintrc@2.1.4': '@eslint/eslintrc@2.1.4':
resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -2985,6 +2978,9 @@ packages:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
comlink@4.4.2:
resolution: {integrity: sha512-OxGdvBmJuNKSCMO4NTl1L47VRp6xn2wG4F/2hYzB6tiCb709otOxtEYCSvK80PtjODfXXZu8ds+Nw5kVCjqd2g==}
commander@2.20.3: commander@2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
@@ -3275,15 +3271,6 @@ packages:
supports-color: supports-color:
optional: true optional: true
debug@4.3.4:
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
engines: {node: '>=6.0'}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
debug@4.4.1: debug@4.4.1:
resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
engines: {node: '>=6.0'} engines: {node: '>=6.0'}
@@ -4959,9 +4946,6 @@ packages:
ms@2.0.0: ms@2.0.0:
resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
ms@2.1.3: ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
@@ -7642,25 +7626,17 @@ snapshots:
'@esbuild/win32-x64@0.25.5': '@esbuild/win32-x64@0.25.5':
optional: true optional: true
'@eslint-community/eslint-utils@4.4.0(eslint@8.57.1)':
dependencies:
eslint: 8.57.1
eslint-visitor-keys: 3.4.3
'@eslint-community/eslint-utils@4.7.0(eslint@8.57.1)': '@eslint-community/eslint-utils@4.7.0(eslint@8.57.1)':
dependencies: dependencies:
eslint: 8.57.1 eslint: 8.57.1
eslint-visitor-keys: 3.4.3 eslint-visitor-keys: 3.4.3
'@eslint-community/regexpp@4.12.1': '@eslint-community/regexpp@4.12.1': {}
optional: true
'@eslint-community/regexpp@4.6.2': {}
'@eslint/eslintrc@2.1.4': '@eslint/eslintrc@2.1.4':
dependencies: dependencies:
ajv: 6.12.6 ajv: 6.12.6
debug: 4.3.4 debug: 4.4.3
espree: 9.6.1 espree: 9.6.1
globals: 13.20.0 globals: 13.20.0
ignore: 5.2.4 ignore: 5.2.4
@@ -7676,7 +7652,7 @@ snapshots:
'@humanwhocodes/config-array@0.13.0': '@humanwhocodes/config-array@0.13.0':
dependencies: dependencies:
'@humanwhocodes/object-schema': 2.0.3 '@humanwhocodes/object-schema': 2.0.3
debug: 4.3.4 debug: 4.4.3
minimatch: 3.1.2 minimatch: 3.1.2
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -8656,7 +8632,7 @@ snapshots:
'@typescript-eslint/types': 8.46.2 '@typescript-eslint/types': 8.46.2
'@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3) '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.46.2 '@typescript-eslint/visitor-keys': 8.46.2
debug: 4.4.1 debug: 4.4.3
eslint: 8.57.1 eslint: 8.57.1
typescript: 5.9.3 typescript: 5.9.3
transitivePeerDependencies: transitivePeerDependencies:
@@ -8676,7 +8652,7 @@ snapshots:
dependencies: dependencies:
'@typescript-eslint/tsconfig-utils': 8.46.2(typescript@5.9.3) '@typescript-eslint/tsconfig-utils': 8.46.2(typescript@5.9.3)
'@typescript-eslint/types': 8.46.2 '@typescript-eslint/types': 8.46.2
debug: 4.4.1 debug: 4.4.3
typescript: 5.9.3 typescript: 5.9.3
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -8707,7 +8683,7 @@ snapshots:
'@typescript-eslint/types': 8.46.2 '@typescript-eslint/types': 8.46.2
'@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3) '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3)
'@typescript-eslint/utils': 8.46.2(eslint@8.57.1)(typescript@5.9.3) '@typescript-eslint/utils': 8.46.2(eslint@8.57.1)(typescript@5.9.3)
debug: 4.4.1 debug: 4.4.3
eslint: 8.57.1 eslint: 8.57.1
ts-api-utils: 2.1.0(typescript@5.9.3) ts-api-utils: 2.1.0(typescript@5.9.3)
typescript: 5.9.3 typescript: 5.9.3
@@ -8742,7 +8718,7 @@ snapshots:
'@typescript-eslint/tsconfig-utils': 8.46.2(typescript@5.9.3) '@typescript-eslint/tsconfig-utils': 8.46.2(typescript@5.9.3)
'@typescript-eslint/types': 8.46.2 '@typescript-eslint/types': 8.46.2
'@typescript-eslint/visitor-keys': 8.46.2 '@typescript-eslint/visitor-keys': 8.46.2
debug: 4.4.1 debug: 4.4.3
fast-glob: 3.3.3 fast-glob: 3.3.3
is-glob: 4.0.3 is-glob: 4.0.3
minimatch: 9.0.5 minimatch: 9.0.5
@@ -9542,6 +9518,8 @@ snapshots:
dependencies: dependencies:
delayed-stream: 1.0.0 delayed-stream: 1.0.0
comlink@4.4.2: {}
commander@2.20.3: {} commander@2.20.3: {}
commander@7.2.0: {} commander@7.2.0: {}
@@ -9836,10 +9814,6 @@ snapshots:
dependencies: dependencies:
ms: 2.1.3 ms: 2.1.3
debug@4.3.4:
dependencies:
ms: 2.1.2
debug@4.4.1: debug@4.4.1:
dependencies: dependencies:
ms: 2.1.3 ms: 2.1.3
@@ -10155,8 +10129,8 @@ snapshots:
eslint@8.57.1: eslint@8.57.1:
dependencies: dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1) '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.1)
'@eslint-community/regexpp': 4.6.2 '@eslint-community/regexpp': 4.12.1
'@eslint/eslintrc': 2.1.4 '@eslint/eslintrc': 2.1.4
'@eslint/js': 8.57.1 '@eslint/js': 8.57.1
'@humanwhocodes/config-array': 0.13.0 '@humanwhocodes/config-array': 0.13.0
@@ -10165,8 +10139,8 @@ snapshots:
'@ungap/structured-clone': 1.2.0 '@ungap/structured-clone': 1.2.0
ajv: 6.12.6 ajv: 6.12.6
chalk: 4.1.2 chalk: 4.1.2
cross-spawn: 7.0.3 cross-spawn: 7.0.6
debug: 4.3.4 debug: 4.4.3
doctrine: 3.0.0 doctrine: 3.0.0
escape-string-regexp: 4.0.0 escape-string-regexp: 4.0.0
eslint-scope: 7.2.2 eslint-scope: 7.2.2
@@ -11745,8 +11719,6 @@ snapshots:
ms@2.0.0: {} ms@2.0.0: {}
ms@2.1.2: {}
ms@2.1.3: {} ms@2.1.3: {}
multiformats@9.9.0: {} multiformats@9.9.0: {}

View File

@@ -1,166 +1,31 @@
import { wrap } from "comlink"
import { nanoid } from "nanoid" import { nanoid } from "nanoid"
import indexedDb from "pouchdb-adapter-indexeddb"
import PouchDb from "pouchdb-browser"
import { DataType } from "./DataType.enum" import { DataType } from "./DataType.enum"
import { Model } from "./models/Model" import { Model } from "./models/Model"
PouchDb.plugin(indexedDb) export interface DataApi {
add<DT extends DataType>(model: Model<DT>): Promise<boolean>
interface GetAllParams { update<DT extends DataType, T extends Model<DT>>(model: T): Promise<boolean>
remove(id: string): Promise<boolean>
get<DT extends DataType, T extends Model<DT>>(id: string): Promise<T | null>
getOrCreate<DT extends DataType, T extends Model<DT>>(
id: string,
initialValue: T
): Promise<T>
getAll<DT extends DataType, T extends Model<DT>>(params: {
prefix?: string prefix?: string
includeDocs?: boolean includeDocs?: boolean
includeAttachments?: boolean includeAttachments?: boolean
keys?: string[] keys?: string[]
}): Promise<T[]>
} }
class Data { export const generateId = (type?: DataType | string, id?: string): string => {
// oxlint-disable-next-line typescript/ban-types if (!type) return id || nanoid()
private readonly locale: PouchDB.Database<{}> | null = null
constructor() {
try {
this.locale = new PouchDb("remanso", {
adapter: "indexeddb"
})
} catch (error) {
console.warn("data error", error)
}
}
public async add<DT extends DataType>(model: Model<DT>): Promise<boolean> {
try {
const result = await this.locale?.put(model)
return result?.ok ?? false
} catch (error) {
console.warn(error)
return false
}
}
public async update<DT extends DataType, T extends Model<DT>>(
model: T
): Promise<boolean> {
try {
if (!model._id) {
const result = await this.locale?.put(model)
return result?.ok ?? false
}
const oldModel = await this.get(model._id)
if (oldModel) {
const result = await this.locale?.put({ ...oldModel, ...model })
return result?.ok ?? false
}
const result = await this.locale?.put(model)
return result?.ok ?? false
} catch (error) {
console.warn(error)
return false
}
}
public async remove(id: string): Promise<boolean> {
try {
const doc = await this.get(id)
if (!doc) {
return false
}
const result = await this.locale?.put({
...doc,
_deleted: true
})
return result?.ok ?? false
} catch {
return false
}
}
public async get<DT extends DataType, T extends Model<DT>>(
id: string
): Promise<T | null> {
try {
return ((await this.locale?.get(id)) as T) || null
} catch {
return null
}
}
public async getOrCreate<DT extends DataType, T extends Model<DT>>(
id: string,
initialValue: T
): Promise<T> {
const element = await this.get<DT, T>(id)
if (element) {
return element
}
await data.add<DT>({ ...initialValue, _id: id })
return this.getOrCreate(id, initialValue)
}
public async getAll<DT extends DataType, T extends Model<DT>>({
prefix,
includeDocs = true,
includeAttachments = false,
keys = []
}: GetAllParams): Promise<T[]> {
if (!this.locale) {
return []
}
if (keys.length) {
const response = await this.locale.allDocs({
include_docs: includeDocs,
attachments: includeAttachments,
keys: keys.map((key) => this.generateId(prefix, key))
})
if (includeDocs) {
return response.rows
.map((row) => {
if ("error" in row) {
return null
}
return row.doc
})
.filter(Boolean) as T[]
} else {
return response.rows
.map((row) => {
if ("error" in row) {
return null
}
return { _id: row.id }
})
.filter(Boolean) as T[]
}
}
const response = await this.locale.allDocs({
include_docs: includeDocs,
attachments: includeAttachments,
startkey: prefix ? prefix : undefined,
endkey: prefix ? `${prefix}\ufff0` : undefined
})
return response.rows.map((row) => row.doc) as T[]
}
public generateId(type?: DataType | string, id?: string) {
if (!type) {
return id || nanoid()
}
return `${type}-${id || nanoid()}` return `${type}-${id || nanoid()}`
} }
}
export const data = new Data() import DataWorker from "./data.worker?worker"
export const data = wrap(new DataWorker()) as unknown as DataApi

156
src/data/data.worker.ts Normal file
View File

@@ -0,0 +1,156 @@
import { expose } from "comlink"
import { nanoid } from "nanoid"
import indexedDb from "pouchdb-adapter-indexeddb"
import PouchDb from "pouchdb-browser"
import { DataType } from "./DataType.enum"
import { Model } from "./models/Model"
PouchDb.plugin(indexedDb)
interface GetAllParams {
prefix?: string
includeDocs?: boolean
includeAttachments?: boolean
keys?: string[]
}
class Data {
// oxlint-disable-next-line typescript/ban-types
private readonly locale: PouchDB.Database<{}> | null = null
constructor() {
try {
this.locale = new PouchDb("remanso", {
adapter: "indexeddb"
})
} catch (error) {
console.warn("data error", error)
}
}
private buildId(type?: DataType | string, id?: string): string {
if (!type) return id || nanoid()
return `${type}-${id || nanoid()}`
}
public async add<DT extends DataType>(model: Model<DT>): Promise<boolean> {
try {
const result = await this.locale?.put(model)
return result?.ok ?? false
} catch (error) {
console.warn(error)
return false
}
}
public async update<DT extends DataType, T extends Model<DT>>(
model: T
): Promise<boolean> {
try {
if (!model._id) {
const result = await this.locale?.put(model)
return result?.ok ?? false
}
const oldModel = await this.get(model._id)
if (oldModel) {
const result = await this.locale?.put({ ...oldModel, ...model })
return result?.ok ?? false
}
const result = await this.locale?.put(model)
return result?.ok ?? false
} catch (error) {
console.warn(error)
return false
}
}
public async remove(id: string): Promise<boolean> {
try {
const doc = await this.get(id)
if (!doc) {
return false
}
const result = await this.locale?.put({
...doc,
_deleted: true
})
return result?.ok ?? false
} catch {
return false
}
}
public async get<DT extends DataType, T extends Model<DT>>(
id: string
): Promise<T | null> {
try {
return ((await this.locale?.get(id)) as T) || null
} catch {
return null
}
}
public async getOrCreate<DT extends DataType, T extends Model<DT>>(
id: string,
initialValue: T
): Promise<T> {
const element = await this.get<DT, T>(id)
if (element) {
return element
}
await this.add<DT>({ ...initialValue, _id: id })
return this.getOrCreate(id, initialValue)
}
public async getAll<DT extends DataType, T extends Model<DT>>({
prefix,
includeDocs = true,
includeAttachments = false,
keys = []
}: GetAllParams): Promise<T[]> {
if (!this.locale) {
return []
}
if (keys.length) {
const response = await this.locale.allDocs({
include_docs: includeDocs,
attachments: includeAttachments,
keys: keys.map((key) => this.buildId(prefix, key))
})
if (includeDocs) {
return response.rows
.map((row) => {
if ("error" in row) return null
return row.doc
})
.filter(Boolean) as T[]
} else {
return response.rows
.map((row) => {
if ("error" in row) return null
return { _id: row.id }
})
.filter(Boolean) as T[]
}
}
const response = await this.locale.allDocs({
include_docs: includeDocs,
attachments: includeAttachments,
startkey: prefix ? prefix : undefined,
endkey: prefix ? `${prefix}\ufff0` : undefined
})
return response.rows.map((row) => row.doc) as T[]
}
}
expose(new Data())

View File

@@ -2,7 +2,7 @@ import { useAsyncState } from "@vueuse/core"
import { ComputedRef, onUnmounted, toValue } from "vue" import { ComputedRef, onUnmounted, toValue } from "vue"
import { backlinkEventBus } from "@/bus/backlinkEventBus" import { backlinkEventBus } from "@/bus/backlinkEventBus"
import { data } from "@/data/data" import { data, generateId } from "@/data/data"
import { DataType } from "@/data/DataType.enum" import { DataType } from "@/data/DataType.enum"
import { BacklinkNote } from "@/modules/note/models/BacklinkNote" import { BacklinkNote } from "@/modules/note/models/BacklinkNote"
@@ -11,7 +11,7 @@ export const useBacklinks = (sha: string | ComputedRef<string>) => {
const { state: backlink, execute } = useAsyncState( const { state: backlink, execute } = useAsyncState(
data.get<DataType.BacklinkNote, BacklinkNote>( data.get<DataType.BacklinkNote, BacklinkNote>(
data.generateId(DataType.BacklinkNote, sha) generateId(DataType.BacklinkNote, sha)
), ),
null, null,
{ {

View File

@@ -1,7 +1,7 @@
import { watch } from "vue" import { watch } from "vue"
import { backlinkEventBus } from "@/bus/backlinkEventBus" import { backlinkEventBus } from "@/bus/backlinkEventBus"
import { data } from "@/data/data" import { data, generateId } from "@/data/data"
import { DataType } from "@/data/DataType.enum" import { DataType } from "@/data/DataType.enum"
import { useFile } from "@/hooks/useFile.hook" import { useFile } from "@/hooks/useFile.hook"
import { Backlink } from "@/modules/note/models/Backlink" import { Backlink } from "@/modules/note/models/Backlink"
@@ -42,7 +42,7 @@ export const useComputeBacklinks = () => {
continue continue
} }
const fileBacklinkId = data.generateId(DataType.BacklinkNote, file.sha) const fileBacklinkId = generateId(DataType.BacklinkNote, file.sha)
const fileBacklink = await data.get<DataType.BacklinkNote, BacklinkNote>( const fileBacklink = await data.get<DataType.BacklinkNote, BacklinkNote>(
fileBacklinkId fileBacklinkId
) )
@@ -102,7 +102,7 @@ export const useComputeBacklinks = () => {
} }
for (const [sha, fileBacklinks] of backlinks) { for (const [sha, fileBacklinks] of backlinks) {
const fileBacklinkId = data.generateId(DataType.BacklinkNote, sha) const fileBacklinkId = generateId(DataType.BacklinkNote, sha)
const backlinkNote: BacklinkNote = { const backlinkNote: BacklinkNote = {
_id: fileBacklinkId, _id: fileBacklinkId,
$type: DataType.BacklinkNote, $type: DataType.BacklinkNote,

View File

@@ -1,7 +1,7 @@
import { useAsyncState } from "@vueuse/core" import { useAsyncState } from "@vueuse/core"
import { computed, ref } from "vue" import { computed, ref } from "vue"
import { data } from "@/data/data" import { data, generateId } from "@/data/data"
import { DataType } from "@/data/DataType.enum" import { DataType } from "@/data/DataType.enum"
import { prepareNoteCache } from "@/modules/note/cache/prepareNoteCache" import { prepareNoteCache } from "@/modules/note/cache/prepareNoteCache"
import { Note } from "@/modules/note/models/Note" import { Note } from "@/modules/note/models/Note"
@@ -36,7 +36,7 @@ export const useOfflineNotes = () => {
if ( if (
!file.sha || !file.sha ||
cachedNotesSet.has(data.generateId(DataType.Note, file.sha)) cachedNotesSet.has(generateId(DataType.Note, file.sha))
) { ) {
continue continue
} }

View File

@@ -4,7 +4,7 @@ import { useAsyncState } from "@vueuse/core"
import { addDays, isAfter } from "date-fns" import { addDays, isAfter } from "date-fns"
import { computed, nextTick, watch } from "vue" import { computed, nextTick, watch } from "vue"
import { data } from "@/data/data" import { data, generateId } from "@/data/data"
import { DataType } from "@/data/DataType.enum" import { DataType } from "@/data/DataType.enum"
import { useFile } from "@/hooks/useFile.hook" import { useFile } from "@/hooks/useFile.hook"
import { useLinks } from "@/hooks/useLinks.hook" import { useLinks } from "@/hooks/useLinks.hook"
@@ -51,7 +51,7 @@ export const useSpacedRepetitionCards = () => {
const repetition = await data.getOrCreate< const repetition = await data.getOrCreate<
DataType.RepetitionCard, DataType.RepetitionCard,
RepetitionCard RepetitionCard
>(data.generateId(DataType.RepetitionCard, cardFile.path), { >(generateId(DataType.RepetitionCard, cardFile.path), {
$type: DataType.RepetitionCard, $type: DataType.RepetitionCard,
level: 1, level: 1,
repeatDate: new Date(), repeatDate: new Date(),

View File

@@ -1,17 +1,17 @@
import { useAsyncState } from "@vueuse/core" import { useAsyncState } from "@vueuse/core"
import { computed } from "vue" import { computed } from "vue"
import { data } from "@/data/data" import { data, generateId } from "@/data/data"
import { DataType } from "@/data/DataType.enum" import { DataType } from "@/data/DataType.enum"
import { History } from "@/data/models/History" import { History } from "@/data/models/History"
const HISTORY_ID = data.generateId(DataType.History, "history") const HISTORY_ID = generateId(DataType.History, "history")
export const useLastVisitedRepos = () => { export const useLastVisitedRepos = () => {
const history = useAsyncState( const history = useAsyncState(
() => () =>
data.get<DataType.History, History>( data.get<DataType.History, History>(
data.generateId(DataType.History, "history") generateId(DataType.History, "history")
), ),
null null
) )

View File

@@ -1,10 +1,10 @@
import { Ref, toValue } from "vue" import { Ref, toValue } from "vue"
import { data } from "@/data/data" import { data, generateId } from "@/data/data"
import { DataType } from "@/data/DataType.enum" import { DataType } from "@/data/DataType.enum"
import { History } from "@/data/models/History" import { History } from "@/data/models/History"
const HISTORY_ID = data.generateId(DataType.History, "history") const HISTORY_ID = generateId(DataType.History, "history")
const MAX_REPO_HISTORY = 10 const MAX_REPO_HISTORY = 10
export const useVisitRepo = (newRepo: { export const useVisitRepo = (newRepo: {

View File

@@ -1,4 +1,4 @@
import { data } from "@/data/data" import { data, generateId } from "@/data/data"
import { DataType } from "@/data/DataType.enum" import { DataType } from "@/data/DataType.enum"
import { Note } from "@/modules/note/models/Note" import { Note } from "@/modules/note/models/Note"
import { useUserRepoStore } from "@/modules/repo/store/userRepo.store" import { useUserRepoStore } from "@/modules/repo/store/userRepo.store"
@@ -14,8 +14,8 @@ type NoteCacheResult =
export const prepareNoteCache = (sha: string, path?: string) => { export const prepareNoteCache = (sha: string, path?: string) => {
const store = useUserRepoStore() const store = useUserRepoStore()
const noteId = data.generateId(DataType.Note, sha) const noteId = generateId(DataType.Note, sha)
const notePath = path ? data.generateId(DataType.Note, path) : null const notePath = path ? generateId(DataType.Note, path) : null
const getCachedNote = async (): Promise<NoteCacheResult> => { const getCachedNote = async (): Promise<NoteCacheResult> => {
const note = await data.get<DataType.Note, Note>(noteId) const note = await data.get<DataType.Note, Note>(noteId)

View File

@@ -1,6 +1,6 @@
import { computed, onMounted, ref } from "vue" import { computed, onMounted, ref } from "vue"
import { data } from "@/data/data" import { data, generateId } from "@/data/data"
import { DataType } from "@/data/DataType.enum" import { DataType } from "@/data/DataType.enum"
import { useRepos } from "@/hooks/useRepos.hook" import { useRepos } from "@/hooks/useRepos.hook"
import { RepoBase } from "@/modules/repo/interfaces/RepoBase" import { RepoBase } from "@/modules/repo/interfaces/RepoBase"
@@ -27,7 +27,7 @@ export const useFavoriteRepos = () => {
const toggleFavorite = async (repo: RepoBase, isFavorite: boolean) => { const toggleFavorite = async (repo: RepoBase, isFavorite: boolean) => {
const favorite: FavoriteRepo = { const favorite: FavoriteRepo = {
_id: data.generateId(DataType.FavoriteRepo, repo.id), _id: generateId(DataType.FavoriteRepo, repo.id),
$type: DataType.FavoriteRepo, $type: DataType.FavoriteRepo,
isFavorite, isFavorite,
name: repo.name, name: repo.name,

View File

@@ -1,6 +1,6 @@
import { defineStore } from "pinia" import { defineStore } from "pinia"
import { data } from "@/data/data" import { data, generateId } from "@/data/data"
import { DataType } from "@/data/DataType.enum" import { DataType } from "@/data/DataType.enum"
import { RepoFile } from "@/modules/repo/interfaces/RepoFile" import { RepoFile } from "@/modules/repo/interfaces/RepoFile"
import { UserSettings } from "@/modules/repo/interfaces/UserSettings" import { UserSettings } from "@/modules/repo/interfaces/UserSettings"
@@ -39,7 +39,7 @@ export const useUserRepoStore = defineStore("USER_REPO_STATE", {
this.user = user this.user = user
this.repo = repo this.repo = repo
const savedRepoId = data.generateId(DataType.SavedRepo, `${user}-${repo}`) const savedRepoId = generateId(DataType.SavedRepo, `${user}-${repo}`)
const userSettingsId = `UserSetting-${user}-${repo}` const userSettingsId = `UserSetting-${user}-${repo}`
const [cachedSavedRepo, cachedUserSettings] = await Promise.all([ const [cachedSavedRepo, cachedUserSettings] = await Promise.all([
@@ -131,7 +131,7 @@ export const useUserRepoStore = defineStore("USER_REPO_STATE", {
return return
} }
const savedRepoId = data.generateId( const savedRepoId = generateId(
DataType.SavedRepo, DataType.SavedRepo,
`${this.user}-${this.repo}` `${this.user}-${this.repo}`
) )

View File

@@ -1,7 +1,7 @@
import { Octokit } from "@octokit/rest" import { Octokit } from "@octokit/rest"
import { addMinutes, addSeconds, isBefore } from "date-fns" import { addMinutes, addSeconds, isBefore } from "date-fns"
import { data } from "@/data/data" import { data, generateId } from "@/data/data"
import { DataType } from "@/data/DataType.enum" import { DataType } from "@/data/DataType.enum"
import { GithubAccessToken } from "@/data/models/GithubAccessToken" import { GithubAccessToken } from "@/data/models/GithubAccessToken"
import { GithubToken } from "@/modules/user/interfaces/GithubToken" import { GithubToken } from "@/modules/user/interfaces/GithubToken"
@@ -26,7 +26,7 @@ export const needToRefreshToken = async () => {
const accessToken = await data.get< const accessToken = await data.get<
DataType.GithubAccessToken, DataType.GithubAccessToken,
GithubAccessToken GithubAccessToken
>(data.generateId(DataType.GithubAccessToken, personalTokenId)) >(generateId(DataType.GithubAccessToken, personalTokenId))
if (!accessToken) { if (!accessToken) {
return false return false
@@ -42,7 +42,7 @@ export const refreshToken = async () => {
const accessToken = await data.get< const accessToken = await data.get<
DataType.GithubAccessToken, DataType.GithubAccessToken,
GithubAccessToken GithubAccessToken
>(data.generateId(DataType.GithubAccessToken, personalTokenId)) >(generateId(DataType.GithubAccessToken, personalTokenId))
if (!accessToken) { if (!accessToken) {
return null return null
@@ -74,7 +74,7 @@ export const getAccessToken = async () => {
const response = await data.get< const response = await data.get<
DataType.GithubAccessToken, DataType.GithubAccessToken,
GithubAccessToken GithubAccessToken
>(data.generateId(DataType.GithubAccessToken, personalTokenId)) >(generateId(DataType.GithubAccessToken, personalTokenId))
return response return response
} }
@@ -94,7 +94,7 @@ export const saveAccessToken = async (githubToken: GithubToken) => {
const accessToken: GithubAccessToken = { const accessToken: GithubAccessToken = {
...actualPAT, ...actualPAT,
_id: data.generateId(DataType.GithubAccessToken, personalTokenId), _id: generateId(DataType.GithubAccessToken, personalTokenId),
$type: DataType.GithubAccessToken, $type: DataType.GithubAccessToken,
token: githubToken.access_token, token: githubToken.access_token,
expiresIn: githubToken.expires_in, expiresIn: githubToken.expires_in,