fix: replace ESM store with native json-store and package Windows desktop build
This commit is contained in:
parent
2c0b0ffc89
commit
d4eda5f36e
@ -115,7 +115,17 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## H. Instructions for the Next AI Agent
|
## H. Important Decisions
|
||||||
|
|
||||||
|
| Decision | Reason | Alternatives Rejected |
|
||||||
|
|---|---|---|
|
||||||
|
| Native JSON store (`JsonStore`) over `electron-store` | `electron-store` v10 is pure ESM causing `ERR_REQUIRE_ESM` in Electron CJS main bundle; native `fs` JSON store has 0 external dependencies and 100% synchronous stability | `electron-store` v10 (rejected: ESM runtime collision) |
|
||||||
|
| Atomic JSON store over `better-sqlite3` | Eliminates requirement for Visual Studio C++ compilers and node-gyp native compilation on target user PCs | `better-sqlite3` (rejected: requires C++ build tools) |
|
||||||
|
| electron-vite over vanilla Vite | Direct Electron HMR and optimized dual-bundle build pipeline | Custom webpack, Create React App |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## I. Instructions for the Next AI Agent
|
||||||
|
|
||||||
1. **Read `PROJECT_STATE.md` completely before making changes.**
|
1. **Read `PROJECT_STATE.md` completely before making changes.**
|
||||||
2. **Read `DESIGN.md` before modifying any UI.** Adhere strictly to the Axiom design system.
|
2. **Read `DESIGN.md` before modifying any UI.** Adhere strictly to the Axiom design system.
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import Store from 'electron-store'
|
import { JsonStore } from './json-store'
|
||||||
import { createLogger } from '../logger'
|
import { createLogger } from '../logger'
|
||||||
import type { Repository } from '../../shared/types/git.types'
|
import type { Repository } from '../../shared/types/git.types'
|
||||||
|
|
||||||
@ -10,18 +10,14 @@ interface DatabaseSchema {
|
|||||||
graphLayout: Record<string, { x: number; y: number }>
|
graphLayout: Record<string, { x: number; y: number }>
|
||||||
}
|
}
|
||||||
|
|
||||||
let store: Store<DatabaseSchema> | null = null
|
let store: JsonStore<DatabaseSchema> | null = null
|
||||||
|
|
||||||
export function getDb(): Store<DatabaseSchema> {
|
export function getDb(): JsonStore<DatabaseSchema> {
|
||||||
if (!store) {
|
if (!store) {
|
||||||
store = new Store<DatabaseSchema>({
|
store = new JsonStore<DatabaseSchema>('flowgit-data', {
|
||||||
name: 'flowgit-data',
|
repositories: [],
|
||||||
defaults: {
|
uiState: {},
|
||||||
repositories: [],
|
graphLayout: {},
|
||||||
uiState: {},
|
|
||||||
graphLayout: {},
|
|
||||||
},
|
|
||||||
clearInvalidConfig: true,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return store
|
return store
|
||||||
@ -47,7 +43,7 @@ export function getRepository(id: string): Repository | null {
|
|||||||
|
|
||||||
export function upsertRepository(repo: Omit<Repository, 'remotes'>): void {
|
export function upsertRepository(repo: Omit<Repository, 'remotes'>): void {
|
||||||
const db = getDb()
|
const db = getDb()
|
||||||
const repos = db.get('repositories') ?? []
|
const repos = [...(db.get('repositories') ?? [])]
|
||||||
const existingIndex = repos.findIndex(r => r.id === repo.id || r.path === repo.path)
|
const existingIndex = repos.findIndex(r => r.id === repo.id || r.path === repo.path)
|
||||||
|
|
||||||
const fullRepo: Repository = {
|
const fullRepo: Repository = {
|
||||||
@ -78,7 +74,7 @@ export function removeRepository(id: string): void {
|
|||||||
|
|
||||||
export function pinRepository(id: string, pinned: boolean): void {
|
export function pinRepository(id: string, pinned: boolean): void {
|
||||||
const db = getDb()
|
const db = getDb()
|
||||||
const repos = db.get('repositories') ?? []
|
const repos = [...(db.get('repositories') ?? [])]
|
||||||
const repo = repos.find(r => r.id === id)
|
const repo = repos.find(r => r.id === id)
|
||||||
if (repo) {
|
if (repo) {
|
||||||
repo.isPinned = pinned
|
repo.isPinned = pinned
|
||||||
@ -95,7 +91,7 @@ export function getUiState(key: string): string | null {
|
|||||||
|
|
||||||
export function setUiState(key: string, value: string): void {
|
export function setUiState(key: string, value: string): void {
|
||||||
const db = getDb()
|
const db = getDb()
|
||||||
const state = db.get('uiState') ?? {}
|
const state = { ...(db.get('uiState') ?? {}) }
|
||||||
state[key] = value
|
state[key] = value
|
||||||
db.set('uiState', state)
|
db.set('uiState', state)
|
||||||
}
|
}
|
||||||
|
|||||||
52
electron/persistence/json-store.ts
Normal file
52
electron/persistence/json-store.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { app } from 'electron'
|
||||||
|
import { join } from 'path'
|
||||||
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs'
|
||||||
|
|
||||||
|
export class JsonStore<T extends object> {
|
||||||
|
private filePath: string
|
||||||
|
private data: T
|
||||||
|
|
||||||
|
constructor(name: string, defaults: T) {
|
||||||
|
let dir = ''
|
||||||
|
try {
|
||||||
|
dir = app.getPath('userData')
|
||||||
|
} catch {
|
||||||
|
dir = join(process.cwd(), '.flowgit-data')
|
||||||
|
}
|
||||||
|
mkdirSync(dir, { recursive: true })
|
||||||
|
this.filePath = join(dir, `${name}.json`)
|
||||||
|
|
||||||
|
if (existsSync(this.filePath)) {
|
||||||
|
try {
|
||||||
|
const raw = readFileSync(this.filePath, 'utf8')
|
||||||
|
this.data = { ...defaults, ...JSON.parse(raw) }
|
||||||
|
} catch {
|
||||||
|
this.data = { ...defaults }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.data = { ...defaults }
|
||||||
|
this.save()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get<K extends keyof T>(key: K): T[K] {
|
||||||
|
return this.data[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
set<K extends keyof T>(key: K, value: T[K]): void {
|
||||||
|
this.data[key] = value
|
||||||
|
this.save()
|
||||||
|
}
|
||||||
|
|
||||||
|
getAll(): T {
|
||||||
|
return { ...this.data }
|
||||||
|
}
|
||||||
|
|
||||||
|
private save(): void {
|
||||||
|
try {
|
||||||
|
writeFileSync(this.filePath, JSON.stringify(this.data, null, 2), 'utf8')
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Failed to write store to ${this.filePath}:`, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import Store from 'electron-store'
|
import { JsonStore } from '../persistence/json-store'
|
||||||
import type { AppSettings } from '../../shared/types/ipc.types'
|
import type { AppSettings } from '../../shared/types/ipc.types'
|
||||||
|
|
||||||
const defaults: AppSettings = {
|
const defaults: AppSettings = {
|
||||||
@ -14,20 +14,23 @@ const defaults: AppSettings = {
|
|||||||
confirmDestructive: true,
|
confirmDestructive: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
const store = new Store<AppSettings>({
|
let store: JsonStore<AppSettings> | null = null
|
||||||
name: 'settings',
|
|
||||||
defaults,
|
function getStore(): JsonStore<AppSettings> {
|
||||||
clearInvalidConfig: true,
|
if (!store) {
|
||||||
})
|
store = new JsonStore<AppSettings>('settings', defaults)
|
||||||
|
}
|
||||||
|
return store
|
||||||
|
}
|
||||||
|
|
||||||
export function getSettings(): AppSettings {
|
export function getSettings(): AppSettings {
|
||||||
return store.store
|
return getStore().getAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getSetting<K extends keyof AppSettings>(key: K): AppSettings[K] {
|
export function getSetting<K extends keyof AppSettings>(key: K): AppSettings[K] {
|
||||||
return store.get(key)
|
return getStore().get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setSetting<K extends keyof AppSettings>(key: K, value: AppSettings[K]): void {
|
export function setSetting<K extends keyof AppSettings>(key: K, value: AppSettings[K]): void {
|
||||||
store.set(key, value)
|
getStore().set(key, value)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,9 +17,7 @@
|
|||||||
"dist": "npm run build && electron-builder",
|
"dist": "npm run build && electron-builder",
|
||||||
"dist:dir": "npm run build && electron-builder --dir"
|
"dist:dir": "npm run build && electron-builder --dir"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {},
|
||||||
"electron-store": "^10.0.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@electron-toolkit/preload": "^3.0.1",
|
"@electron-toolkit/preload": "^3.0.1",
|
||||||
"@electron-toolkit/utils": "^3.0.0",
|
"@electron-toolkit/utils": "^3.0.0",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user