Skip to content

Commit f6583b7

Browse files
fix(elysia): prevent DB hangs during saves (#643)
* feat(api): refactor error handling to use status responses and dynamic import for ESM compatibility * feat(deps): update @elysiajs/swagger to v1.3.1 and add @sinclair/typebox v0.34.41 * fix(api): add explicit return type for '/tree' route handler * feat(api): regenerate
1 parent 6b94af5 commit f6583b7

File tree

9 files changed

+223
-267
lines changed

9 files changed

+223
-267
lines changed

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@
4141
"dependencies": {
4242
"@dagrejs/dagre": "^1.1.5",
4343
"@elysiajs/cors": "^1.2.0",
44-
"@elysiajs/node": "^1.2.5",
45-
"@elysiajs/swagger": "^1.2.2",
44+
"@elysiajs/node": "^1.4.2",
45+
"@elysiajs/swagger": "^1.3.1",
46+
"@sinclair/typebox": "^0.34.41",
4647
"@vue-flow/background": "^1.3.2",
4748
"@vue-flow/controls": "^1.1.3",
4849
"@vue-flow/core": "^1.46.5",
@@ -60,7 +61,7 @@
6061
"date-fns": "^4.1.0",
6162
"dom-to-image": "^2.6.0",
6263
"electron-store": "^8.2.0",
63-
"elysia": "^1.2.15",
64+
"elysia": "^1.4.16",
6465
"fs-extra": "^11.3.0",
6566
"i18next": "^24.2.2",
6667
"i18next-fs-backend": "^2.6.0",

pnpm-lock.yaml

Lines changed: 157 additions & 84 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main/api/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
import { cors } from '@elysiajs/cors'
2-
import { node } from '@elysiajs/node'
32
import { swagger } from '@elysiajs/swagger'
43
import { app as electronApp } from 'electron'
54
import { Elysia } from 'elysia'
65
import { store } from '../store'
6+
import { importEsm } from '../utils'
77
import folders from './routes/folders'
88
import snippets from './routes/snippets'
99
import tags from './routes/tags'
1010

11-
export function initApi() {
11+
export async function initApi() {
12+
// поскольку @elysiajs/node использует crossws, который работает только в ESM среде,
13+
// то делаем хак с динамическим импортом
14+
const { node } = await importEsm('@elysiajs/node')
15+
1216
const app = new Elysia({ adapter: node() })
1317
const port = store.preferences.get('apiPort')
1418

src/main/api/routes/folders.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ app
4242
// Получение папок в виде древовидной структуры
4343
.get(
4444
'/tree',
45-
() => {
45+
(): any => {
4646
const db = useDB()
4747
const allFolders = db
4848
.prepare(
@@ -141,7 +141,7 @@ app
141141
// Обновление папки
142142
.patch(
143143
'/:id',
144-
({ params, body, error }) => {
144+
({ params, body, status }) => {
145145
const db = useDB()
146146
const { id } = params
147147
const now = Date.now()
@@ -187,7 +187,7 @@ app
187187
}
188188

189189
if (updateFields.length === 0) {
190-
return error(400, { message: 'Need at least one field to update' })
190+
return status(400, { message: 'Need at least one field to update' })
191191
}
192192

193193
updateFields.push('updatedAt = ?')
@@ -204,7 +204,7 @@ app
204204
| undefined
205205

206206
if (!folder) {
207-
return error(404, { message: 'Folder not found' })
207+
return status(404, { message: 'Folder not found' })
208208
}
209209

210210
// Обновляем порядок, только если изменился родитель или индекс
@@ -301,7 +301,7 @@ app
301301
// Удаление папки
302302
.delete(
303303
'/:id',
304-
({ params, error }) => {
304+
({ params, status }) => {
305305
const db = useDB()
306306
const { id } = params
307307

@@ -314,7 +314,7 @@ app
314314
.get(id)
315315

316316
if (!folder) {
317-
return error(404, { message: 'Folder not found' })
317+
return status(404, { message: 'Folder not found' })
318318
}
319319

320320
const transaction = db.transaction(() => {

src/main/api/routes/snippets.ts

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ app
231231
// Обновление сниппета
232232
.patch(
233233
'/:id',
234-
({ params, body, error }) => {
234+
({ params, body, status }) => {
235235
const db = useDB()
236236
const { id } = params
237237

@@ -264,7 +264,7 @@ app
264264
}
265265

266266
if (updateFields.length === 0) {
267-
return error(400, { message: 'Need at least one field to update' })
267+
return status(400, { message: 'Need at least one field to update' })
268268
}
269269

270270
updateFields.push('updatedAt = ?')
@@ -283,7 +283,7 @@ app
283283
const result = stmt.run(...updateParams)
284284

285285
if (!result.changes) {
286-
return error(404, { message: 'Snippet not found' })
286+
return status(404, { message: 'Snippet not found' })
287287
}
288288

289289
return { message: 'Snippet updated' }
@@ -298,7 +298,7 @@ app
298298
// Обновление содержимого сниппета
299299
.patch(
300300
'/:id/contents/:contentId',
301-
({ params, body, error }) => {
301+
({ params, body, status }) => {
302302
const db = useDB()
303303
const { id, contentId } = params
304304

@@ -321,7 +321,7 @@ app
321321
}
322322

323323
if (updateFields.length === 0) {
324-
return error(400, { message: 'Need at least one field to update' })
324+
return status(400, { message: 'Need at least one field to update' })
325325
}
326326

327327
updateParams.push(contentId)
@@ -335,7 +335,7 @@ app
335335
const contentsResult = contentsStmt.run(...updateParams)
336336

337337
if (!contentsResult.changes) {
338-
return error(404, { message: 'Snippet content not found' })
338+
return status(404, { message: 'Snippet content not found' })
339339
}
340340

341341
// Обновляем дату сниппета только если были реальные изменения в данных
@@ -348,7 +348,7 @@ app
348348
const snippetResult = snippetsStmt.run(now, id)
349349

350350
if (!snippetResult.changes) {
351-
return error(404, { message: 'Snippet not found' })
351+
return status(404, { message: 'Snippet not found' })
352352
}
353353
}
354354

@@ -364,7 +364,7 @@ app
364364
// Добавление тега к сниппету
365365
.post(
366366
'/:id/tags/:tagId',
367-
({ params, error }) => {
367+
({ params, status }) => {
368368
const db = useDB()
369369
const { id, tagId } = params
370370

@@ -378,7 +378,7 @@ app
378378
.get(id)
379379

380380
if (!snippet) {
381-
return error(404, { message: 'Snippet not found' })
381+
return status(404, { message: 'Snippet not found' })
382382
}
383383

384384
// Проверяем, существует ли тег
@@ -391,7 +391,7 @@ app
391391
.get(tagId)
392392

393393
if (!tag) {
394-
return error(404, { message: 'Tag not found' })
394+
return status(404, { message: 'Tag not found' })
395395
}
396396

397397
// Добавляем связь между сниппетом и тегом
@@ -415,7 +415,7 @@ app
415415
// Удаление тега из сниппета
416416
.delete(
417417
'/:id/tags/:tagId',
418-
({ params, error }) => {
418+
({ params, status }) => {
419419
const db = useDB()
420420
const { id, tagId } = params
421421

@@ -429,7 +429,7 @@ app
429429
.get(id)
430430

431431
if (!snippet) {
432-
return error(404, { message: 'Snippet not found' })
432+
return status(404, { message: 'Snippet not found' })
433433
}
434434

435435
// Проверяем, существует ли тег
@@ -442,7 +442,7 @@ app
442442
.get(tagId)
443443

444444
if (!tag) {
445-
return error(404, { message: 'Tag not found' })
445+
return status(404, { message: 'Tag not found' })
446446
}
447447

448448
// Удаляем связь между сниппетом и тегом
@@ -456,7 +456,7 @@ app
456456
const result = stmt.run(id, tagId)
457457

458458
if (!result.changes) {
459-
return error(404, {
459+
return status(404, {
460460
message: 'Tag is not associated with this snippet',
461461
})
462462
}
@@ -472,7 +472,7 @@ app
472472
// Удаление сниппета
473473
.delete(
474474
'/:id',
475-
({ params, error }) => {
475+
({ params, status }) => {
476476
const db = useDB()
477477
const { id } = params
478478

@@ -485,7 +485,7 @@ app
485485
.get(id)
486486

487487
if (!snippet) {
488-
return error(404, { message: 'Snippet not found' })
488+
return status(404, { message: 'Snippet not found' })
489489
}
490490

491491
const transaction = db.transaction(() => {
@@ -524,7 +524,7 @@ app
524524
// Удаление всех сниппетов в корзине
525525
.delete(
526526
'/trash',
527-
({ error }) => {
527+
({ status }) => {
528528
const db = useDB()
529529
const deletedSnippets = db
530530
.prepare(
@@ -535,7 +535,7 @@ app
535535
.all() as { id: number }[]
536536

537537
if (deletedSnippets.length === 0) {
538-
return error(404, { message: 'No snippets in trash' })
538+
return status(404, { message: 'No snippets in trash' })
539539
}
540540

541541
const transaction = db.transaction(() => {
@@ -582,7 +582,7 @@ app
582582
// Удаление содержимого сниппета
583583
.delete(
584584
'/:id/contents/:contentId',
585-
({ params, error }) => {
585+
({ params, status }) => {
586586
const db = useDB()
587587
const { contentId } = params
588588

@@ -595,7 +595,7 @@ app
595595
.run(contentId)
596596

597597
if (!result.changes) {
598-
return error(404, { message: 'Snippet content not found' })
598+
return status(404, { message: 'Snippet content not found' })
599599
}
600600

601601
return { message: 'Snippet content deleted' }

src/main/api/routes/tags.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ app
4949
// Удаление тега и удаление его из всех сниппетов
5050
.delete(
5151
'/:id',
52-
({ params, error }) => {
52+
({ params, status }) => {
5353
const db = useDB()
5454
const tag = db
5555
.prepare(
@@ -60,7 +60,7 @@ app
6060
.get(params.id)
6161

6262
if (!tag) {
63-
return error(404, { message: 'Tag not found' })
63+
return status(404, { message: 'Tag not found' })
6464
}
6565

6666
const transaction = db.transaction(() => {

src/main/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ else {
9090
}
9191

9292
try {
93-
initApi()
93+
await initApi()
9494
}
9595
catch (error) {
9696
log('Error initializing API', error)

src/main/utils/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,8 @@ export function log(context: string, error: unknown): void {
1212
stack,
1313
})
1414
}
15+
16+
export function importEsm(specifier: string) {
17+
// eslint-disable-next-line no-new-func
18+
return new Function('s', 'return import(s)')(specifier) as Promise<any>
19+
}

0 commit comments

Comments
 (0)