Compare commits

...

25 Commits

Author SHA1 Message Date
renovate[bot]
00368fc131 fix(deps): update dependency node-html-parser to v7.1.0 2026-03-03 02:01:49 +00:00
Elian Doran
4c5aada5d3 chore(deps): update dependency @types/express-serve-static-core to v5.1.1 (#8346) 2026-03-02 22:42:10 +02:00
Elian Doran
05551cec9e chore(deps): update dependency sax to v1.5.0 (#8875) 2026-03-02 22:41:20 +02:00
Elian Doran
6300a8c8d1 chore(deps): update dependency @redocly/cli to v2.20.2 (#8853) 2026-03-02 22:34:22 +02:00
Elian Doran
ca4d15727d Merge branch 'main' into renovate/express-serve-static-core-5.x 2026-03-02 22:30:43 +02:00
renovate[bot]
2fe076086e chore(deps): update dependency sax to v1.5.0 2026-03-02 20:25:56 +00:00
Elian Doran
56b65ddfae Translations update from Hosted Weblate (#8870) 2026-03-02 22:22:37 +02:00
Hasan Kara
fcf6673825 Translated using Weblate (Turkish)
Currently translated at 16.3% (19 of 116 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/tr/
2026-03-02 20:54:15 +01:00
Hasan Kara
9eda264f52 Translated using Weblate (Turkish)
Currently translated at 5.1% (20 of 387 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/tr/
2026-03-02 20:54:14 +01:00
Hasan Kara
fe1270c679 Translated using Weblate (Turkish)
Currently translated at 4.2% (71 of 1675 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/tr/
2026-03-02 20:54:13 +01:00
Hasan Kara
679e1ac678 Translated using Weblate (Turkish)
Currently translated at 12.0% (19 of 158 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/tr/
2026-03-02 20:54:12 +01:00
ibs-allaow
e309ff2d17 Translated using Weblate (Arabic)
Currently translated at 100.0% (116 of 116 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/ar/
2026-03-02 20:54:12 +01:00
Francis C.
c910335155 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (1675 of 1675 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hant/
2026-03-02 20:54:11 +01:00
Yatrik Patel
5606cde506 Translated using Weblate (Hindi)
Currently translated at 100.0% (1675 of 1675 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/hi/
2026-03-02 20:54:10 +01:00
Yatrik Patel
0e2f4f4e13 Translated using Weblate (Hindi)
Currently translated at 38.6% (61 of 158 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/hi/
2026-03-02 20:54:09 +01:00
renovate[bot]
1f6c6f2acd chore(deps): update dependency @redocly/cli to v2.20.2 2026-03-02 18:09:58 +00:00
Elian Doran
37d2e9f14b fix(deps): update dependency globals to v17.4.0 (#8876) 2026-03-02 16:44:44 +02:00
Adorian Doran
0fcf30a3b8 Merge branch 'main' of https://github.com/TriliumNext/Trilium 2026-03-02 11:22:08 +02:00
Adorian Doran
8712e7dd16 style/pdf viewer: fix some layout issues in toolbar 2026-03-02 11:21:47 +02:00
renovate[bot]
2ee4e9cc14 fix(deps): update dependency globals to v17.4.0 2026-03-02 01:18:53 +00:00
Elian Doran
34ca7912fc Merge remote-tracking branch 'origin/main' into renovate/express-serve-static-core-5.x 2026-02-28 19:11:57 +02:00
Elian Doran
dc3de5bf36 chore(server): address requested changes 2026-02-27 00:05:54 +02:00
Elian Doran
1041bf70e1 test(express-partial-content): fix type errors 2026-02-26 21:11:22 +02:00
Elian Doran
0c6326b678 refactor(server): use strong typing for routes 2026-02-26 21:08:54 +02:00
renovate[bot]
fd805a5279 chore(deps): update dependency @types/express-serve-static-core to v5.1.1 2026-02-26 18:18:55 +00:00
49 changed files with 698 additions and 677 deletions

View File

@@ -16,7 +16,7 @@
"license": "AGPL-3.0-only",
"packageManager": "pnpm@10.30.3",
"devDependencies": {
"@redocly/cli": "2.19.2",
"@redocly/cli": "2.20.2",
"archiver": "7.0.1",
"fs-extra": "11.3.3",
"js-yaml": "4.1.1",

View File

@@ -44,7 +44,7 @@
"debounce": "3.0.0",
"draggabilly": "3.0.0",
"force-graph": "1.51.1",
"globals": "17.3.0",
"globals": "17.4.0",
"i18next": "25.8.13",
"i18next-http-backend": "3.0.2",
"jquery": "4.0.0",

View File

@@ -51,7 +51,7 @@
},
"add_link": {
"note": "नोट",
"add_link": "लिंक जोड़ें",
"add_link": "लिंक ऐड करें",
"help_on_links": "लिंक्स पर मदद।",
"search_note": "नोट को नाम से खोजें",
"link_title_mirrors": "लिंक टाइटल नोट के करंट टाइटल के हिसाब से बदलता है",
@@ -112,7 +112,7 @@
"help_on_tree_prefix": "ट्री प्रीफ़िक्स पर मदद",
"prefix": "प्रीफ़िक्स: ",
"save": "सेव करें",
"branch_prefix_saved": "ब्रांच प्रीिक्स सेव कर दिया गया है।",
"branch_prefix_saved": "ब्रांच प्रीफ़िक्स सेव हो चुका है।",
"branch_prefix_saved_multiple": "{{count}} ब्रांचेस के लिए ब्रांच प्रीफ़िक्स सेव कर दिया गया है।",
"affected_branches": "प्रभावित ब्रांचेस ({{count}}):"
},

View File

@@ -50,8 +50,15 @@
},
"bundle-error": {
"title": "Özel bir betik yüklenemedi",
"message": "ID'si \"{{id}}\" ve başlığı \"{{title}}\" olan nottan alınan komut dosyası şunun nedeniyle yürütülemedi:\n\n{{message}}"
}
"message": "Komut şu nedenle yürütülemedi:\n\n{{message}}"
},
"widget-list-error": {
"title": "Sunucudan widget listesi alınamadı"
},
"widget-render-error": {
"title": "Özel React widget'ı çizilirken sorun yaşandı"
},
"scripting-error": "Kullanıcı tanımlı betik hatası: {{title}}"
},
"add_link": {
"add_link": "Bağlantı ekle",

View File

@@ -1495,7 +1495,8 @@
"beta-feature": "Beta",
"task-list": "任務列表",
"new-feature": "新增",
"collections": "集合"
"collections": "集合",
"ai-chat": "AI 聊天"
},
"protect_note": {
"toggle-on": "保護筆記",
@@ -1594,7 +1595,8 @@
},
"search_result": {
"no_notes_found": "沒有找到符合搜尋條件的筆記。",
"search_not_executed": "尚未執行搜尋。請點擊上方的「搜尋」按鈕查看結果。"
"search_not_executed": "尚未執行搜尋。",
"search_now": "立即搜尋"
},
"spacer": {
"configure_launchbar": "設定啟動欄"
@@ -2011,7 +2013,9 @@
"app-restart-required": "(需要重啟程式以套用更改)"
},
"pagination": {
"total_notes": "{{count}} 筆記"
"total_notes": "{{count}} 筆記",
"prev_page": "上一頁",
"next_page": "下一頁"
},
"collections": {
"rendering_error": "發現錯誤,無法顯示內容。"

View File

@@ -31,7 +31,7 @@
"dependencies": {
"better-sqlite3": "12.6.2",
"html-to-text": "9.0.5",
"node-html-parser": "7.0.2",
"node-html-parser": "7.1.0",
"sucrase": "3.35.1"
},
"devDependencies": {
@@ -114,7 +114,7 @@
"safe-compare": "1.1.4",
"sanitize-filename": "1.6.3",
"sanitize-html": "2.17.1",
"sax": "1.4.4",
"sax": "1.5.0",
"serve-favicon": "2.5.1",
"stream-throttle": "0.1.3",
"strip-bom": "5.0.0",

View File

@@ -16,6 +16,9 @@
"create-note-into": "Aktif nota bağlı alt not oluştur",
"create-note-after": "Aktif nottan sonra yeni bir not oluştur",
"delete-note": "Notu sil",
"move-note-down": "Notu aşağıya kaydır"
"move-note-down": "Notu aşağıya kaydır",
"create-note-into-inbox": "Eğer tanımlandıysa gelen kutusunda bir not veya günlük not oluşturun",
"move-note-up-in-hierarchy": "Notu hiyerarşide yukarı taşı",
"move-note-down-in-hierarchy": "Notu hiyerarşide aşağı taşı"
}
}

View File

@@ -1,14 +1,15 @@
import type { AttachmentRow } from "@triliumnext/commons";
import type { Router } from "express";
import becca from "../becca/becca.js";
import utils from "../services/utils.js";
import eu from "./etapi_utils.js";
import type { ValidatorMap } from "./etapi-interface.js";
import mappers from "./mappers.js";
import v from "./validators.js";
import utils from "../services/utils.js";
import type { Router } from "express";
import type { AttachmentRow } from "@triliumnext/commons";
import type { ValidatorMap } from "./etapi-interface.js";
function register(router: Router) {
eu.route(router, "get", "/etapi/notes/:noteId/attachments", (req, res, next) => {
eu.route<{ noteId: string }>(router, "get", "/etapi/notes/:noteId/attachments", (req, res, next) => {
const note = eu.getAndCheckNote(req.params.noteId);
const attachments = note.getAttachments();
res.json(attachments.map((attachment) => mappers.mapAttachmentToPojo(attachment)));
@@ -41,7 +42,7 @@ function register(router: Router) {
}
});
eu.route(router, "get", "/etapi/attachments/:attachmentId", (req, res, next) => {
eu.route<{ attachmentId: string }>(router, "get", "/etapi/attachments/:attachmentId", (req, res, next) => {
const attachment = eu.getAndCheckAttachment(req.params.attachmentId);
res.json(mappers.mapAttachmentToPojo(attachment));
@@ -54,7 +55,7 @@ function register(router: Router) {
position: [v.notNull, v.isInteger]
};
eu.route(router, "patch", "/etapi/attachments/:attachmentId", (req, res, next) => {
eu.route<{ attachmentId: string }>(router, "patch", "/etapi/attachments/:attachmentId", (req, res, next) => {
const attachment = eu.getAndCheckAttachment(req.params.attachmentId);
if (attachment.isProtected) {
@@ -67,7 +68,7 @@ function register(router: Router) {
res.json(mappers.mapAttachmentToPojo(attachment));
});
eu.route(router, "get", "/etapi/attachments/:attachmentId/content", (req, res, next) => {
eu.route<{ attachmentId: string }>(router, "get", "/etapi/attachments/:attachmentId/content", (req, res, next) => {
const attachment = eu.getAndCheckAttachment(req.params.attachmentId);
if (attachment.isProtected) {
@@ -84,7 +85,7 @@ function register(router: Router) {
res.send(attachment.getContent());
});
eu.route(router, "put", "/etapi/attachments/:attachmentId/content", (req, res, next) => {
eu.route<{ attachmentId: string }>(router, "put", "/etapi/attachments/:attachmentId/content", (req, res, next) => {
const attachment = eu.getAndCheckAttachment(req.params.attachmentId);
if (attachment.isProtected) {
@@ -96,7 +97,7 @@ function register(router: Router) {
return res.sendStatus(204);
});
eu.route(router, "delete", "/etapi/attachments/:attachmentId", (req, res, next) => {
eu.route<{ attachmentId: string }>(router, "delete", "/etapi/attachments/:attachmentId", (req, res, next) => {
const attachment = becca.getAttachment(req.params.attachmentId);
if (!attachment) {

View File

@@ -1,14 +1,15 @@
import becca from "../becca/becca.js";
import eu from "./etapi_utils.js";
import mappers from "./mappers.js";
import attributeService from "../services/attributes.js";
import v from "./validators.js";
import type { Router } from "express";
import type { AttributeRow } from "@triliumnext/commons";
import type { Router } from "express";
import becca from "../becca/becca.js";
import attributeService from "../services/attributes.js";
import eu from "./etapi_utils.js";
import type { ValidatorMap } from "./etapi-interface.js";
import mappers from "./mappers.js";
import v from "./validators.js";
function register(router: Router) {
eu.route(router, "get", "/etapi/attributes/:attributeId", (req, res, next) => {
eu.route<{ attributeId: string }>(router, "get", "/etapi/attributes/:attributeId", (req, res, next) => {
const attribute = eu.getAndCheckAttribute(req.params.attributeId);
res.json(mappers.mapAttributeToPojo(attribute));
@@ -51,7 +52,7 @@ function register(router: Router) {
position: [v.notNull, v.isInteger]
};
eu.route(router, "patch", "/etapi/attributes/:attributeId", (req, res, next) => {
eu.route<{ attributeId: string }>(router, "patch", "/etapi/attributes/:attributeId", (req, res, next) => {
const attribute = eu.getAndCheckAttribute(req.params.attributeId);
if (attribute.type === "label") {
@@ -67,7 +68,7 @@ function register(router: Router) {
res.json(mappers.mapAttributeToPojo(attribute));
});
eu.route(router, "delete", "/etapi/attributes/:attributeId", (req, res, next) => {
eu.route<{ attributeId: string }>(router, "delete", "/etapi/attributes/:attributeId", (req, res, next) => {
const attribute = becca.getAttribute(req.params.attributeId);
if (!attribute) {

View File

@@ -1,10 +1,10 @@
import type { Router } from "express";
import eu from "./etapi_utils.js";
import backupService from "../services/backup.js";
import eu from "./etapi_utils.js";
function register(router: Router) {
eu.route(router, "put", "/etapi/backup/:backupName", (req, res, next) => {
eu.route<{ backupName: string }>(router, "put", "/etapi/backup/:backupName", (req, res, next) => {
backupService.backupNow(req.params.backupName)
.then(() => res.sendStatus(204))
.catch(() => res.sendStatus(500));

View File

@@ -1,15 +1,15 @@
import type { BranchRow } from "@triliumnext/commons";
import type { Router } from "express";
import becca from "../becca/becca.js";
import eu from "./etapi_utils.js";
import mappers from "./mappers.js";
import BBranch from "../becca/entities/bbranch.js";
import entityChangesService from "../services/entity_changes.js";
import eu from "./etapi_utils.js";
import mappers from "./mappers.js";
import v from "./validators.js";
import type { BranchRow } from "@triliumnext/commons";
function register(router: Router) {
eu.route(router, "get", "/etapi/branches/:branchId", (req, res, next) => {
eu.route<{ branchId: string }>(router, "get", "/etapi/branches/:branchId", (req, res, next) => {
const branch = eu.getAndCheckBranch(req.params.branchId);
res.json(mappers.mapBranchToPojo(branch));
@@ -37,15 +37,15 @@ function register(router: Router) {
existing.save();
return res.status(200).json(mappers.mapBranchToPojo(existing));
} else {
try {
const branch = new BBranch(params).save();
}
try {
const branch = new BBranch(params).save();
res.status(201).json(mappers.mapBranchToPojo(branch));
} catch (e: any) {
throw new eu.EtapiError(400, eu.GENERIC_CODE, e.message);
}
res.status(201).json(mappers.mapBranchToPojo(branch));
} catch (e: any) {
throw new eu.EtapiError(400, eu.GENERIC_CODE, e.message);
}
});
const ALLOWED_PROPERTIES_FOR_PATCH = {
@@ -54,7 +54,7 @@ function register(router: Router) {
isExpanded: [v.notNull, v.isBoolean]
};
eu.route(router, "patch", "/etapi/branches/:branchId", (req, res, next) => {
eu.route<{ branchId: string }>(router, "patch", "/etapi/branches/:branchId", (req, res, next) => {
const branch = eu.getAndCheckBranch(req.params.branchId);
eu.validateAndPatch(branch, req.body, ALLOWED_PROPERTIES_FOR_PATCH);
@@ -63,7 +63,7 @@ function register(router: Router) {
res.json(mappers.mapBranchToPojo(branch));
});
eu.route(router, "delete", "/etapi/branches/:branchId", (req, res, next) => {
eu.route<{ branchId: string }>(router, "delete", "/etapi/branches/:branchId", (req, res, next) => {
const branch = becca.getBranch(req.params.branchId);
if (!branch) {
@@ -75,7 +75,7 @@ function register(router: Router) {
res.sendStatus(204);
});
eu.route(router, "post", "/etapi/refresh-note-ordering/:parentNoteId", (req, res, next) => {
eu.route<{ parentNoteId: string }>(router, "post", "/etapi/refresh-note-ordering/:parentNoteId", (req, res, next) => {
eu.getAndCheckNote(req.params.parentNoteId);
entityChangesService.putNoteReorderingEntityChange(req.params.parentNoteId, "etapi");

View File

@@ -1,12 +1,14 @@
import cls from "../services/cls.js";
import sql from "../services/sql.js";
import log from "../services/log.js";
import becca from "../becca/becca.js";
import etapiTokenService from "../services/etapi_tokens.js";
import config from "../services/config.js";
import type { NextFunction, Request, RequestHandler, Response, Router } from "express";
import type { ValidatorMap } from "./etapi-interface.js";
import type { ParamsDictionary } from "express-serve-static-core";
import becca from "../becca/becca.js";
import type { ApiRequestHandler, SyncRouteRequestHandler } from "../routes/route_api.js";
import cls from "../services/cls.js";
import config from "../services/config.js";
import etapiTokenService from "../services/etapi_tokens.js";
import log from "../services/log.js";
import sql from "../services/sql.js";
import type { ValidatorMap } from "./etapi-interface.js";
const GENERIC_CODE = "GENERIC";
type HttpMethod = "all" | "get" | "post" | "put" | "delete" | "patch" | "options" | "head";
@@ -35,8 +37,8 @@ function sendError(res: Response, statusCode: number, code: string, message: str
.send(
JSON.stringify({
status: statusCode,
code: code,
message: message
code,
message
})
);
}
@@ -49,7 +51,7 @@ function checkEtapiAuth(req: Request, res: Response, next: NextFunction) {
}
}
function processRequest(req: Request, res: Response, routeHandler: ApiRequestHandler, next: NextFunction, method: string, path: string) {
function processRequest<P extends ParamsDictionary>(req: Request<P>, res: Response, routeHandler: ApiRequestHandler<P>, next: NextFunction, method: string, path: string) {
try {
cls.namespace.bindEmitter(req);
cls.namespace.bindEmitter(res);
@@ -73,12 +75,12 @@ function processRequest(req: Request, res: Response, routeHandler: ApiRequestHan
}
}
function route(router: Router, method: HttpMethod, path: string, routeHandler: SyncRouteRequestHandler) {
router[method](path, checkEtapiAuth, (req: Request, res: Response, next: NextFunction) => processRequest(req, res, routeHandler, next, method, path));
function route<P extends ParamsDictionary>(router: Router, method: HttpMethod, path: string, routeHandler: SyncRouteRequestHandler<P>) {
router[method](path, checkEtapiAuth, (req: Request<P>, res: Response, next: NextFunction) => processRequest(req, res, routeHandler, next, method, path));
}
function NOT_AUTHENTICATED_ROUTE(router: Router, method: HttpMethod, path: string, middleware: RequestHandler[], routeHandler: SyncRouteRequestHandler) {
router[method](path, ...middleware, (req: Request, res: Response, next: NextFunction) => processRequest(req, res, routeHandler, next, method, path));
function NOT_AUTHENTICATED_ROUTE<P extends ParamsDictionary>(router: Router, method: HttpMethod, path: string, middleware: RequestHandler[], routeHandler: SyncRouteRequestHandler<P>) {
router[method](path, ...middleware, (req: Request<P>, res: Response, next: NextFunction) => processRequest(req, res, routeHandler, next, method, path));
}
function getAndCheckNote(noteId: string) {
@@ -86,9 +88,8 @@ function getAndCheckNote(noteId: string) {
if (note) {
return note;
} else {
throw new EtapiError(404, "NOTE_NOT_FOUND", `Note '${noteId}' not found.`);
}
throw new EtapiError(404, "NOTE_NOT_FOUND", `Note '${noteId}' not found.`);
}
function getAndCheckAttachment(attachmentId: string) {
@@ -96,9 +97,8 @@ function getAndCheckAttachment(attachmentId: string) {
if (attachment) {
return attachment;
} else {
throw new EtapiError(404, "ATTACHMENT_NOT_FOUND", `Attachment '${attachmentId}' not found.`);
}
throw new EtapiError(404, "ATTACHMENT_NOT_FOUND", `Attachment '${attachmentId}' not found.`);
}
function getAndCheckBranch(branchId: string) {
@@ -106,9 +106,8 @@ function getAndCheckBranch(branchId: string) {
if (branch) {
return branch;
} else {
throw new EtapiError(404, "BRANCH_NOT_FOUND", `Branch '${branchId}' not found.`);
}
throw new EtapiError(404, "BRANCH_NOT_FOUND", `Branch '${branchId}' not found.`);
}
function getAndCheckAttribute(attributeId: string) {
@@ -116,9 +115,8 @@ function getAndCheckAttribute(attributeId: string) {
if (attribute) {
return attribute;
} else {
throw new EtapiError(404, "ATTRIBUTE_NOT_FOUND", `Attribute '${attributeId}' not found.`);
}
throw new EtapiError(404, "ATTRIBUTE_NOT_FOUND", `Attribute '${attributeId}' not found.`);
}
function getAndCheckRevision(revisionId: string) {
@@ -126,9 +124,8 @@ function getAndCheckRevision(revisionId: string) {
if (revision) {
return revision;
} else {
throw new EtapiError(404, "REVISION_NOT_FOUND", `Revision '${revisionId}' not found.`);
}
throw new EtapiError(404, "REVISION_NOT_FOUND", `Revision '${revisionId}' not found.`);
}
function validateAndPatch(target: any, source: any, allowedProperties: ValidatorMap) {

View File

@@ -1,20 +1,21 @@
import becca from "../becca/becca.js";
import utils from "../services/utils.js";
import eu from "./etapi_utils.js";
import mappers from "./mappers.js";
import noteService from "../services/notes.js";
import TaskContext from "../services/task_context.js";
import v from "./validators.js";
import searchService from "../services/search/services/search.js";
import SearchContext from "../services/search/search_context.js";
import zipExportService from "../services/export/zip.js";
import zipImportService from "../services/import/zip.js";
import type { Request, Router } from "express";
import type { ParsedQs } from "qs";
import type { NoteParams } from "../services/note-interface.js";
import type { SearchParams } from "../services/search/services/types.js";
import type { ValidatorMap } from "./etapi-interface.js";
import becca from "../becca/becca.js";
import zipExportService from "../services/export/zip.js";
import type { ExportFormat } from "../services/export/zip/abstract_provider.js";
import zipImportService from "../services/import/zip.js";
import type { NoteParams } from "../services/note-interface.js";
import noteService from "../services/notes.js";
import SearchContext from "../services/search/search_context.js";
import searchService from "../services/search/services/search.js";
import type { SearchParams } from "../services/search/services/types.js";
import TaskContext from "../services/task_context.js";
import utils from "../services/utils.js";
import eu from "./etapi_utils.js";
import type { ValidatorMap } from "./etapi-interface.js";
import mappers from "./mappers.js";
import v from "./validators.js";
function register(router: Router) {
eu.route(router, "get", "/etapi/notes", (req, res, next) => {
@@ -41,7 +42,7 @@ function register(router: Router) {
res.json(resp);
});
eu.route(router, "get", "/etapi/notes/:noteId", (req, res, next) => {
eu.route<{ noteId: string }>(router, "get", "/etapi/notes/:noteId", (req, res, next) => {
const note = eu.getAndCheckNote(req.params.noteId);
res.json(mappers.mapNoteToPojo(note));
@@ -86,7 +87,7 @@ function register(router: Router) {
utcDateCreated: [v.notNull, v.isString, v.isUtcDateTime]
};
eu.route(router, "patch", "/etapi/notes/:noteId", (req, res, next) => {
eu.route<{ noteId: string }>(router, "patch", "/etapi/notes/:noteId", (req, res, next) => {
const note = eu.getAndCheckNote(req.params.noteId);
if (note.isProtected) {
@@ -100,7 +101,7 @@ function register(router: Router) {
res.json(mappers.mapNoteToPojo(note));
});
eu.route(router, "delete", "/etapi/notes/:noteId", (req, res, next) => {
eu.route<{ noteId: string }>(router, "delete", "/etapi/notes/:noteId", (req, res, next) => {
const { noteId } = req.params;
const note = becca.getNote(noteId);
@@ -114,7 +115,7 @@ function register(router: Router) {
res.sendStatus(204);
});
eu.route(router, "get", "/etapi/notes/:noteId/content", (req, res, next) => {
eu.route<{ noteId: string }>(router, "get", "/etapi/notes/:noteId/content", (req, res, next) => {
const note = eu.getAndCheckNote(req.params.noteId);
if (note.isProtected) {
@@ -131,7 +132,7 @@ function register(router: Router) {
res.send(note.getContent());
});
eu.route(router, "put", "/etapi/notes/:noteId/content", (req, res, next) => {
eu.route<{ noteId: string }>(router, "put", "/etapi/notes/:noteId/content", (req, res, next) => {
const note = eu.getAndCheckNote(req.params.noteId);
if (note.isProtected) {
@@ -146,7 +147,7 @@ function register(router: Router) {
return res.sendStatus(204);
});
eu.route(router, "get", "/etapi/notes/:noteId/export", (req, res, next) => {
eu.route<{ noteId: string }>(router, "get", "/etapi/notes/:noteId/export", (req, res, next) => {
const note = eu.getAndCheckNote(req.params.noteId);
const format = req.query.format || "html";
@@ -163,7 +164,7 @@ function register(router: Router) {
zipExportService.exportToZip(taskContext, branch, format as ExportFormat, res);
});
eu.route(router, "post", "/etapi/notes/:noteId/import", (req, res, next) => {
eu.route<{ noteId: string }>(router, "post", "/etapi/notes/:noteId/import", (req, res, next) => {
const note = eu.getAndCheckNote(req.params.noteId);
const taskContext = new TaskContext("no-progress-reporting", "importNotes", null);
@@ -175,7 +176,7 @@ function register(router: Router) {
}); // we need better error handling here, async errors won't be properly processed.
});
eu.route(router, "post", "/etapi/notes/:noteId/revision", (req, res, next) => {
eu.route<{ noteId: string }>(router, "post", "/etapi/notes/:noteId/revision", (req, res, next) => {
const note = eu.getAndCheckNote(req.params.noteId);
note.saveRevision();
@@ -183,7 +184,7 @@ function register(router: Router) {
return res.sendStatus(204);
});
eu.route(router, "get", "/etapi/notes/:noteId/attachments", (req, res, next) => {
eu.route<{ noteId: string }>(router, "get", "/etapi/notes/:noteId/attachments", (req, res, next) => {
const note = eu.getAndCheckNote(req.params.noteId);
const attachments = note.getAttachments();

View File

@@ -1,13 +1,14 @@
import type { NoteRow, RecentChangeRow } from "@triliumnext/commons";
import type { Router } from "express";
import becca from "../becca/becca.js";
import noteService from "../services/notes.js";
import protectedSessionService from "../services/protected_session.js";
import sql from "../services/sql.js";
import TaskContext from "../services/task_context.js";
import utils from "../services/utils.js";
import eu from "./etapi_utils.js";
import mappers from "./mappers.js";
import noteService from "../services/notes.js";
import TaskContext from "../services/task_context.js";
import protectedSessionService from "../services/protected_session.js";
import utils from "../services/utils.js";
import type { Router } from "express";
import type { NoteRow, RecentChangeRow } from "@triliumnext/commons";
function register(router: Router) {
// GET /etapi/notes/history - must be registered before /etapi/notes/:noteId routes
@@ -130,7 +131,7 @@ function register(router: Router) {
});
// GET /etapi/notes/:noteId/revisions - List all revisions for a note
eu.route(router, "get", "/etapi/notes/:noteId/revisions", (req, res, next) => {
eu.route<{ noteId: string }>(router, "get", "/etapi/notes/:noteId/revisions", (req, res, next) => {
const note = eu.getAndCheckNote(req.params.noteId);
const revisions = becca.getRevisionsFromQuery(
@@ -146,7 +147,7 @@ function register(router: Router) {
});
// POST /etapi/notes/:noteId/undelete - Restore a deleted note
eu.route(router, "post", "/etapi/notes/:noteId/undelete", (req, res, next) => {
eu.route<{ noteId: string }>(router, "post", "/etapi/notes/:noteId/undelete", (req, res, next) => {
const { noteId } = req.params;
const noteRow = sql.getRow<NoteRow | null>("SELECT * FROM notes WHERE noteId = ?", [noteId]);
@@ -172,7 +173,7 @@ function register(router: Router) {
});
// GET /etapi/revisions/:revisionId - Get revision metadata
eu.route(router, "get", "/etapi/revisions/:revisionId", (req, res, next) => {
eu.route<{ revisionId: string }>(router, "get", "/etapi/revisions/:revisionId", (req, res, next) => {
const revision = eu.getAndCheckRevision(req.params.revisionId);
if (revision.isProtected) {
@@ -183,7 +184,7 @@ function register(router: Router) {
});
// GET /etapi/revisions/:revisionId/content - Get revision content
eu.route(router, "get", "/etapi/revisions/:revisionId/content", (req, res, next) => {
eu.route<{ revisionId: string }>(router, "get", "/etapi/revisions/:revisionId/content", (req, res, next) => {
const revision = eu.getAndCheckRevision(req.params.revisionId);
if (revision.isProtected) {

View File

@@ -1,8 +1,9 @@
import specialNotesService from "../services/special_notes.js";
import type { Router } from "express";
import dateNotesService from "../services/date_notes.js";
import specialNotesService from "../services/special_notes.js";
import eu from "./etapi_utils.js";
import mappers from "./mappers.js";
import type { Router } from "express";
const getDateInvalidError = (date: string) => new eu.EtapiError(400, "DATE_INVALID", `Date "${date}" is not valid.`);
const getWeekInvalidError = (week: string) => new eu.EtapiError(400, "WEEK_INVALID", `Week "${week}" is not valid.`);
@@ -15,7 +16,7 @@ function isValidDate(date: string) {
}
function register(router: Router) {
eu.route(router, "get", "/etapi/inbox/:date", (req, res, next) => {
eu.route<{ date: string }>(router, "get", "/etapi/inbox/:date", (req, res, next) => {
const { date } = req.params;
if (!isValidDate(date)) {
@@ -25,7 +26,7 @@ function register(router: Router) {
res.json(mappers.mapNoteToPojo(note));
});
eu.route(router, "get", "/etapi/calendar/days/:date", (req, res, next) => {
eu.route<{ date: string }>(router, "get", "/etapi/calendar/days/:date", (req, res, next) => {
const { date } = req.params;
if (!isValidDate(date)) {
@@ -36,7 +37,7 @@ function register(router: Router) {
res.json(mappers.mapNoteToPojo(note));
});
eu.route(router, "get", "/etapi/calendar/week-first-day/:date", (req, res, next) => {
eu.route<{ date: string }>(router, "get", "/etapi/calendar/week-first-day/:date", (req, res, next) => {
const { date } = req.params;
if (!isValidDate(date)) {
@@ -47,7 +48,7 @@ function register(router: Router) {
res.json(mappers.mapNoteToPojo(note));
});
eu.route(router, "get", "/etapi/calendar/weeks/:week", (req, res, next) => {
eu.route<{ week: string }>(router, "get", "/etapi/calendar/weeks/:week", (req, res, next) => {
const { week } = req.params;
if (!/[0-9]{4}-W[0-9]{2}/.test(week)) {
@@ -63,7 +64,7 @@ function register(router: Router) {
res.json(mappers.mapNoteToPojo(note));
});
eu.route(router, "get", "/etapi/calendar/months/:month", (req, res, next) => {
eu.route<{ month: string }>(router, "get", "/etapi/calendar/months/:month", (req, res, next) => {
const { month } = req.params;
if (!/[0-9]{4}-[0-9]{2}/.test(month)) {
@@ -74,7 +75,7 @@ function register(router: Router) {
res.json(mappers.mapNoteToPojo(note));
});
eu.route(router, "get", "/etapi/calendar/years/:year", (req, res, next) => {
eu.route<{ year: string }>(router, "get", "/etapi/calendar/years/:year", (req, res, next) => {
const { year } = req.params;
if (!/[0-9]{4}/.test(year)) {

View File

@@ -1,29 +1,30 @@
import becca from "../../becca/becca.js";
import blobService from "../../services/blob.js";
import ValidationError from "../../errors/validation_error.js";
import imageService from "../../services/image.js";
import type { Request } from "express";
import { ConvertAttachmentToNoteResponse } from "@triliumnext/commons";
import type { Request } from "express";
function getAttachmentBlob(req: Request) {
import becca from "../../becca/becca.js";
import ValidationError from "../../errors/validation_error.js";
import blobService from "../../services/blob.js";
import imageService from "../../services/image.js";
function getAttachmentBlob(req: Request<{ attachmentId: string }>) {
const preview = req.query.preview === "true";
return blobService.getBlobPojo("attachments", req.params.attachmentId, { preview });
}
function getAttachments(req: Request) {
function getAttachments(req: Request<{ noteId: string }>) {
const note = becca.getNoteOrThrow(req.params.noteId);
return note.getAttachments();
}
function getAttachment(req: Request) {
function getAttachment(req: Request<{ attachmentId: string }>) {
const { attachmentId } = req.params;
return becca.getAttachmentOrThrow(attachmentId);
}
function getAllAttachments(req: Request) {
function getAllAttachments(req: Request<{ attachmentId: string }>) {
const { attachmentId } = req.params;
// one particular attachment is requested, but return all note's attachments
@@ -31,10 +32,10 @@ function getAllAttachments(req: Request) {
return attachment.getNote()?.getAttachments() || [];
}
function saveAttachment(req: Request) {
function saveAttachment(req: Request<{ noteId: string }>) {
const { noteId } = req.params;
const { attachmentId, role, mime, title, content } = req.body;
const matchByQuery = req.query.matchBy
const matchByQuery = req.query.matchBy;
const isValidMatchBy = (typeof matchByQuery === "string") && (matchByQuery === "attachmentId" || matchByQuery === "title");
const matchBy = isValidMatchBy ? matchByQuery : undefined;
@@ -42,7 +43,7 @@ function saveAttachment(req: Request) {
note.saveAttachment({ attachmentId, role, mime, title, content }, matchBy);
}
function uploadAttachment(req: Request) {
function uploadAttachment(req: Request<{ noteId: string }>) {
const { noteId } = req.params;
const { file } = req;
@@ -76,7 +77,7 @@ function uploadAttachment(req: Request) {
};
}
function renameAttachment(req: Request) {
function renameAttachment(req: Request<{ attachmentId: string }>) {
const { title } = req.body;
const { attachmentId } = req.params;
@@ -90,7 +91,7 @@ function renameAttachment(req: Request) {
attachment.save();
}
function deleteAttachment(req: Request) {
function deleteAttachment(req: Request<{ attachmentId: string }>) {
const { attachmentId } = req.params;
const attachment = becca.getAttachment(attachmentId);
@@ -100,7 +101,7 @@ function deleteAttachment(req: Request) {
}
}
function convertAttachmentToNote(req: Request) {
function convertAttachmentToNote(req: Request<{ attachmentId: string }>) {
const { attachmentId } = req.params;
const attachment = becca.getAttachmentOrThrow(attachmentId);

View File

@@ -1,21 +1,22 @@
"use strict";
import sql from "../../services/sql.js";
import log from "../../services/log.js";
import attributeService from "../../services/attributes.js";
import BAttribute from "../../becca/entities/battribute.js";
import becca from "../../becca/becca.js";
import ValidationError from "../../errors/validation_error.js";
import type { Request } from "express";
import { UpdateAttributeResponse } from "@triliumnext/commons";
import type { Request } from "express";
function getEffectiveNoteAttributes(req: Request) {
import becca from "../../becca/becca.js";
import BAttribute from "../../becca/entities/battribute.js";
import ValidationError from "../../errors/validation_error.js";
import attributeService from "../../services/attributes.js";
import log from "../../services/log.js";
import sql from "../../services/sql.js";
function getEffectiveNoteAttributes(req: Request<{ noteId: string }>) {
const note = becca.getNote(req.params.noteId);
return note?.getAttributes();
}
function updateNoteAttribute(req: Request) {
function updateNoteAttribute(req: Request<{ noteId: string }>) {
const noteId = req.params.noteId;
const body = req.body;
@@ -47,7 +48,7 @@ function updateNoteAttribute(req: Request) {
}
attribute = new BAttribute({
noteId: noteId,
noteId,
name: body.name,
type: body.type,
isInheritable: body.isInheritable
@@ -96,7 +97,7 @@ function addNoteAttribute(req: Request) {
new BAttribute({ ...body, noteId }).save();
}
function deleteNoteAttribute(req: Request) {
function deleteNoteAttribute(req: Request<{ noteId: string; attributeId: string }>) {
const noteId = req.params.noteId;
const attributeId = req.params.attributeId;
@@ -111,7 +112,7 @@ function deleteNoteAttribute(req: Request) {
}
}
function updateNoteAttributes(req: Request) {
function updateNoteAttributes(req: Request<{ noteId: string }>) {
const noteId = req.params.noteId;
const incomingAttributes = req.body;
@@ -193,7 +194,7 @@ function getValuesForAttribute(req: Request) {
return sql.getColumn("SELECT DISTINCT value FROM attributes WHERE isDeleted = 0 AND name = ? AND type = 'label' AND value != '' ORDER BY value", [attributeName]);
}
function createRelation(req: Request) {
function createRelation(req: Request<{ noteId: string; targetNoteId: string; name: string }>) {
const sourceNoteId = req.params.noteId;
const targetNoteId = req.params.targetNoteId;
const name = req.params.name;
@@ -208,7 +209,7 @@ function createRelation(req: Request) {
if (!attribute) {
attribute = new BAttribute({
noteId: sourceNoteId,
name: name,
name,
type: "relation",
value: targetNoteId
}).save();

View File

@@ -1,24 +1,23 @@
"use strict";
import sql from "../../services/sql.js";
import utils from "../../services/utils.js";
import entityChangesService from "../../services/entity_changes.js";
import treeService from "../../services/tree.js";
import eraseService from "../../services/erase.js";
import becca from "../../becca/becca.js";
import TaskContext from "../../services/task_context.js";
import branchService from "../../services/branches.js";
import log from "../../services/log.js";
import ValidationError from "../../errors/validation_error.js";
import eventService from "../../services/events.js";
import type { Request } from "express";
import becca from "../../becca/becca.js";
import ValidationError from "../../errors/validation_error.js";
import branchService from "../../services/branches.js";
import entityChangesService from "../../services/entity_changes.js";
import eraseService from "../../services/erase.js";
import eventService from "../../services/events.js";
import log from "../../services/log.js";
import sql from "../../services/sql.js";
import TaskContext from "../../services/task_context.js";
import treeService from "../../services/tree.js";
import utils from "../../services/utils.js";
/**
* Code in this file deals with moving and cloning branches. The relationship between note and parent note is unique
* for not deleted branches. There may be multiple deleted note-parent note relationships.
*/
function moveBranchToParent(req: Request) {
function moveBranchToParent(req: Request<{ branchId: string, parentBranchId: string }>) {
const { branchId, parentBranchId } = req.params;
const branchToMove = becca.getBranch(branchId);
@@ -31,7 +30,7 @@ function moveBranchToParent(req: Request) {
return branchService.moveBranchToBranch(branchToMove, targetParentBranch, branchId);
}
function moveBranchBeforeNote(req: Request) {
function moveBranchBeforeNote(req: Request<{ branchId: string, beforeBranchId: string }>) {
const { branchId, beforeBranchId } = req.params;
const branchToMove = becca.getBranchOrThrow(branchId);
@@ -79,7 +78,7 @@ function moveBranchBeforeNote(req: Request) {
return { success: true };
}
function moveBranchAfterNote(req: Request) {
function moveBranchAfterNote(req: Request<{ branchId: string, afterBranchId: string }>) {
const { branchId, afterBranchId } = req.params;
const branchToMove = becca.getBranchOrThrow(branchId);
@@ -128,7 +127,7 @@ function moveBranchAfterNote(req: Request) {
return { success: true };
}
function setExpanded(req: Request) {
function setExpanded(req: Request<{ branchId: string, expanded: string }>) {
const { branchId } = req.params;
const expanded = parseInt(req.params.expanded);
@@ -150,7 +149,7 @@ function setExpanded(req: Request) {
}
}
function setExpandedForSubtree(req: Request) {
function setExpandedForSubtree(req: Request<{ branchId: string, expanded: string }>) {
const { branchId } = req.params;
const expanded = parseInt(req.params.expanded);
@@ -232,7 +231,7 @@ function setExpandedForSubtree(req: Request) {
* - session: []
* tags: ["data"]
*/
function deleteBranch(req: Request) {
function deleteBranch(req: Request<{ branchId: string }>) {
const last = req.query.last === "true";
const eraseNotes = req.query.eraseNotes === "true";
const branch = becca.getBranchOrThrow(req.params.branchId);
@@ -256,11 +255,11 @@ function deleteBranch(req: Request) {
}
return {
noteDeleted: noteDeleted
noteDeleted
};
}
function setPrefix(req: Request) {
function setPrefix(req: Request<{ branchId: string }>) {
const branchId = req.params.branchId;
//TriliumNextTODO: req.body arrives as string, so req.body.prefix will be undefined did the code below ever even work?
const prefix = utils.isEmptyOrWhitespace(req.body.prefix) ? null : req.body.prefix;
@@ -272,7 +271,7 @@ function setPrefix(req: Request) {
function setPrefixBatch(req: Request) {
const { branchIds, prefix } = req.body;
if (!Array.isArray(branchIds)) {
throw new ValidationError("branchIds must be an array");
}

View File

@@ -38,7 +38,7 @@ async function addClipping(req: Request) {
if (!clippingNote) {
clippingNote = noteService.createNewNote({
parentNoteId: clipperInbox.noteId,
title: title,
title,
content: "",
type: "text"
}).note;
@@ -188,7 +188,7 @@ export function processContent(images: Image[], note: BNote, content: string) {
return rewrittenContent;
}
function openNote(req: Request) {
function openNote(req: Request<{ noteId: string }>) {
if (utils.isElectron) {
ws.sendMessageToAllClients({
type: "openNote",
@@ -198,11 +198,11 @@ function openNote(req: Request) {
return {
result: "ok"
};
} else {
return {
result: "open-in-browser"
};
}
}
return {
result: "open-in-browser"
};
}
function handshake() {
@@ -212,7 +212,7 @@ function handshake() {
};
}
async function findNotesByUrl(req: Request) {
async function findNotesByUrl(req: Request<{ noteUrl: string }>) {
const pageUrl = req.params.noteUrl;
const clipperInbox = await getClipperInboxNote();
const foundPage = findClippingNote(clipperInbox, pageUrl, null);

View File

@@ -1,29 +1,28 @@
"use strict";
import type { Request } from "express";
import cloningService from "../../services/cloning.js";
function cloneNoteToBranch(req: Request) {
function cloneNoteToBranch(req: Request<{ noteId: string; parentBranchId: string }>) {
const { noteId, parentBranchId } = req.params;
const { prefix } = req.body;
return cloningService.cloneNoteToBranch(noteId, parentBranchId, prefix);
}
function cloneNoteToParentNote(req: Request) {
function cloneNoteToParentNote(req: Request<{ noteId: string; parentNoteId: string }>) {
const { noteId, parentNoteId } = req.params;
const { prefix } = req.body;
return cloningService.cloneNoteToParentNote(noteId, parentNoteId, prefix);
}
function cloneNoteAfter(req: Request) {
function cloneNoteAfter(req: Request<{ noteId: string; afterBranchId: string }>) {
const { noteId, afterBranchId } = req.params;
return cloningService.cloneNoteAfter(noteId, afterBranchId);
}
function toggleNoteInParent(req: Request) {
function toggleNoteInParent(req: Request<{ noteId: string; parentNoteId: string; present: string }>) {
const { noteId, parentNoteId, present } = req.params;
return cloningService.toggleNoteInParent(present === "true", noteId, parentNoteId);

View File

@@ -1,6 +1,7 @@
import type { Request } from "express";
import etapiTokenService from "../../services/etapi_tokens.js";
import { EtapiToken, PostTokensResponse } from "@triliumnext/commons";
import type { Request } from "express";
import etapiTokenService from "../../services/etapi_tokens.js";
function getTokens() {
const tokens = etapiTokenService.getTokens();
@@ -14,11 +15,11 @@ function createToken(req: Request) {
return etapiTokenService.createToken(req.body.tokenName) satisfies PostTokensResponse;
}
function patchToken(req: Request) {
function patchToken(req: Request<{ etapiTokenId: string }>) {
etapiTokenService.renameToken(req.params.etapiTokenId, req.body.name);
}
function deleteToken(req: Request) {
function deleteToken(req: Request<{ etapiTokenId: string }>) {
etapiTokenService.deleteToken(req.params.etapiTokenId);
}

View File

@@ -1,17 +1,16 @@
"use strict";
import zipExportService from "../../services/export/zip.js";
import singleExportService from "../../services/export/single.js";
import opmlExportService from "../../services/export/opml.js";
import becca from "../../becca/becca.js";
import TaskContext from "../../services/task_context.js";
import log from "../../services/log.js";
import NotFoundError from "../../errors/not_found_error.js";
import type { Request, Response } from "express";
import becca from "../../becca/becca.js";
import NotFoundError from "../../errors/not_found_error.js";
import ValidationError from "../../errors/validation_error.js";
import opmlExportService from "../../services/export/opml.js";
import singleExportService from "../../services/export/single.js";
import zipExportService from "../../services/export/zip.js";
import log from "../../services/log.js";
import TaskContext from "../../services/task_context.js";
import { safeExtractMessageAndStackFromError } from "../../services/utils.js";
function exportBranch(req: Request, res: Response) {
function exportBranch(req: Request<{ branchId: string; type: string; format: string; version: string; taskId: string }>, res: Response) {
const { branchId, type, format, version, taskId } = req.params;
const branch = becca.getBranch(branchId);

View File

@@ -1,5 +1,3 @@
import chokidar from "chokidar";
import type { Request, Response } from "express";
import fs from "fs";
@@ -17,7 +15,7 @@ import protectedSessionService from "../../services/protected_session.js";
import utils from "../../services/utils.js";
import ws from "../../services/ws.js";
function updateFile(req: Request) {
function updateFile(req: Request<{ noteId: string }>) {
const note = becca.getNoteOrThrow(req.params.noteId);
const file = req.file;
@@ -46,7 +44,7 @@ function updateFile(req: Request) {
};
}
function updateAttachment(req: Request) {
function updateAttachment(req: Request<{ attachmentId: string }>) {
const attachment = becca.getAttachmentOrThrow(req.params.attachmentId);
const file = req.file;
if (!file) {
@@ -103,20 +101,20 @@ function downloadAttachmentInt(attachmentId: string, res: Response, contentDispo
return downloadData(attachment, res, contentDisposition);
}
const downloadFile = (req: Request, res: Response) => downloadNoteInt(req.params.noteId, res, true);
const openFile = (req: Request, res: Response) => downloadNoteInt(req.params.noteId, res, false);
const downloadFile = (req: Request<{ noteId: string }>, res: Response) => downloadNoteInt(req.params.noteId, res, true);
const openFile = (req: Request<{ noteId: string }>, res: Response) => downloadNoteInt(req.params.noteId, res, false);
const downloadAttachment = (req: Request, res: Response) => downloadAttachmentInt(req.params.attachmentId, res, true);
const openAttachment = (req: Request, res: Response) => downloadAttachmentInt(req.params.attachmentId, res, false);
const downloadAttachment = (req: Request<{ attachmentId: string }>, res: Response) => downloadAttachmentInt(req.params.attachmentId, res, true);
const openAttachment = (req: Request<{ attachmentId: string }>, res: Response) => downloadAttachmentInt(req.params.attachmentId, res, false);
function fileContentProvider(req: Request) {
function fileContentProvider(req: Request<{ noteId: string }>) {
// Read the file name from route params.
const note = becca.getNoteOrThrow(req.params.noteId);
return streamContent(note.getContent(), note.getFileName(), note.mime);
}
function attachmentContentProvider(req: Request) {
function attachmentContentProvider(req: Request<{ attachmentId: string }>) {
// Read the file name from route params.
const attachment = becca.getAttachmentOrThrow(req.params.attachmentId);
@@ -149,7 +147,7 @@ async function streamContent(content: string | Buffer, fileName: string, mimeTyp
};
}
function saveNoteToTmpDir(req: Request) {
function saveNoteToTmpDir(req: Request<{ noteId: string }>) {
const note = becca.getNoteOrThrow(req.params.noteId);
const fileName = note.getFileName();
const content = note.getContent();
@@ -157,7 +155,7 @@ function saveNoteToTmpDir(req: Request) {
return saveToTmpDir(fileName, content, "notes", note.noteId);
}
function saveAttachmentToTmpDir(req: Request) {
function saveAttachmentToTmpDir(req: Request<{ attachmentId: string }>) {
const attachment = becca.getAttachmentOrThrow(req.params.attachmentId);
const fileName = attachment.getFileName();
const content = attachment.getContent();
@@ -205,7 +203,7 @@ function saveToTmpDir(fileName: string, content: string | Buffer, entityType: st
};
}
function uploadModifiedFileToNote(req: Request) {
function uploadModifiedFileToNote(req: Request<{ noteId: string }>) {
const noteId = req.params.noteId;
const { filePath } = req.body;
@@ -228,7 +226,7 @@ function uploadModifiedFileToNote(req: Request) {
note.setContent(fileContent);
}
function uploadModifiedFileToAttachment(req: Request) {
function uploadModifiedFileToAttachment(req: Request<{ attachmentId: string }>) {
const { attachmentId } = req.params;
const { filePath } = req.body;

View File

@@ -1,20 +1,19 @@
"use strict";
import imageService from "../../services/image.js";
import becca from "../../becca/becca.js";
import fs from "fs";
import type { Request, Response } from "express";
import fs from "fs";
import becca from "../../becca/becca.js";
import type BNote from "../../becca/entities/bnote.js";
import type BRevision from "../../becca/entities/brevision.js";
import imageService from "../../services/image.js";
import { RESOURCE_DIR } from "../../services/resource_dir.js";
function returnImageFromNote(req: Request, res: Response) {
function returnImageFromNote(req: Request<{ noteId: string }>, res: Response) {
const image = becca.getNote(req.params.noteId);
return returnImageInt(image, res);
}
function returnImageFromRevision(req: Request, res: Response) {
function returnImageFromRevision(req: Request<{ revisionId: string }>, res: Response) {
const image = becca.getRevision(req.params.revisionId);
return returnImageInt(image, res);
@@ -61,7 +60,7 @@ export function renderSvgAttachment(image: BNote | BRevision, res: Response, att
res.send(svg);
}
function returnAttachedImage(req: Request, res: Response) {
function returnAttachedImage(req: Request<{ attachmentId: string }>, res: Response) {
const attachment = becca.getAttachment(req.params.attachmentId);
if (!attachment) {
@@ -78,7 +77,7 @@ function returnAttachedImage(req: Request, res: Response) {
res.send(attachment.getContent());
}
function updateImage(req: Request) {
function updateImage(req: Request<{ noteId: string }>) {
const { noteId } = req.params;
const { file } = req;

View File

@@ -1,21 +1,20 @@
"use strict";
import enexImportService from "../../services/import/enex.js";
import opmlImportService from "../../services/import/opml.js";
import zipImportService from "../../services/import/zip.js";
import singleImportService from "../../services/import/single.js";
import cls from "../../services/cls.js";
import type { Request } from "express";
import path from "path";
import becca from "../../becca/becca.js";
import beccaLoader from "../../becca/becca_loader.js";
import type BNote from "../../becca/entities/bnote.js";
import ValidationError from "../../errors/validation_error.js";
import cls from "../../services/cls.js";
import enexImportService from "../../services/import/enex.js";
import opmlImportService from "../../services/import/opml.js";
import singleImportService from "../../services/import/single.js";
import zipImportService from "../../services/import/zip.js";
import log from "../../services/log.js";
import TaskContext from "../../services/task_context.js";
import ValidationError from "../../errors/validation_error.js";
import type { Request } from "express";
import type BNote from "../../becca/entities/bnote.js";
import { safeExtractMessageAndStackFromError } from "../../services/utils.js";
async function importNotesToBranch(req: Request) {
async function importNotesToBranch(req: Request<{ parentNoteId: string }>) {
const { parentNoteId } = req.params;
const { taskId, last } = req.body;
@@ -88,7 +87,7 @@ async function importNotesToBranch(req: Request) {
setTimeout(
() =>
taskContext.taskSucceeded({
parentNoteId: parentNoteId,
parentNoteId,
importedNoteId: note?.noteId
}),
1000
@@ -101,7 +100,7 @@ async function importNotesToBranch(req: Request) {
return note.getPojo();
}
function importAttachmentsToNote(req: Request) {
function importAttachmentsToNote(req: Request<{ parentNoteId: string }>) {
const { parentNoteId } = req.params;
const { taskId, last } = req.body;
@@ -138,7 +137,7 @@ function importAttachmentsToNote(req: Request) {
setTimeout(
() =>
taskContext.taskSucceeded({
parentNoteId: parentNoteId
parentNoteId
}),
1000
);

View File

@@ -1,11 +1,12 @@
"use strict";
import becca from "../../becca/becca.js";
import type BNote from "../../becca/entities/bnote.js";
import type BAttribute from "../../becca/entities/battribute.js";
import { BacklinkCountResponse, BacklinksResponse } from "@triliumnext/commons";
import type { Request } from "express";
import { HTMLElement, parse, TextNode } from "node-html-parser";
import { BacklinkCountResponse, BacklinksResponse } from "@triliumnext/commons";
import becca from "../../becca/becca.js";
import type BAttribute from "../../becca/entities/battribute.js";
import type BNote from "../../becca/entities/bnote.js";
interface TreeLink {
sourceNoteId: string;
@@ -97,7 +98,7 @@ function getNeighbors(note: BNote, depth: number): string[] {
return retNoteIds;
}
function getLinkMap(req: Request) {
function getLinkMap(req: Request<{ noteId: string }>) {
const mapRootNote = becca.getNoteOrThrow(req.params.noteId);
// if the map root itself has "excludeFromNoteMap" attribute (journal typically) then there wouldn't be anything
@@ -156,9 +157,9 @@ function getLinkMap(req: Request) {
return false;
} else if (excludeRelations.has(rel.name)) {
return false;
} else {
return true;
}
}
return true;
})
.map((rel) => ({
id: `${rel.noteId}-${rel.name}-${rel.value}`,
@@ -168,13 +169,13 @@ function getLinkMap(req: Request) {
}));
return {
notes: notes,
notes,
noteIdToDescendantCountMap: buildDescendantCountMap(noteIdsArray),
links: links
links
};
}
function getTreeMap(req: Request) {
function getTreeMap(req: Request<{ noteId: string }>) {
const mapRootNote = becca.getNoteOrThrow(req.params.noteId);
// if the map root itself has "excludeFromNoteMap" (journal typically) then there wouldn't be anything to display,
// so we'll just ignore it
@@ -223,9 +224,9 @@ function getTreeMap(req: Request) {
updateDescendantCountMapForSearch(noteIdToDescendantCountMap, subtree.relationships);
return {
notes: notes,
noteIdToDescendantCountMap: noteIdToDescendantCountMap,
links: links
notes,
noteIdToDescendantCountMap,
links
};
}
@@ -350,7 +351,7 @@ function getFilteredBacklinks(note: BNote): BAttribute[] {
);
}
function getBacklinkCount(req: Request) {
function getBacklinkCount(req: Request<{ noteId: string }>) {
const { noteId } = req.params;
const note = becca.getNoteOrThrow(noteId);
@@ -360,7 +361,7 @@ function getBacklinkCount(req: Request) {
} satisfies BacklinkCountResponse;
}
function getBacklinks(req: Request): BacklinksResponse {
function getBacklinks(req: Request<{ noteId: string }>): BacklinksResponse {
const { noteId } = req.params;
const note = becca.getNoteOrThrow(noteId);

View File

@@ -1,18 +1,19 @@
"use strict";
import noteService from "../../services/notes.js";
import eraseService from "../../services/erase.js";
import treeService from "../../services/tree.js";
import sql from "../../services/sql.js";
import utils from "../../services/utils.js";
import log from "../../services/log.js";
import TaskContext from "../../services/task_context.js";
import type { AttributeRow, CreateChildrenResponse, DeleteNotesPreview, MetadataResponse } from "@triliumnext/commons";
import type { Request } from "express";
import becca from "../../becca/becca.js";
import type BBranch from "../../becca/entities/bbranch.js";
import ValidationError from "../../errors/validation_error.js";
import blobService from "../../services/blob.js";
import type { Request } from "express";
import type BBranch from "../../becca/entities/bbranch.js";
import type { AttributeRow, CreateChildrenResponse, DeleteNotesPreview, MetadataResponse } from "@triliumnext/commons";
import eraseService from "../../services/erase.js";
import log from "../../services/log.js";
import noteService from "../../services/notes.js";
import sql from "../../services/sql.js";
import TaskContext from "../../services/task_context.js";
import treeService from "../../services/tree.js";
import utils from "../../services/utils.js";
/**
* @swagger
@@ -39,7 +40,7 @@ import type { AttributeRow, CreateChildrenResponse, DeleteNotesPreview, Metadata
* - session: []
* tags: ["data"]
*/
function getNote(req: Request) {
function getNote(req: Request<{ noteId: string }>) {
return becca.getNoteOrThrow(req.params.noteId);
}
@@ -66,7 +67,7 @@ function getNote(req: Request) {
* - session: []
* tags: ["data"]
*/
function getNoteBlob(req: Request) {
function getNoteBlob(req: Request<{ noteId: string }>) {
return blobService.getBlobPojo("notes", req.params.noteId);
}
@@ -93,7 +94,7 @@ function getNoteBlob(req: Request) {
* - session: []
* tags: ["data"]
*/
function getNoteMetadata(req: Request) {
function getNoteMetadata(req: Request<{ noteId: string }>) {
const note = becca.getNoteOrThrow(req.params.noteId);
return {
@@ -126,7 +127,7 @@ function createNote(req: Request) {
} satisfies CreateChildrenResponse;
}
function updateNoteData(req: Request) {
function updateNoteData(req: Request<{ noteId: string }>) {
const { content, attachments } = req.body;
const { noteId } = req.params;
@@ -170,7 +171,7 @@ function updateNoteData(req: Request) {
* - session: []
* tags: ["data"]
*/
function deleteNote(req: Request) {
function deleteNote(req: Request<{ noteId: string }>) {
const noteId = req.params.noteId;
const taskId = req.query.taskId;
const eraseNotes = req.query.eraseNotes === "true";
@@ -197,7 +198,7 @@ function deleteNote(req: Request) {
}
}
function undeleteNote(req: Request) {
function undeleteNote(req: Request<{ noteId: string }>) {
const taskContext = TaskContext.getInstance(utils.randomString(10), "undeleteNotes", null);
noteService.undeleteNote(req.params.noteId, taskContext);
@@ -205,7 +206,7 @@ function undeleteNote(req: Request) {
taskContext.taskSucceeded(null);
}
function sortChildNotes(req: Request) {
function sortChildNotes(req: Request<{ noteId: string }>) {
const noteId = req.params.noteId;
const { sortBy, sortDirection, foldersFirst, sortNatural, sortLocale } = req.body;
@@ -216,7 +217,7 @@ function sortChildNotes(req: Request) {
treeService.sortNotes(noteId, sortBy, reverse, foldersFirst, sortNatural, sortLocale);
}
function protectNote(req: Request) {
function protectNote(req: Request<{ noteId: string; isProtected: string }>) {
const noteId = req.params.noteId;
const note = becca.notes[noteId];
const protect = !!parseInt(req.params.isProtected);
@@ -229,7 +230,7 @@ function protectNote(req: Request) {
taskContext.taskSucceeded(null);
}
function setNoteTypeMime(req: Request) {
function setNoteTypeMime(req: Request<{ noteId: string }>) {
// can't use [] destructuring because req.params is not iterable
const { noteId } = req.params;
const { type, mime } = req.body;
@@ -240,7 +241,7 @@ function setNoteTypeMime(req: Request) {
note.save();
}
function changeTitle(req: Request) {
function changeTitle(req: Request<{ noteId: string }>) {
const noteId = req.params.noteId;
const title = req.body.title;
@@ -267,7 +268,7 @@ function changeTitle(req: Request) {
return note;
}
function duplicateSubtree(req: Request) {
function duplicateSubtree(req: Request<{ noteId: string; parentNoteId: string }>) {
const { noteId, parentNoteId } = req.params;
return noteService.duplicateSubtree(noteId, parentNoteId);
@@ -342,7 +343,7 @@ function getDeleteNotesPreview(req: Request) {
} satisfies DeleteNotesPreview;
}
function forceSaveRevision(req: Request) {
function forceSaveRevision(req: Request<{ noteId: string }>) {
const { noteId } = req.params;
const note = becca.getNoteOrThrow(noteId);
@@ -353,7 +354,7 @@ function forceSaveRevision(req: Request) {
note.saveRevision();
}
function convertNoteToAttachment(req: Request) {
function convertNoteToAttachment(req: Request<{ noteId: string }>) {
const { noteId } = req.params;
const note = becca.getNoteOrThrow(noteId);

View File

@@ -128,7 +128,7 @@ function getOptions() {
return resultMap;
}
function updateOption(req: Request) {
function updateOption(req: Request<{ name: string; value: string }>) {
const { name, value } = req.params;
if (!update(name, value)) {

View File

@@ -1,13 +1,12 @@
"use strict";
import sql from "../../services/sql.js";
import protectedSessionService from "../../services/protected_session.js";
import noteService from "../../services/notes.js";
import becca from "../../becca/becca.js";
import type { Request } from "express";
import type { RecentChangeRow } from "@triliumnext/commons";
import type { Request } from "express";
function getRecentChanges(req: Request) {
import becca from "../../becca/becca.js";
import noteService from "../../services/notes.js";
import protectedSessionService from "../../services/protected_session.js";
import sql from "../../services/sql.js";
function getRecentChanges(req: Request<{ ancestorNoteId: string }>) {
const { ancestorNoteId } = req.params;
let recentChanges: RecentChangeRow[] = [];

View File

@@ -1,18 +1,19 @@
"use strict";
import beccaService from "../../becca/becca_service.js";
import utils from "../../services/utils.js";
import sql from "../../services/sql.js";
import cls from "../../services/cls.js";
import path from "path";
import becca from "../../becca/becca.js";
import blobService from "../../services/blob.js";
import eraseService from "../../services/erase.js";
import type { Request, Response } from "express";
import type BRevision from "../../becca/entities/brevision.js";
import type BNote from "../../becca/entities/bnote.js";
import type { NotePojo } from "../../becca/becca-interface.js";
import { EditedNotesResponse, RevisionItem, RevisionPojo, RevisionRow } from "@triliumnext/commons";
import type { Request, Response } from "express";
import path from "path";
import becca from "../../becca/becca.js";
import beccaService from "../../becca/becca_service.js";
import type { NotePojo } from "../../becca/becca-interface.js";
import type BNote from "../../becca/entities/bnote.js";
import type BRevision from "../../becca/entities/brevision.js";
import blobService from "../../services/blob.js";
import cls from "../../services/cls.js";
import eraseService from "../../services/erase.js";
import sql from "../../services/sql.js";
import utils from "../../services/utils.js";
interface NotePath {
noteId: string;
@@ -26,13 +27,13 @@ interface NotePojoWithNotePath extends NotePojo {
notePath?: string[] | null;
}
function getRevisionBlob(req: Request) {
function getRevisionBlob(req: Request<{ revisionId: string }>) {
const preview = req.query.preview === "true";
return blobService.getBlobPojo("revisions", req.params.revisionId, { preview });
}
function getRevisions(req: Request) {
function getRevisions(req: Request<{ noteId: string }>) {
return becca.getRevisionsFromQuery(
`
SELECT revisions.*,
@@ -45,7 +46,7 @@ function getRevisions(req: Request) {
) satisfies RevisionItem[];
}
function getRevision(req: Request) {
function getRevision(req: Request<{ revisionId: string }>) {
const revision = becca.getRevisionOrThrow(req.params.revisionId);
if (revision.type === "file") {
@@ -85,7 +86,7 @@ function getRevisionFilename(revision: BRevision) {
return filename;
}
function downloadRevision(req: Request, res: Response) {
function downloadRevision(req: Request<{ revisionId: string }>, res: Response) {
const revision = becca.getRevisionOrThrow(req.params.revisionId);
if (!revision.isContentAvailable()) {
@@ -100,13 +101,13 @@ function downloadRevision(req: Request, res: Response) {
res.send(revision.getContent());
}
function eraseAllRevisions(req: Request) {
function eraseAllRevisions(req: Request<{ noteId: string }>) {
const revisionIdsToErase = sql.getColumn<string>("SELECT revisionId FROM revisions WHERE noteId = ?", [req.params.noteId]);
eraseService.eraseRevisions(revisionIdsToErase);
}
function eraseRevision(req: Request) {
function eraseRevision(req: Request<{ revisionId: string }>) {
eraseService.eraseRevisions([req.params.revisionId]);
}
@@ -117,7 +118,7 @@ function eraseAllExcessRevisions() {
});
}
function restoreRevision(req: Request) {
function restoreRevision(req: Request<{ revisionId: string }>) {
const revision = becca.getRevision(req.params.revisionId);
if (revision) {
@@ -166,7 +167,7 @@ function getEditedNotesOnDate(req: Request) {
)
ORDER BY isDeleted
LIMIT 50`,
{ date: `${req.params.date}%` }
{ date: `${req.params.date}%` }
);
let notes = becca.getNotes(noteIds, true);
@@ -204,7 +205,7 @@ function getNotePathData(note: BNote): NotePath | undefined {
return {
noteId: note.noteId,
branchId: branchId,
branchId,
title: noteTitle,
notePath: retPath,
path: retPath.join("/")

View File

@@ -1,11 +1,12 @@
"use strict";
import scriptService, { type Bundle } from "../../services/script.js";
import attributeService from "../../services/attributes.js";
import becca from "../../becca/becca.js";
import syncService from "../../services/sync.js";
import sql from "../../services/sql.js";
import type { Request } from "express";
import becca from "../../becca/becca.js";
import attributeService from "../../services/attributes.js";
import scriptService, { type Bundle } from "../../services/script.js";
import sql from "../../services/sql.js";
import syncService from "../../services/sync.js";
import { safeExtractMessageAndStackFromError } from "../../services/utils.js";
interface ScriptBody {
@@ -43,7 +44,7 @@ async function exec(req: Request) {
}
}
function run(req: Request) {
function run(req: Request<{ noteId: string }>) {
const note = becca.getNoteOrThrow(req.params.noteId);
const result = scriptService.executeNote(note, { originEntity: note });
@@ -71,23 +72,23 @@ function getStartupBundles(req: Request) {
if (!process.env.TRILIUM_SAFE_MODE) {
if (req.query.mobile === "true") {
return getBundlesWithLabel("run", "mobileStartup");
} else {
return getBundlesWithLabel("run", "frontendStartup");
}
} else {
return [];
}
}
return getBundlesWithLabel("run", "frontendStartup");
}
return [];
}
function getWidgetBundles() {
if (!process.env.TRILIUM_SAFE_MODE) {
return getBundlesWithLabel("widget");
} else {
return [];
}
}
return [];
}
function getRelationBundles(req: Request) {
function getRelationBundles(req: Request<{ noteId: string, relationName: string }>) {
const noteId = req.params.noteId;
const note = becca.getNoteOrThrow(noteId);
const relationName = req.params.relationName;
@@ -116,7 +117,7 @@ function getRelationBundles(req: Request) {
return bundles;
}
function getBundle(req: Request) {
function getBundle(req: Request<{ noteId: string }>) {
const note = becca.getNoteOrThrow(req.params.noteId);
const { script, params } = req.body ?? {};

View File

@@ -1,19 +1,19 @@
"use strict";
import type { Request } from "express";
import becca from "../../becca/becca.js";
import SearchContext from "../../services/search/search_context.js";
import searchService, { EMPTY_RESULT, type SearchNoteResult } from "../../services/search/services/search.js";
import beccaService from "../../becca/becca_service.js";
import ValidationError from "../../errors/validation_error.js";
import attributeFormatter from "../../services/attribute_formatter.js";
import bulkActionService from "../../services/bulk_actions.js";
import cls from "../../services/cls.js";
import attributeFormatter from "../../services/attribute_formatter.js";
import ValidationError from "../../errors/validation_error.js";
import type SearchResult from "../../services/search/search_result.js";
import hoistedNoteService from "../../services/hoisted_note.js";
import beccaService from "../../becca/becca_service.js";
import SearchContext from "../../services/search/search_context.js";
import type SearchResult from "../../services/search/search_result.js";
import searchService, { EMPTY_RESULT, type SearchNoteResult } from "../../services/search/services/search.js";
function searchFromNote(req: Request): SearchNoteResult {
function searchFromNote(req: Request<{ noteId: string }>): SearchNoteResult {
const note = becca.getNoteOrThrow(req.params.noteId);
if (!note) {
@@ -28,7 +28,7 @@ function searchFromNote(req: Request): SearchNoteResult {
return searchService.searchFromNote(note);
}
function searchAndExecute(req: Request) {
function searchAndExecute(req: Request<{ noteId: string }>) {
const note = becca.getNoteOrThrow(req.params.noteId);
if (!note) {
@@ -45,7 +45,7 @@ function searchAndExecute(req: Request) {
bulkActionService.executeActionsFromNote(note, searchResultNoteIds);
}
function quickSearch(req: Request) {
function quickSearch(req: Request<{ searchString: string }>) {
const { searchString } = req.params;
const searchContext = new SearchContext({
@@ -82,7 +82,7 @@ function quickSearch(req: Request) {
highlightedContentSnippet: result.highlightedContentSnippet,
attributeSnippet: result.attributeSnippet,
highlightedAttributeSnippet: result.highlightedAttributeSnippet,
icon: icon
icon
};
});
@@ -90,12 +90,12 @@ function quickSearch(req: Request) {
return {
searchResultNoteIds: resultNoteIds,
searchResults: searchResults,
searchResults,
error: searchContext.getError()
};
}
function search(req: Request) {
function search(req: Request<{ searchString: string }>) {
const { searchString } = req.params;
const searchContext = new SearchContext({

View File

@@ -1,12 +1,10 @@
"use strict";
import { SimilarNoteResponse } from "@triliumnext/commons";
import type { Request } from "express";
import similarityService from "../../becca/similarity.js";
import becca from "../../becca/becca.js";
import { SimilarNoteResponse } from "@triliumnext/commons";
import similarityService from "../../becca/similarity.js";
async function getSimilarNotes(req: Request) {
async function getSimilarNotes(req: Request<{ noteId: string }>) {
const noteId = req.params.noteId;
const _note = becca.getNoteOrThrow(noteId);

View File

@@ -6,33 +6,33 @@ import dateNoteService from "../../services/date_notes.js";
import specialNotesService, { type LauncherType } from "../../services/special_notes.js";
import sql from "../../services/sql.js";
function getInboxNote(req: Request) {
function getInboxNote(req: Request<{ date: string }>) {
return specialNotesService.getInboxNote(req.params.date);
}
function getDayNote(req: Request) {
function getDayNote(req: Request<{ date: string }>) {
const calendarRootId = req.query.calendarRootId;
const calendarRoot = typeof calendarRootId === "string" ? becca.getNoteOrThrow(calendarRootId) : null;
return dateNoteService.getDayNote(req.params.date, calendarRoot);
}
function getWeekFirstDayNote(req: Request) {
function getWeekFirstDayNote(req: Request<{ date: string }>) {
return dateNoteService.getWeekFirstDayNote(req.params.date);
}
function getWeekNote(req: Request) {
function getWeekNote(req: Request<{ week: string }>) {
return dateNoteService.getWeekNote(req.params.week);
}
function getMonthNote(req: Request) {
function getMonthNote(req: Request<{ month: string }>) {
return dateNoteService.getMonthNote(req.params.month);
}
function getQuarterNote(req: Request) {
function getQuarterNote(req: Request<{ quarter: string }>) {
return dateNoteService.getQuarterNote(req.params.quarter);
}
function getYearNote(req: Request) {
function getYearNote(req: Request<{ year: string }>) {
return dateNoteService.getYearNote(req.params.year);
}
@@ -90,7 +90,7 @@ function getHoistedNote() {
return becca.getNote(cls.getHoistedNoteId());
}
function createLauncher(req: Request) {
function createLauncher(req: Request<{ parentNoteId: string, launcherType: string }>) {
return specialNotesService.createLauncher({
parentNoteId: req.params.parentNoteId,
// TODO: Validate the parameter
@@ -98,7 +98,7 @@ function createLauncher(req: Request) {
});
}
function resetLauncher(req: Request) {
function resetLauncher(req: Request<{ noteId: string }>) {
return specialNotesService.resetLauncher(req.params.noteId);
}

View File

@@ -1,9 +1,8 @@
"use strict";
import sql from "../../services/sql.js";
import becca from "../../becca/becca.js";
import type { Request } from "express";
import becca from "../../becca/becca.js";
import ValidationError from "../../errors/validation_error.js";
import sql from "../../services/sql.js";
import { safeExtractMessageAndStackFromError } from "../../services/utils.js";
interface Table {
@@ -25,7 +24,7 @@ function getSchema() {
return tables;
}
function execute(req: Request) {
function execute(req: Request<{ noteId: string }>) {
const note = becca.getNoteOrThrow(req.params.noteId);
const content = note.getContent();

View File

@@ -1,7 +1,8 @@
import sql from "../../services/sql.js";
import becca from "../../becca/becca.js";
import type { Request } from "express";
import { NoteSizeResponse, SubtreeSizeResponse } from "@triliumnext/commons";
import type { Request } from "express";
import becca from "../../becca/becca.js";
import sql from "../../services/sql.js";
function getNoteSize(req: Request) {
const { noteId } = req.params;
@@ -26,7 +27,7 @@ function getNoteSize(req: Request) {
} satisfies NoteSizeResponse;
}
function getSubtreeSize(req: Request) {
function getSubtreeSize(req: Request<{ noteId: string }>) {
const note = becca.getNoteOrThrow(req.params.noteId);
const subTreeNoteIds = note.getSubtreeNoteIds();

View File

@@ -1,21 +1,20 @@
"use strict";
import syncService from "../../services/sync.js";
import syncUpdateService from "../../services/sync_update.js";
import entityChangesService from "../../services/entity_changes.js";
import sql from "../../services/sql.js";
import sqlInit from "../../services/sql_init.js";
import optionService from "../../services/options.js";
import contentHashService from "../../services/content_hash.js";
import log from "../../services/log.js";
import syncOptions from "../../services/sync_options.js";
import utils, { safeExtractMessageAndStackFromError } from "../../services/utils.js";
import ws from "../../services/ws.js";
import { type EntityChange, SyncTestResponse } from "@triliumnext/commons";
import type { Request } from "express";
import { t } from "i18next";
import ValidationError from "../../errors/validation_error.js";
import consistencyChecksService from "../../services/consistency_checks.js";
import { t } from "i18next";
import { SyncTestResponse, type EntityChange } from "@triliumnext/commons";
import contentHashService from "../../services/content_hash.js";
import entityChangesService from "../../services/entity_changes.js";
import log from "../../services/log.js";
import optionService from "../../services/options.js";
import sql from "../../services/sql.js";
import sqlInit from "../../services/sql_init.js";
import syncService from "../../services/sync.js";
import syncOptions from "../../services/sync_options.js";
import syncUpdateService from "../../services/sync_update.js";
import utils, { safeExtractMessageAndStackFromError } from "../../services/utils.js";
import ws from "../../services/ws.js";
async function testSync(): Promise<SyncTestResponse> {
try {
@@ -287,10 +286,10 @@ function update(req: Request) {
if (pageIndex !== pageCount - 1) {
return;
} else {
body = JSON.parse(partialRequests[requestId].payload);
delete partialRequests[requestId];
}
body = JSON.parse(partialRequests[requestId].payload);
delete partialRequests[requestId];
}
const { entities, instanceId } = body;
@@ -314,7 +313,7 @@ function syncFinished() {
sqlInit.setDbAsInitialized();
}
function queueSector(req: Request) {
function queueSector(req: Request<{ entityName: string; sector: string }>) {
const entityName = utils.sanitizeSqlIdentifier(req.params.entityName);
const sector = utils.sanitizeSqlIdentifier(req.params.sector);

View File

@@ -1,15 +1,17 @@
import express, { type RequestHandler } from "express";
import type { ParamsDictionary } from "express-serve-static-core";
import multer from "multer";
import log from "../services/log.js";
import cls from "../services/cls.js";
import sql from "../services/sql.js";
import entityChangesService from "../services/entity_changes.js";
import AbstractBeccaEntity from "../becca/entities/abstract_becca_entity.js";
import NotFoundError from "../errors/not_found_error.js";
import ValidationError from "../errors/validation_error.js";
import auth from "../services/auth.js";
import { doubleCsrfProtection as csrfMiddleware } from "./csrf_protection.js";
import cls from "../services/cls.js";
import entityChangesService from "../services/entity_changes.js";
import log from "../services/log.js";
import sql from "../services/sql.js";
import { safeExtractMessageAndStackFromError } from "../services/utils.js";
import { doubleCsrfProtection as csrfMiddleware } from "./csrf_protection.js";
const MAX_ALLOWED_FILE_SIZE_MB = 250;
export const router = express.Router();
@@ -20,8 +22,8 @@ type HttpMethod = "all" | "get" | "post" | "put" | "delete" | "patch" | "options
export type ApiResultHandler = (req: express.Request, res: express.Response, result: unknown) => number;
type NotAPromise<T> = T & { then?: void };
export type ApiRequestHandler = (req: express.Request, res: express.Response, next: express.NextFunction) => unknown;
export type SyncRouteRequestHandler = (req: express.Request, res: express.Response, next: express.NextFunction) => NotAPromise<object> | number | string | void | null;
export type ApiRequestHandler<P extends ParamsDictionary> = (req: express.Request<P>, res: express.Response, next: express.NextFunction) => unknown;
export type SyncRouteRequestHandler<P extends ParamsDictionary> = (req: express.Request<P>, res: express.Response, next: express.NextFunction) => NotAPromise<object> | number | string | void | null;
/** Handling common patterns. If entity is not caught, serialization to JSON will fail */
function convertEntitiesToPojo(result: unknown) {
@@ -67,9 +69,9 @@ export function apiResultHandler(req: express.Request, res: express.Response, re
return send(res, statusCode, response);
} else if (result === undefined) {
return send(res, 204, "");
} else {
return send(res, 200, result);
}
return send(res, 200, result);
}
function send(res: express.Response, statusCode: number, response: unknown) {
@@ -81,34 +83,34 @@ function send(res: express.Response, statusCode: number, response: unknown) {
res.status(statusCode).send(response);
return response.length;
} else {
const json = JSON.stringify(response);
res.setHeader("Content-Type", "application/json");
res.status(statusCode).send(json);
return json.length;
}
const json = JSON.stringify(response);
res.setHeader("Content-Type", "application/json");
res.status(statusCode).send(json);
return json.length;
}
export function apiRoute(method: HttpMethod, path: string, routeHandler: SyncRouteRequestHandler) {
export function apiRoute<P extends ParamsDictionary>(method: HttpMethod, path: string, routeHandler: SyncRouteRequestHandler<P>) {
route(method, path, [auth.checkApiAuth, csrfMiddleware], routeHandler, apiResultHandler);
}
export function asyncApiRoute(method: HttpMethod, path: string, routeHandler: ApiRequestHandler) {
export function asyncApiRoute<P extends ParamsDictionary>(method: HttpMethod, path: string, routeHandler: ApiRequestHandler<P>) {
asyncRoute(method, path, [auth.checkApiAuth, csrfMiddleware], routeHandler, apiResultHandler);
}
export function route(method: HttpMethod, path: string, middleware: express.Handler[], routeHandler: SyncRouteRequestHandler, resultHandler: ApiResultHandler | null = null) {
export function route<P extends ParamsDictionary>(method: HttpMethod, path: string, middleware: express.Handler[], routeHandler: SyncRouteRequestHandler<P>, resultHandler: ApiResultHandler | null = null) {
internalRoute(method, path, middleware, routeHandler, resultHandler, true);
}
export function asyncRoute(method: HttpMethod, path: string, middleware: express.Handler[], routeHandler: ApiRequestHandler, resultHandler: ApiResultHandler | null = null) {
export function asyncRoute<P extends ParamsDictionary>(method: HttpMethod, path: string, middleware: express.Handler[], routeHandler: ApiRequestHandler<P>, resultHandler: ApiResultHandler | null = null) {
internalRoute(method, path, middleware, routeHandler, resultHandler, false);
}
function internalRoute(method: HttpMethod, path: string, middleware: express.Handler[], routeHandler: ApiRequestHandler, resultHandler: ApiResultHandler | null = null, transactional: boolean) {
router[method](path, ...(middleware as express.Handler[]), (req: express.Request, res: express.Response, next: express.NextFunction) => {
function internalRoute<P extends ParamsDictionary>(method: HttpMethod, path: string, middleware: express.Handler[], routeHandler: ApiRequestHandler<P>, resultHandler: ApiResultHandler | null = null, transactional: boolean) {
router[method](path, ...(middleware as express.Handler[]), (req: express.Request<P>, res: express.Response, next: express.NextFunction) => {
const start = Date.now();
try {
@@ -193,7 +195,7 @@ export function createUploadMiddleware(): RequestHandler {
const uploadMiddleware = createUploadMiddleware();
export const uploadMiddlewareWithErrorHandling = function (req: express.Request, res: express.Response, next: express.NextFunction) {
uploadMiddleware(req, res, function (err) {
uploadMiddleware(req, res, (err) => {
if (err?.code === "LIMIT_FILE_SIZE") {
res.setHeader("Content-Type", "text/plain").status(400).send(`Cannot upload file because it excceeded max allowed file size of ${MAX_ALLOWED_FILE_SIZE_MB} MiB`);
} else {

View File

@@ -10,14 +10,13 @@ import etapiBackupRoute from "../etapi/backup.js";
import etapiBranchRoutes from "../etapi/branches.js";
import etapiMetricsRoute from "../etapi/metrics.js";
import etapiNoteRoutes from "../etapi/notes.js";
import etapiRevisionsRoutes from "../etapi/revisions.js";
import etapiSpecRoute from "../etapi/spec.js";
import etapiSpecialNoteRoutes from "../etapi/special_notes.js";
import etapiRevisionsRoutes from "../etapi/revisions.js";
import auth from "../services/auth.js";
import openID from '../services/open_id.js';
import { isElectron } from "../services/utils.js";
import shareRoutes from "../share/routes.js";
import appInfoRoute from "./api/app_info.js";
import attachmentsApiRoute from "./api/attachments.js";
import attributesRoute from "./api/attributes.js";
@@ -35,12 +34,10 @@ import fontsRoute from "./api/fonts.js";
import imageRoute from "./api/image.js";
import importRoute from "./api/import.js";
import keysRoute from "./api/keys.js";
import loginApiRoute from "./api/login.js";
import metricsRoute from "./api/metrics.js";
import noteMapRoute from "./api/note_map.js";
import notesApiRoute from "./api/notes.js";
import optionsApiRoute from "./api/options.js";
import otherRoute from "./api/other.js";
import passwordApiRoute from "./api/password.js";

View File

@@ -21,15 +21,18 @@
},
"note_types": {
"canvas_title": "कैनवास",
"mindmap_title": "माइंडमैप"
"mindmap_title": "माइंडमैप",
"file_title": "फ़ाइल नोट्स"
},
"extensibility_benefits": {
"share_title": "वेब पर नोट्स शेयर करें",
"share_description": "अगर आपके पास सर्वर है, तो इसका उपयोग अपने नोट्स के एक हिस्से को अन्य लोगों के साथ शेयर करने के लिए किया जा सकता है।"
"share_description": "अगर आपके पास सर्वर है, तो इसका उपयोग अपने नोट्स के एक हिस्से को अन्य लोगों के साथ शेयर करने के लिए किया जा सकता है।",
"import_export_title": "इंपोर्ट/एक्सपोर्ट"
},
"collections": {
"calendar_title": "कैलेंडर",
"table_title": "टेबल"
"table_title": "टेबल",
"board_title": "कानबान बोर्ड"
},
"download_now": {
"linux_small": "लिनक्स के लिए",

View File

@@ -19,6 +19,11 @@
"note_structure_title": "Not yapısı",
"note_structure_description": "Notlar hiyerarşik olarak düzenlenebilir. Her not 'alt notlar' içerebildiği için klasörlere ihtiyaç duyulmaz. Tek bir not, hiyerarşinin birden fazla noktasına eklenebilir.",
"attributes_description": "Notlar arasında ilişkiler kurun veya kolay kategorizasyon için etiketler ekleyin. Tablolarda ve panolarda kullanılabilen yapılandırılmış bilgileri eklemek için öne çıkan öznitelikleri kullanın.",
"hoisting_description": "Kişisel ve iş notlarınızı bir çalışma alanı altında gruplandırarak kolayca ayırın; bu sayede not ağacınız yalnızca belirli bir not kümesini gösterecek şekilde odaklanacaktır."
"hoisting_description": "Kişisel ve iş notlarınızı bir çalışma alanı altında gruplandırarak kolayca ayırın; bu sayede not ağacınız yalnızca belirli bir not kümesini gösterecek şekilde odaklanacaktır.",
"attributes_title": "Not etiketleri ve ilişkileri"
},
"productivity_benefits": {
"title": "Üretkenlik ve güvenlik",
"revisions_title": "Note düzenlemeleri"
}
}

315
docs/README-ar.md vendored
View File

@@ -41,7 +41,7 @@ script)](./README-ZH_TW.md) | [English](../README.md) | [French](./README-fr.md)
- [الإصدار الليلي](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
إصدار تطوير غير مستقر، يتم تحديثه يوميًا بأحدث الميزات والإصلاحات.
## 📚توثيق
## 📚 الوثائق
**يمكنكم الاطلاع على وثائقنا الشاملة على الرابط التالي:
[docs.triliumnotes.org](https://docs.triliumnotes.org/)**
@@ -61,33 +61,35 @@ script)](./README-ZH_TW.md) | [English](../README.md) | [French](./README-fr.md)
- [ترقية تريليوم
للملاحظات](https://docs.triliumnotes.org/user-guide/setup/upgrading)
- [مفاهيم ومميزات
اساسية](https://docs.triliumnotes.org/user-guide/concepts/notes)
أساسية](https://docs.triliumnotes.org/user-guide/concepts/notes)
- [أنماط قاعدة المعرفة
الشخصية](https://docs.triliumnotes.org/user-guide/misc/patterns-of-personal-knowledge)
## 🎁الميزات
## 🎁 المميزات
* يمكن ترتيب النوتات الموسيقية في شجرة ذات عمق غير محدود. ويمكن وضع نوتة واحدة
في أماكن متعددة في الشجرة (انظر
* يمكن تنظيم الملاحظات في شجرة ذات عمق غير محدود. كما يمكن وضع الملاحظة الواحدة
في أماكن متعددة داخل الشجرة (راجع
[الاستنساخ](https://docs.triliumnotes.org/user-guide/concepts/notes/cloning))
* محرر ملاحظات WYSIWYG غني يتضمن على سبيل المثال الجداول والصور
و[الرياضيات](https://docs.triliumnotes.org/user-guide/note-types/text) مع
تنسيق تلقائي لـ Markdown[2]
* دعم تحرير [الملاحظات التي تحتوي على شفرة
المصدر](https://docs.triliumnotes.org/user-guide/note-types/code)، بما في ذلك
تمييز بناء الجملة
* التنقل السريع والسهل بين الملاحظات
(https://docs.triliumnotes.org/user-guide/concepts/navigation/note-navigation)،
والبحث في النص الكامل، ورفع الملاحظات
(https://docs.triliumnotes.org/user-guide/concepts/navigation/note-hoisting)
* سلس [ملاحظة حول إصدار
النظام](https://docs.triliumnotes.org/user-guide/concepts/notes/note-revisions)
Markdown [تنسيق
تلقائي](https://docs.triliumnotes.org/user-guide/note-types/text/markdown-formatting)
* دعم تحرير [ملاحظات التعليمات
البرمجية](https://docs.triliumnotes.org/user-guide/note-types/code)، بما في
ذلك تمييز بناء الجملة
* [التنقل بين
الملاحظات](https://docs.triliumnotes.org/user-guide/concepts/navigation/note-navigation)
سهل وسريع، مع دعم البحث في النص الكامل، و[رفع
الملاحظات](https://docs.triliumnotes.org/user-guide/concepts/navigation/note-hoisting)
* نظام [إصدارات
الملاحظات](https://docs.triliumnotes.org/user-guide/concepts/notes/note-revisions)
السلس
* يمكن استخدام
[السمات](https://docs.triliumnotes.org/user-guide/advanced-usage/attributes)
لتنظيم الملاحظات والاستعلام عنها و[البرمجة
النصية](https://docs.triliumnotes.org/user-guide/scripts) المتقدمة
* UI available in English, German, Spanish, French, Romanian, and Chinese
(simplified and traditional)
* واجهة المستخدم متوفرة باللغات الإنجليزية والألمانية والإسبانية والفرنسية
والرومانية والصينية (المبسطة والتقليدية)
* تكامل مباشر مع [أنظمة الهوية المفتوحة OpenID وكلمات المرور المؤقتة
TOTP](https://docs.triliumnotes.org/user-guide/setup/server/mfa) لتسجيل دخول
أكثر أماناً
@@ -118,131 +120,129 @@ script)](./README-ZH_TW.md) | [English](../README.md) | [French](./README-fr.md)
المتقدمة](https://docs.triliumnotes.org/user-guide/advanced-usage/advanced-showcases)
* [واجهة REST
API](https://docs.triliumnotes.org/user-guide/advanced-usage/etapi) للأتمتة
* Scales well in both usability and performance upwards of 100 000 notes
* Touch optimized [mobile
frontend](https://docs.triliumnotes.org/user-guide/setup/mobile-frontend) for
smartphones and tablets
* Built-in [dark
theme](https://docs.triliumnotes.org/user-guide/concepts/themes), support for
user themes
* [Evernote](https://docs.triliumnotes.org/user-guide/concepts/import-export/evernote)
and [Markdown import &
export](https://docs.triliumnotes.org/user-guide/concepts/import-export/markdown)
* [Web Clipper](https://docs.triliumnotes.org/user-guide/setup/web-clipper) for
easy saving of web content
* Customizable UI (sidebar buttons, user-defined widgets, ...)
* [Metrics](https://docs.triliumnotes.org/user-guide/advanced-usage/metrics),
along with a Grafana Dashboard.
* يتميز بسهولة الاستخدام والأداء العاليين، ويستوعب أكثر من 100,000 ملاحظة
* "[واجهة جوال](https://docs.triliumnotes.org/user-guide/setup/mobile-frontend)
محسنة للمس، مخصصة للهواتف الذكية والأجهزة اللوحية"
* [الوضع الداكن](https://docs.triliumnotes.org/user-guide/concepts/themes)
المدمج، ودعم سمات المستخدم
* [إيفيرنوت
(Evernote)](https://docs.triliumnotes.org/user-guide/concepts/import-export/evernote)
و[استيراد وتصدير ملفات
Markdown](https://docs.triliumnotes.org/user-guide/concepts/import-export/markdown)
* [أداة قص الويب](https://docs.triliumnotes.org/user-guide/setup/web-clipper)
لحفظ محتوى الويب بسهولة
* واجهة مستخدم قابلة للتخصيص (أزرار الشريط الجانبي، أدوات المستخدم المحددة، ...)
* [مؤشرات
الأداء](https://docs.triliumnotes.org/user-guide/advanced-usage/metrics)، مع
لوحة تحكم Grafana.
Check out the following third-party resources/communities for more TriliumNext
related goodies:
اطلع على الموارد/المجتمعات الخارجية التالية لمزيد من المعلومات المفيدة
المتعلقة بـ TriliumNext:
- [awesome-trilium](https://github.com/Nriver/awesome-trilium) for 3rd party
themes, scripts, plugins and more.
- [TriliumRocks!](https://trilium.rocks/) for tutorials, guides, and much more.
- [awesome-trillium](https://github.com/Nriver/awesome-trilium) للقوالب والبرامج
النصية والإضافات الخارجية والمزيد.
- [TriliumRocks!](https://trilium.rocks/) للحصول على دروس تعليمية، وأدلة، وغير
ذلك الكثير.
## لماذا تريليوم التالي؟
## ؟لماذا TriliumNext؟
The original Trilium developer ([Zadam](https://github.com/zadam)) has
graciously given the Trilium repository to the community project which resides
at https://github.com/TriliumNext
قام مطور Trilium الأصلي ([Zadam](https://github.com/zadam)) مشكورًا بإهداء
مستودع Trilium إلى مشروع المجتمع الموجود على الرابط التالي:
https://github.com/TriliumNext
### ⬆️ الهجرة من Zadam الى تريليوم؟
### ⬆️الانتقال من Zadam/Trilium؟
There are no special migration steps to migrate from a zadam/Trilium instance to
a TriliumNext/Trilium instance. Simply [install
TriliumNext/Trilium](#-installation) as usual and it will use your existing
database.
لا توجد خطوات انتقال خاصة للانتقال من نسخة zadam/Trilium إلى نسخة
TriliumNext/Trilium. ما عليك سوى تثبيت TriliumNext/Trilium كالمعتاد، وسيستخدم
قاعدة بياناتك الحالية.
Versions up to and including
[v0.90.4](https://github.com/TriliumNext/Trilium/releases/tag/v0.90.4) are
compatible with the latest zadam/trilium version of
[v0.63.7](https://github.com/zadam/trilium/releases/tag/v0.63.7). Any later
versions of TriliumNext/Trilium have their sync versions incremented which
prevents direct migration.
الإصدارات حتى الإصدار
[v0.90.4](https://github.com/TriliumNext/Trilium/releases/tag/v0.90.4) متوافقة
مع أحدث إصدار من zadam/trillium وهو [v0.63.7]{2]. أما الإصدارات اللاحقة من
TriliumNext/Trilium، فقد تم تحديث أرقام المزامنة الخاصة بها، مما يمنع الترقية
المباشرة.
## 💬تحدث معنا
## 💬 ناقش معنا
Feel free to join our official conversations. We would love to hear what
features, suggestions, or issues you may have!
لا تترددوا في الانضمام إلى محادثاتنا الرسمية. يسعدنا أن نسمع عن الميزات أو
الاقتراحات أو المشاكل التي قد تواجهونها!
- [Matrix](https://matrix.to/#/#triliumnext:matrix.org) (For synchronous
discussions.)
- The `General` Matrix room is also bridged to
[XMPP](xmpp:discuss@trilium.thisgreat.party?join)
- [Github Discussions](https://github.com/TriliumNext/Trilium/discussions) (For
asynchronous discussions.)
- [Github Issues](https://github.com/TriliumNext/Trilium/issues) (For bug
reports and feature requests.)
- [ماتريكس (Matrix)](https://matrix.to/#/#triliumnext:matrix.org) (للمناقشات
المتزامنة.)
- غرفة ماتريكس `العامة` مرتبطة أيضاً بـ
[XMPP](xmpp:discuss@trilium.thisgreat.party?join) (Extensible Messaging and
Presence Protocol)
- [مناقشات GitHub](https://github.com/TriliumNext/Trilium/discussions)
(للمناقشات غير المتزامنة.)
- [Github Issues](https://github.com/TriliumNext/Trilium/issues) (لتقديم تقارير
الأخطاء وطلبات الميزات.)
## 🏗️ تثبيت
## 🏗️ التثبيت
### ويندوز / نظام تشغيل ماك
### ويندوز (Windows) / نظام تشغيل ماك (MacOS)
Download the binary release for your platform from the [latest release
page](https://github.com/TriliumNext/Trilium/releases/latest), unzip the package
and run the `trilium` executable.
نزل الإصدار الثنائي (Binary) المناسب لمنصتك من [صفحة أحدث
الإصدارات](https://github.com/TriliumNext/Trilium/releases/latest)، ثم فك ضغط
الحزمة وشغّل ملف `trilium` التنفيذي.
### لينكس
### لينكس (Linux)
If your distribution is listed in the table below, use your distribution's
package.
إذا كانت توزيعتك مدرجة في الجدول أدناه، فاستخدم الحزمة الخاصة بتوزيعتك.
[![Packaging
status](https://repology.org/badge/vertical-allrepos/triliumnext.svg)](https://repology.org/project/triliumnext/versions)
[![حالة
الحزم](https://repology.org/badge/vertical-allrepos/triliumnext.svg)](https://repology.org/project/triliumnext/versions)
You may also download the binary release for your platform from the [latest
release page](https://github.com/TriliumNext/Trilium/releases/latest), unzip the
package and run the `trilium` executable.
يمكنك أيضًا تنزيل الإصدار الثنائي لمنصتك من [صفحة أحدث
إصدار](https://github.com/TriliumNext/Trilium/releases/latest)، وفك ضغط الحزمة
وتشغيل الملف التنفيذي `trillium`.
TriliumNext is also provided as a Flatpak, but not yet published on FlatHub.
يتم توفير TriliumNext أيضًا كـ Flatpak، ولكن لم يتم نشره بعد على FlatHub.
### مستعرض( اي نظام تشغيل)
### متصفح (أي نظام تشغيل)
If you use a server installation (see below), you can directly access the web
interface (which is almost identical to the desktop app).
إذا كنت تستخدم تثبيت الخادم (انظر أدناه)، فيمكنك الوصول مباشرة إلى واجهة الويب
(وهي مطابقة تقريبًا لتطبيق سطح المكتب).
Currently only the latest versions of Chrome & Firefox are supported (and
tested).
حالياً، يتم دعم أحدث إصدارات متصفحي Chrome و Firefox فقط (والتي تم اختبارها).
### هاتف المحمول
### الهاتف المحمول
To use TriliumNext on a mobile device, you can use a mobile web browser to
access the mobile interface of a server installation (see below).
لاستخدام TriliumNext على الأجهزة المحمولة، يمكنك استخدام المتصفح للوصول إلى
واجهة الجوال الخاصة بنسخة الخادم المثبتة (انظر أدناه).
See issue https://github.com/TriliumNext/Trilium/issues/4962 for more
information on mobile app support.
راجع المشكلة رقم https://github.com/TriliumNext/Trilium/issues/4962 لمزيد من
المعلومات حول دعم إصدار الهاتف المحمول.
If you prefer a native Android app, you can use
إذا كنت تفضل تطبيقًا أصليًا لنظام Android، يمكنك استخدام
[TriliumDroid](https://apt.izzysoft.de/fdroid/index/apk/eu.fliegendewurst.triliumdroid).
Report bugs and missing features at [their
repository](https://github.com/FliegendeWurst/TriliumDroid). Note: It is best to
disable automatic updates on your server installation (see below) when using
TriliumDroid since the sync version must match between Trilium and TriliumDroid.
أبلغ عن الأخطاء والميزات المفقودة في
[مستودعهم](https://github.com/FliegendeWurst/TriliumDroid). ملاحظة: يُفضل تعطيل
التحديثات التلقائية على تثبيت الخادم الخاص بك (انظر أدناه) عند استخدام
TriliumDroid، حيث يجب أن تتطابق نسخة المزامنة بين Trilium وTriliumDroid.
### الخادم
To install TriliumNext on your own server (including via Docker from
[Dockerhub](https://hub.docker.com/r/triliumnext/trilium)) follow [the server
installation docs](https://docs.triliumnotes.org/user-guide/setup/server).
لتثبيت TriliumNext على خادمك الخاص (بما في ذلك عبر Docker من
[Dockerhub](https://hub.docker.com/r/triliumnext/trilium)) اتبع [وثائق تثبيت
الخادم]{2].
## 💻 المساهمة
### ترجمات
### الترجمات
If you are a native speaker, help us translate Trilium by heading over to our
[Weblate page](https://hosted.weblate.org/engage/trilium/).
إذا كنت متحدثًا أصليًا للغة، فساعدنا في ترجمة Trilium من خلال التوجه إلى [صفحة
الويب]{1].
Here's the language coverage we have so far:
إليك قائمة نسبة اكتمال اللغات المدعومة حتى الآن:
[![Translation
status](https://hosted.weblate.org/widget/trilium/multi-auto.svg)](https://hosted.weblate.org/engage/trilium/)
[![حالة
الترجمة](https://hosted.weblate.org/widget/trilium/multi-auto.svg)](https://hosted.weblate.org/engage/trilium/)
### كود
### التعليمات البرمجية
Download the repository, install dependencies using `pnpm` and then run the
server (available at http://localhost:8080):
قم بتنزيل المستودع، وقم بتثبيت التبعيات باستخدام `pnpm`، ثم قم بتشغيل الخادم
(المتاح على http://localhost:8080):
```shell
git clone https://github.com/TriliumNext/Trilium.git
cd Trilium
@@ -252,8 +252,8 @@ pnpm run server:start
### التوثيق
Download the repository, install dependencies using `pnpm` and then run the
environment required to edit the documentation:
قم بتنزيل المستودع، وقم بتثبيت التبعيات باستخدام `pnpm`، ثم قم بتشغيل البيئة
المطلوبة لتحرير الوثائق:
```shell
git clone https://github.com/TriliumNext/Trilium.git
cd Trilium
@@ -262,8 +262,8 @@ pnpm edit-docs:edit-docs
```
### بناء الملف التنفيذي
Download the repository, install dependencies using `pnpm` and then build the
desktop app for Windows:
قم بتنزيل المستودع، وقم بتثبيت التبعيات باستخدام `pnpm`، ثم قم ببناء تطبيق سطح
المكتب لنظام التشغيل ويندوز (Windows):
```shell
git clone https://github.com/TriliumNext/Trilium.git
cd Trilium
@@ -271,71 +271,66 @@ pnpm install
pnpm run --filter desktop electron-forge:make --arch=x64 --platform=win32
```
For more details, see the [development
docs](https://github.com/TriliumNext/Trilium/tree/main/docs/Developer%20Guide/Developer%20Guide).
لمزيد من التفاصيل، راجع [وثائق
التطوير](https://github.com/TriliumNext/Trilium/tree/main/docs/Developer%20Guide/Developer%20Guide).
### توثيق المطور
### وثائق المطورين
Please view the [documentation
guide](https://github.com/TriliumNext/Trilium/blob/main/docs/Developer%20Guide/Developer%20Guide/Environment%20Setup.md)
for details. If you have more questions, feel free to reach out via the links
described in the "Discuss with us" section above.
يرجى الاطلاع على [دليل
التوثيق](https://github.com/TriliumNext/Trilium/blob/main/docs/Developer%20Guide/Developer%20Guide/Environment%20Setup.md)
لمزيد من التفاصيل. إذا كانت لديكم أي استفسارات أخرى، فلا تترددوا في التواصل معنا
عبر الروابط الموضحة في قسم "ناقش معنا" أعلاه.
## 👏 اشادات
## 👏 شكر خاص
* [zadam](https://github.com/zadam) for the original concept and implementation
of the application.
* [Sarah Hussein](https://github.com/Sarah-Hussein) for designing the
application icon.
* [nriver](https://github.com/nriver) for his work on internationalization.
* [Thomas Frei](https://github.com/thfrei) for his original work on the Canvas.
* [antoniotejada](https://github.com/nriver) for the original syntax highlight
widget.
* [Dosu](https://dosu.dev/) for providing us with the automated responses to
GitHub issues and discussions.
* [Tabler Icons](https://tabler.io/icons) for the system tray icons.
* [zadam](https://github.com/zadam): للمفهوم الأصلي وتنفيذ التطبيق.
* [سارة حسين (Sarah Hussein)](https://github.com/Sarah-Hussein): لتصميم أيقونة
التطبيق.
* [nriver](https://github.com/nriver): لعمله على تدويل التطبيق (دعم اللغات).
* [Thomas Frei](https://github.com/thfrei): لعمله الأصلي على "اللوحة" (Canvas).
* [antoniotejada](https://github.com/nriver): لأداة تمييز الصيغة البرمجية
(Syntax highlight) الأصلية.
* [Dosu](https://dosu.dev/): لتزويدنا بالردود الآلية على مشكلات ونقاشات GitHub.
* [Tabler Icons](https://tabler.io/icons): لأيقونات شريط النظام.
Trilium would not be possible without the technologies behind it:
لم يكن لـ Trilium أن يرى النور لولا التقنيات التي تقف خلفه:
* [CKEditor 5](https://github.com/ckeditor/ckeditor5) - the visual editor behind
text notes. We are grateful for being offered a set of the premium features.
* [CodeMirror](https://github.com/codemirror/CodeMirror) - code editor with
support for huge amount of languages.
* [Excalidraw](https://github.com/excalidraw/excalidraw) - the infinite
whiteboard used in Canvas notes.
* [Mind Elixir](https://github.com/SSShooter/mind-elixir-core) - providing the
mind map functionality.
* [Leaflet](https://github.com/Leaflet/Leaflet) - for rendering geographical
maps.
* [Tabulator](https://github.com/olifolkerd/tabulator) - for the interactive
table used in collections.
* [FancyTree](https://github.com/mar10/fancytree) - feature-rich tree library
without real competition.
* [jsPlumb](https://github.com/jsplumb/jsplumb) - visual connectivity library.
Used in [relation
maps](https://docs.triliumnotes.org/user-guide/note-types/relation-map) and
[link
maps](https://docs.triliumnotes.org/user-guide/advanced-usage/note-map#link-map)
* [CKEditor 5](https://github.com/ckeditor/ckeditor5): - المحرر المرئي خلف
الملاحظات النصية. نحن ممتنون لحصولنا على مجموعة من الميزات المدفوعة (Premium).
* [CodeMirror](https://github.com/codemirror/CodeMirror): - محرر أكواد يدعم
عدداً هائلاً من اللغات.
* [Excalidraw](https://github.com/excalidraw/excalidraw): - السبورة البيضاء
اللانهائية المستخدمة في ملاحظات Canvas.
* [Mind Elixir](https://github.com/SSShooter/mind-elixir-core): - يوفر وظائف
الخرائط الذهنية.
* [Leaflet](https://github.com/Leaflet/Leaflet): - لعرض الخرائط الجغرافية.
* [Tabulator](https://github.com/olifolkerd/tabulator): - للجداول التفاعلية
المستخدمة في المجموعات.
* [FancyTree](https://github.com/mar10/fancytree): - مكتبة "شجرية" غنية بالميزات
ولا يوجد لها منافس حقيقي.
* [jsPlumb](https://github.com/jsplumb/jsplumb): - مكتبة للربط المرئي، تُستخدم
في [خرائط
العلاقات](https://docs.triliumnotes.org/user-guide/note-types/relation-map)
و[خرائط
الروابط](https://docs.triliumnotes.org/user-guide/advanced-usage/note-map#link-map)
## 🤝 الدعم
Trilium is built and maintained with [hundreds of hours of
work](https://github.com/TriliumNext/Trilium/graphs/commit-activity). Your
support keeps it open-source, improves features, and covers costs such as
hosting.
تم بناء وصيانة برنامج Trilium بمئات الساعات من العمل. دعمكم يحافظ على كونه مفتوح
المصدر، ويحسن الميزات، ويغطي التكاليف مثل الاستضافة.
Consider supporting the main developer
([eliandoran](https://github.com/eliandoran)) of the application via:
يرجى التفكير في دعم المطور الرئيسي ([eliandoran](https://github.com/eliandoran))
للتطبيق عبر:
- [GitHub Sponsors](https://github.com/sponsors/eliandoran)
- [رعاة GitHub](https://github.com/sponsors/eliandoran)
- [PayPal](https://paypal.me/eliandoran)
- [Buy Me a Coffee](https://buymeacoffee.com/eliandoran)
- [اشترِ لي قهوة](https://buymeacoffee.com/eliandoran)
## 🔑 الترخيص
Copyright 2017-2025 zadam, Elian Doran, and other contributors
جميع الحقوق محفوظة لـ zadam وإليان دوران ومساهمين آخرين، من عام 2017 إلى عام
2025
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option) any
later version.
هذا البرنامج هو برنامج مجاني: يمكنك إعادة توزيعه و/أو تعديله بموجب شروط رخصة جنو
أفيرو (GNU Affero) العامة كما نشرتها مؤسسة البرمجيات الحرة، سواء الإصدار 3 من
الرخصة، أو (حسب اختيارك) أي إصدار لاحق.

9
docs/README-tr.md vendored
View File

@@ -50,10 +50,9 @@ edin(https://docs.triliumnotes.org/)**
Dokümantasyonumuz birden fazla formatta mevcuttur:
- **Çevrimiçi Dökümantasyon**: Tüm dökümantasyonu görebilmek için
[docs.triliumnotes.org](https://docs.triliumnotes.org/)'a uğrayın
- **In-App Help**: Press `F1` within Trilium to access the same documentation
directly in the application
- **GitHub**: Navigate through the [User Guide](./User%20Guide/User%20Guide/) in
this repository
- **Uygulama içi Yardım**: Aynı dökümantasyona ulaşmak için Trillium
içerisindeyken `F1` tuşuna basın
- **Github**: Bu repodaki [Kullanıcı Rehberi] sayfasına yönelin
### Hızlı linkler
- [Başlangıç Kılavuzu](https://docs.triliumnotes.org/)
@@ -64,7 +63,7 @@ Dokümantasyonumuz birden fazla formatta mevcuttur:
- [Patterns of Personal Knowledge
Base](https://docs.triliumnotes.org/user-guide/misc/patterns-of-personal-knowledge)
## 🎁 Features
## 🎁 Özellikler
* Notes can be arranged into arbitrarily deep tree. Single note can be placed
into multiple places in the tree (see

View File

@@ -103,7 +103,7 @@
"mermaid": "11.12.3",
"preact": "10.28.4",
"roughjs": "4.6.6",
"@types/express-serve-static-core": "5.1.0",
"@types/express-serve-static-core": "5.1.1",
"flat@<5.0.1": ">=5.0.1",
"debug@>=3.2.0 <3.2.7": ">=3.2.7",
"nanoid@<3.3.8": ">=3.3.8",

View File

@@ -1,6 +1,8 @@
import type { Request } from "express";
import type { Content } from "./Content.js";
import type { ParamsDictionary } from "express-serve-static-core";
/**
* @type {function (Request): Promise<Content>}
*/
export type ContentProvider = (req: Request) => Promise<Content>;
export type ContentProvider<P extends ParamsDictionary> = (req: Request<P>) => Promise<Content>;

View File

@@ -21,7 +21,7 @@ describe("createPartialContentHandler tests", () => {
vi.restoreAllMocks();
});
it("returns a handler", () => {
const contentProvider = vi.fn().mockResolvedValue({}) as ContentProvider;
const contentProvider = vi.fn().mockResolvedValue({}) as ContentProvider<{}>;
const handler = createPartialContentHandler(contentProvider, logger);
expect(typeof handler === "function");
});
@@ -45,7 +45,7 @@ describe("createPartialContentHandler tests", () => {
sendStatusSpy = vi.spyOn(res, "sendStatus");
});
it("invokes contentProvider with the specified request", async () => {
const contentProvider = vi.fn().mockResolvedValue({}) as ContentProvider;
const contentProvider = vi.fn().mockResolvedValue({}) as ContentProvider<{}>;
const handler = createPartialContentHandler(contentProvider, logger);
try {
await handler(req, res);
@@ -54,7 +54,7 @@ describe("createPartialContentHandler tests", () => {
});
it("returns 404 if contentProvider throws ContentDoesNotExistError error", async () => {
const error = new ContentDoesNotExistError("404-File not found!");
const contentProvider = vi.fn().mockRejectedValue(error) as ContentProvider;
const contentProvider = vi.fn().mockRejectedValue(error) as ContentProvider<{}>;
const handler = createPartialContentHandler(contentProvider, logger);
try {
await handler(req, res);
@@ -66,7 +66,7 @@ describe("createPartialContentHandler tests", () => {
});
it("returns 500 if contentProvider throws any other error", async () => {
const error = new Error("Something went wrong!");
const contentProvider = vi.fn().mockRejectedValue(error) as ContentProvider;
const contentProvider = vi.fn().mockRejectedValue(error) as ContentProvider<{}>;
const handler = createPartialContentHandler(contentProvider, logger);
try {
await handler(req, res);
@@ -76,7 +76,7 @@ describe("createPartialContentHandler tests", () => {
}
});
it("returns 416 if parseRangeHeader throws RangeParserError error", async () => {
const contentProvider = vi.fn().mockResolvedValue({}) as ContentProvider;
const contentProvider = vi.fn().mockResolvedValue({}) as ContentProvider<{}>;
const handler = createPartialContentHandler(contentProvider, logger);
req.headers = { range: "bytes=30-10" };
try {
@@ -87,7 +87,7 @@ describe("createPartialContentHandler tests", () => {
}
});
it("returns 500 if parseRangeHeader throws other errors", async () => {
const contentProvider = vi.fn().mockResolvedValue({}) as ContentProvider;
const contentProvider = vi.fn().mockResolvedValue({}) as ContentProvider<{}>;
const handler = createPartialContentHandler(contentProvider, logger);
try {
await handler(req, res);
@@ -112,7 +112,7 @@ describe("createPartialContentHandler tests", () => {
};
const pipeSpy = vi.spyOn(result, "pipe");
const getStreamSpy = vi.spyOn(content, "getStream");
const contentProvider = vi.fn().mockResolvedValue(content) as ContentProvider;
const contentProvider = vi.fn().mockResolvedValue(content) as ContentProvider<{}>;
const handler = createPartialContentHandler(contentProvider, logger);
const setContentTypeHeaderSpy = vi.spyOn(utils, "setContentTypeHeader");
const setContentDispositionHeaderSpy = vi.spyOn(utils, "setContentDispositionHeader");
@@ -152,7 +152,7 @@ describe("createPartialContentHandler tests", () => {
const range = { start: 0, end: 5 };
const pipeSpy = vi.spyOn(result, "pipe");
const getStreamSpy = vi.spyOn(content, "getStream");
const contentProvider = vi.fn().mockResolvedValue(content) as ContentProvider;
const contentProvider = vi.fn().mockResolvedValue(content) as ContentProvider<{}>;
const handler = createPartialContentHandler(contentProvider, logger);
const setContentTypeHeaderSpy = vi.spyOn(utils, "setContentTypeHeader");
const setContentDispositionHeaderSpy = vi.spyOn(utils, "setContentDispositionHeader");

View File

@@ -3,6 +3,7 @@ import { parseRangeHeader } from "./parseRangeHeader.js";
import { RangeParserError } from "./RangeParserError.js";
import type { Logger } from "./Logger.js";
import type { ContentProvider } from "./ContentProvider.js";
import type { ParamsDictionary } from "express-serve-static-core";
import { ContentDoesNotExistError } from "./ContentDoesNotExistError.js";
import {
getRangeHeader,
@@ -13,8 +14,8 @@ import {
setContentLengthHeader,
setCacheControlHeaderNoCache
} from "./utils.js";
export function createPartialContentHandler(contentProvider: ContentProvider, logger: Logger) {
return async function handler(req: Request, res: Response) {
export function createPartialContentHandler<P extends ParamsDictionary>(contentProvider: ContentProvider<P>, logger: Logger) {
return async function handler(req: Request<P>, res: Response) {
let content;
try {
content = await contentProvider(req);

View File

@@ -91,7 +91,7 @@ input[type="number"] {
--input-horizontal-padding: 8px;
border-radius: 4px !important;
font-size: .85rem !important;
font-size: .85rem;
&:hover {
--field-bg-color: var(--tn-input-hover-background);
@@ -135,12 +135,14 @@ input[type="color"] {
/* #region Toolbar */
#toolbarContainer select.scaleSelect,
#toolbarContainer input.pageNumber {
#toolbarContainer select#scaleSelect,
#toolbarContainer input#pageNumber {
height: calc(var(--toolbar-height) - 8px);
padding-block: 0;
font-size: 13px;
}
#toolbarContainer {
padding-inline: 12px;
}
@@ -230,14 +232,19 @@ input[type="color"] {
}
#toolbarContainer #toolbarViewer #pageNumber {
font-size: 12px;
font-weight: 600;
}
#numPages {
font-size: 13px;
line-height: unset;
}
#scaleSelectContainer {
--dropdown-btn-bg-color: transparent;
--button-hover-color: transparent;
border-radius: 6px;
margin-top: 1px;
&:hover,
&:focus-within{

180
pnpm-lock.yaml generated
View File

@@ -8,7 +8,7 @@ overrides:
mermaid: 11.12.3
preact: 10.28.4
roughjs: 4.6.6
'@types/express-serve-static-core': 5.1.0
'@types/express-serve-static-core': 5.1.1
flat@<5.0.1: '>=5.0.1'
debug@>=3.2.0 <3.2.7: '>=3.2.7'
nanoid@<3.3.8: '>=3.3.8'
@@ -156,8 +156,8 @@ importers:
apps/build-docs:
devDependencies:
'@redocly/cli':
specifier: 2.19.2
version: 2.19.2(@opentelemetry/api@1.9.0)(bufferutil@4.0.9)(core-js@3.46.0)(encoding@0.1.13)(utf-8-validate@6.0.5)
specifier: 2.20.2
version: 2.20.2(@opentelemetry/api@1.9.0)(bufferutil@4.0.9)(core-js@3.46.0)(encoding@0.1.13)(utf-8-validate@6.0.5)
archiver:
specifier: 7.0.1
version: 7.0.1
@@ -267,8 +267,8 @@ importers:
specifier: 1.51.1
version: 1.51.1
globals:
specifier: 17.3.0
version: 17.3.0
specifier: 17.4.0
version: 17.4.0
i18next:
specifier: 25.8.13
version: 25.8.13(typescript@5.9.3)
@@ -538,8 +538,8 @@ importers:
specifier: 9.0.5
version: 9.0.5
node-html-parser:
specifier: 7.0.2
version: 7.0.2
specifier: 7.1.0
version: 7.1.0
sucrase:
specifier: 3.35.1
version: 3.35.1
@@ -782,8 +782,8 @@ importers:
specifier: 2.17.1
version: 2.17.1
sax:
specifier: 1.4.4
version: 1.4.4
specifier: 1.5.0
version: 1.5.0
serve-favicon:
specifier: 2.5.1
version: 2.5.1
@@ -4744,30 +4744,30 @@ packages:
'@radix-ui/rect@1.1.0':
resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==}
'@redocly/ajv@8.17.4':
resolution: {integrity: sha512-BieiCML/IgP6x99HZByJSt7fJE4ipgzO7KAFss92Bs+PEI35BhY7vGIysFXLT+YmS7nHtQjZjhOQyPPEf7xGHA==}
'@redocly/ajv@8.18.0':
resolution: {integrity: sha512-F+LMD2IDIXuHxgpLJh3nkLj9+tSaEzoUWd+7fONGq5pe2169FUDjpEkOfEpoGLz1sbZni/69p07OsecNfAOpqA==}
'@redocly/cli@2.19.2':
resolution: {integrity: sha512-eT0hDCFwXceOUD7UxMltCk6baE9cOlCJ0LsBWFMHlaUYhkBztts0BoLx+nQTSqDUPCMGg0BKRLuNuHe3CR4HeA==}
'@redocly/cli@2.20.2':
resolution: {integrity: sha512-wfEoGFoXq1vZjd9uEtTd9mIixF5I5Ci1rusK/9HHcS6UGy3o2kuvrSn1daDHl1T3KcG5YFqQoLzzEgcL4Je7KQ==}
engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'}
hasBin: true
'@redocly/config@0.22.2':
resolution: {integrity: sha512-roRDai8/zr2S9YfmzUfNhKjOF0NdcOIqF7bhf4MVC5UxpjIysDjyudvlAiVbpPHp3eDRWbdzUgtkK1a7YiDNyQ==}
'@redocly/config@0.43.0':
resolution: {integrity: sha512-AbyFKRHKJ2VBmh9nO2lrG9tO2Gu/Lmnfdj4Uwoh7h/a7jWr1104t4fBgQZs/NwgGBAOkGmyQYAvardwyBeRGZA==}
'@redocly/config@0.44.0':
resolution: {integrity: sha512-UHKkWcCNZrGiKBbrQ1CE08ElrOUGm5H97Zn8+wkp80Uu2AT/go5In1sbqvhHxViPYtu1MLdy7qKiifSyOL3W/A==}
'@redocly/openapi-core@1.34.5':
resolution: {integrity: sha512-0EbE8LRbkogtcCXU7liAyC00n9uNG9hJ+eMyHFdUsy9lB/WGqnEBgwjA9q2cyzAVcdTkQqTBBU1XePNnN3OijA==}
engines: {node: '>=18.17.0', npm: '>=9.5.0'}
'@redocly/openapi-core@2.19.2':
resolution: {integrity: sha512-eooTSDKyN0F4YOjLPh/ajcvpzg/Rv7y5+Os/EyyCc2yu+zA+gZhSykQnOAIXcrSzrjn1bNpe4QF9eZNFLX4q0A==}
'@redocly/openapi-core@2.20.2':
resolution: {integrity: sha512-L3rzEZWMxq9SpAHP8k9C+/Fqxex4vxXgSZ5hQ+dg7++LXre67ZbT3RkhKsmYadJB/EUdbS6Z+h1Ont5TAI6zyQ==}
engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'}
'@redocly/respect-core@2.19.2':
resolution: {integrity: sha512-Ng5m9Sh+6PNW5rFrGQMucphRK/1EtMwLGeJVZBMDGe7YofiyqziDLQvJbI4aHzN2RKrYA585PKGZOQekWfoaCA==}
'@redocly/respect-core@2.20.2':
resolution: {integrity: sha512-oUCp+H83py0DEq5DJ+XmGPJQW9Yoq/tgml4OGwQrPEt1sC7QF7GjMRCA1HnRS4/dQ9psWGyFj9FwI1fCupQ8uw==}
engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'}
'@replit/codemirror-indentation-markers@6.5.3':
@@ -5834,8 +5834,8 @@ packages:
'@types/express-http-proxy@1.6.7':
resolution: {integrity: sha512-CEp9pbnwVI1RzN9PXc+KESMxwUW5r1O7tkWb5h7Wg/YAIf+KulD/zKev8fbbn+Ljt0Yvs8MXwV2W6Id+cKxe2Q==}
'@types/express-serve-static-core@5.1.0':
resolution: {integrity: sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==}
'@types/express-serve-static-core@5.1.1':
resolution: {integrity: sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==}
'@types/express-session@1.18.2':
resolution: {integrity: sha512-k+I0BxwVXsnEU2hV77cCobC08kIsn4y44C3gC0b46uxZVMaXA04lSPgRLR/bSL2w0t0ShJiG8o4jPzRG/nscFg==}
@@ -9348,8 +9348,8 @@ packages:
resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==}
engines: {node: '>=18'}
globals@17.3.0:
resolution: {integrity: sha512-yMqGUQVVCkD4tqjOJf3TnrvaaHDMYp4VlUSObbkIiuCPe/ofdMBFIAcBbCSRFWOnos6qRiTVStDwqPLUclaxIw==}
globals@17.4.0:
resolution: {integrity: sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==}
engines: {node: '>=18'}
globalthis@1.0.4:
@@ -11448,8 +11448,8 @@ packages:
node-html-parser@6.1.13:
resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==}
node-html-parser@7.0.2:
resolution: {integrity: sha512-DxodLVh7a6JMkYzWyc8nBX9MaF4M0lLFYkJHlWOiu7+9/I6mwNK9u5TbAMC7qfqDJEPX9OIoWA2A9t4C2l1mUQ==}
node-html-parser@7.1.0:
resolution: {integrity: sha512-iJo8b2uYGT40Y8BTyy5ufL6IVbN8rbm/1QK2xffXU/1a/v3AAa0d1YAoqBNYqaS4R/HajkWIpIfdE6KcyFh1AQ==}
node-notifier@10.0.1:
resolution: {integrity: sha512-YX7TSyDukOZ0g+gmzjB6abKu+hTGvO8+8+gIFDsRCU2t8fLV/P2unmt+LGFaIa4y64aX98Qksa97rgz4vMNeLQ==}
@@ -13325,8 +13325,8 @@ packages:
engines: {node: '>=14.0.0'}
hasBin: true
sax@1.4.4:
resolution: {integrity: sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==}
sax@1.5.0:
resolution: {integrity: sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==}
engines: {node: '>=11.0.0'}
saxes@5.0.1:
@@ -16310,7 +16310,7 @@ snapshots:
'@ckeditor/ckeditor5-dev-utils': 54.0.0(@babel/core@7.28.0)(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.27.3)(typescript@5.0.4)(webpack@5.101.3(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.27.3))
chalk: 5.6.2
fs-extra: 11.3.3
glob: 13.0.0
glob: 13.0.6
plural-forms: 0.5.5
pofile: 1.1.4
rimraf: 6.0.1
@@ -16339,7 +16339,7 @@ snapshots:
cssnano: 7.1.1(postcss@8.5.6)
esbuild-loader: 4.3.0(webpack@5.101.3(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.27.3))
fs-extra: 11.3.3
glob: 13.0.0
glob: 13.0.6
is-interactive: 2.0.0
mini-css-extract-plugin: 2.9.4(webpack@5.101.3(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.27.3))
mocha: 11.7.2
@@ -16605,8 +16605,6 @@ snapshots:
'@ckeditor/ckeditor5-utils': 47.4.0
'@ckeditor/ckeditor5-widget': 47.4.0
ckeditor5: 47.4.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-html-embed@47.4.0':
dependencies:
@@ -16980,6 +16978,8 @@ snapshots:
'@ckeditor/ckeditor5-ui': 47.4.0
'@ckeditor/ckeditor5-utils': 47.4.0
ckeditor5: 47.4.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-slash-command@47.4.0':
dependencies:
@@ -17131,8 +17131,6 @@ snapshots:
'@ckeditor/ckeditor5-icons': 47.4.0
'@ckeditor/ckeditor5-ui': 47.4.0
'@ckeditor/ckeditor5-utils': 47.4.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-upload@47.4.0':
dependencies:
@@ -18324,7 +18322,7 @@ snapshots:
'@file-type/xml@0.4.3':
dependencies:
sax: 1.4.4
sax: 1.5.0
strtok3: 10.2.2
'@floating-ui/core@1.6.9':
@@ -18815,7 +18813,7 @@ snapshots:
'@isaacs/fs-minipass@4.0.1':
dependencies:
minipass: 7.1.2
minipass: 7.1.3
'@istanbuljs/schema@0.1.3': {}
@@ -19429,7 +19427,7 @@ snapshots:
'@npmcli/package-json@7.0.0':
dependencies:
'@npmcli/git': 6.0.3
glob: 13.0.0
glob: 13.0.6
hosted-git-info: 9.0.0
json-parse-even-better-errors: 4.0.0
proc-log: 5.0.0
@@ -20000,24 +19998,24 @@ snapshots:
'@radix-ui/rect@1.1.0': {}
'@redocly/ajv@8.17.4':
'@redocly/ajv@8.18.0':
dependencies:
fast-deep-equal: 3.1.3
fast-uri: 3.1.0
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
'@redocly/cli@2.19.2(@opentelemetry/api@1.9.0)(bufferutil@4.0.9)(core-js@3.46.0)(encoding@0.1.13)(utf-8-validate@6.0.5)':
'@redocly/cli@2.20.2(@opentelemetry/api@1.9.0)(bufferutil@4.0.9)(core-js@3.46.0)(encoding@0.1.13)(utf-8-validate@6.0.5)':
dependencies:
'@opentelemetry/exporter-trace-otlp-http': 0.202.0(@opentelemetry/api@1.9.0)
'@opentelemetry/resources': 2.0.1(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-trace-node': 2.0.1(@opentelemetry/api@1.9.0)
'@opentelemetry/semantic-conventions': 1.34.0
'@redocly/openapi-core': 2.19.2
'@redocly/respect-core': 2.19.2
'@redocly/openapi-core': 2.20.2
'@redocly/respect-core': 2.20.2
abort-controller: 3.0.0
ajv: '@redocly/ajv@8.17.4'
ajv-formats: 3.0.1(@redocly/ajv@8.17.4)
ajv: '@redocly/ajv@8.18.0'
ajv-formats: 3.0.1(@redocly/ajv@8.18.0)
colorette: 1.4.0
cookie: 0.7.2
dotenv: 16.4.7
@@ -20048,13 +20046,13 @@ snapshots:
'@redocly/config@0.22.2': {}
'@redocly/config@0.43.0':
'@redocly/config@0.44.0':
dependencies:
json-schema-to-ts: 2.7.2
'@redocly/openapi-core@1.34.5':
dependencies:
'@redocly/ajv': 8.17.4
'@redocly/ajv': 8.18.0
'@redocly/config': 0.22.2
colorette: 1.4.0
https-proxy-agent: 7.0.6
@@ -20066,12 +20064,12 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@redocly/openapi-core@2.19.2':
'@redocly/openapi-core@2.20.2':
dependencies:
'@redocly/ajv': 8.17.4
'@redocly/config': 0.43.0
ajv: '@redocly/ajv@8.17.4'
ajv-formats: 3.0.1(@redocly/ajv@8.17.4)
'@redocly/ajv': 8.18.0
'@redocly/config': 0.44.0
ajv: '@redocly/ajv@8.18.0'
ajv-formats: 3.0.1(@redocly/ajv@8.18.0)
colorette: 1.4.0
js-levenshtein: 1.1.6
js-yaml: 4.1.1
@@ -20079,14 +20077,14 @@ snapshots:
pluralize: 8.0.0
yaml-ast-parser: 0.0.43
'@redocly/respect-core@2.19.2':
'@redocly/respect-core@2.20.2':
dependencies:
'@faker-js/faker': 7.6.0
'@noble/hashes': 1.8.0
'@redocly/ajv': 8.17.4
'@redocly/openapi-core': 2.19.2
ajv: '@redocly/ajv@8.17.4'
better-ajv-errors: 1.2.0(@redocly/ajv@8.17.4)
'@redocly/ajv': 8.18.0
'@redocly/openapi-core': 2.20.2
ajv: '@redocly/ajv@8.18.0'
better-ajv-errors: 1.2.0(@redocly/ajv@8.18.0)
colorette: 2.0.20
json-pointer: 0.6.2
jsonpath-rfc9535: 1.3.0
@@ -21121,7 +21119,7 @@ snapshots:
'@types/connect-history-api-fallback@1.5.4':
dependencies:
'@types/express-serve-static-core': 5.1.0
'@types/express-serve-static-core': 5.1.1
'@types/node': 24.11.0
'@types/connect@3.4.38':
@@ -21296,7 +21294,7 @@ snapshots:
dependencies:
'@types/express': 5.0.3
'@types/express-serve-static-core@5.1.0':
'@types/express-serve-static-core@5.1.1':
dependencies:
'@types/node': 24.11.0
'@types/qs': 6.14.0
@@ -21310,20 +21308,20 @@ snapshots:
'@types/express@4.17.23':
dependencies:
'@types/body-parser': 1.19.6
'@types/express-serve-static-core': 5.1.0
'@types/express-serve-static-core': 5.1.1
'@types/qs': 6.14.0
'@types/serve-static': 2.2.0
'@types/express@5.0.3':
dependencies:
'@types/body-parser': 1.19.6
'@types/express-serve-static-core': 5.1.0
'@types/express-serve-static-core': 5.1.1
'@types/serve-static': 2.2.0
'@types/express@5.0.6':
dependencies:
'@types/body-parser': 1.19.6
'@types/express-serve-static-core': 5.1.0
'@types/express-serve-static-core': 5.1.1
'@types/serve-static': 2.2.0
'@types/filesystem@0.0.36':
@@ -22049,7 +22047,7 @@ snapshots:
'@wdio/types': 9.24.0
'@wdio/utils': 9.24.0
deepmerge-ts: 7.1.5
glob: 13.0.0
glob: 13.0.6
import-meta-resolve: 4.2.0
jiti: 2.6.1
transitivePeerDependencies:
@@ -22296,9 +22294,9 @@ snapshots:
optionalDependencies:
ajv: 8.17.1
ajv-formats@3.0.1(@redocly/ajv@8.17.4):
ajv-formats@3.0.1(@redocly/ajv@8.18.0):
optionalDependencies:
ajv: '@redocly/ajv@8.17.4'
ajv: '@redocly/ajv@8.18.0'
ajv-formats@3.0.1(ajv@8.13.0):
optionalDependencies:
@@ -22413,7 +22411,7 @@ snapshots:
archiver-utils@5.0.2:
dependencies:
glob: 13.0.0
glob: 13.0.6
graceful-fs: 4.2.11
is-stream: 2.0.1
lazystream: 1.0.1
@@ -22663,11 +22661,11 @@ snapshots:
batch@0.6.1: {}
better-ajv-errors@1.2.0(@redocly/ajv@8.17.4):
better-ajv-errors@1.2.0(@redocly/ajv@8.18.0):
dependencies:
'@babel/code-frame': 7.27.1
'@humanwhocodes/momoa': 2.0.4
ajv: '@redocly/ajv@8.17.4'
ajv: '@redocly/ajv@8.18.0'
chalk: 4.1.2
jsonpointer: 5.0.1
leven: 3.1.0
@@ -22929,9 +22927,9 @@ snapshots:
dependencies:
'@npmcli/fs': 4.0.0
fs-minipass: 3.0.3
glob: 13.0.0
glob: 13.0.6
lru-cache: 10.4.3
minipass: 7.1.2
minipass: 7.1.3
minipass-collect: 2.0.1
minipass-flush: 1.0.5
minipass-pipeline: 1.2.4
@@ -22944,9 +22942,9 @@ snapshots:
dependencies:
'@npmcli/fs': 4.0.0
fs-minipass: 3.0.3
glob: 13.0.0
glob: 13.0.6
lru-cache: 11.2.4
minipass: 7.1.2
minipass: 7.1.3
minipass-collect: 2.0.1
minipass-flush: 1.0.5
minipass-pipeline: 1.2.4
@@ -24989,7 +24987,7 @@ snapshots:
eslint-plugin-playwright@2.8.0(eslint@10.0.2(jiti@2.6.1)):
dependencies:
eslint: 10.0.2(jiti@2.6.1)
globals: 17.3.0
globals: 17.4.0
eslint-plugin-react-hooks@5.2.0(eslint@10.0.2(jiti@2.6.1)):
dependencies:
@@ -25603,7 +25601,7 @@ snapshots:
fs-minipass@3.0.3:
dependencies:
minipass: 7.1.2
minipass: 7.1.3
fs-temp@1.2.1:
dependencies:
@@ -25882,7 +25880,7 @@ snapshots:
globals@16.5.0: {}
globals@17.3.0: {}
globals@17.4.0: {}
globalthis@1.0.4:
dependencies:
@@ -27492,7 +27490,7 @@ snapshots:
'@npmcli/agent': 3.0.0
cacache: 19.0.1
http-cache-semantics: 4.2.0
minipass: 7.1.2
minipass: 7.1.3
minipass-fetch: 4.0.1
minipass-flush: 1.0.5
minipass-pipeline: 1.2.4
@@ -27508,7 +27506,7 @@ snapshots:
'@npmcli/agent': 4.0.0
cacache: 20.0.1
http-cache-semantics: 4.2.0
minipass: 7.1.2
minipass: 7.1.3
minipass-fetch: 5.0.0
minipass-flush: 1.0.5
minipass-pipeline: 1.2.4
@@ -28078,7 +28076,7 @@ snapshots:
minipass-collect@2.0.1:
dependencies:
minipass: 7.1.2
minipass: 7.1.3
minipass-fetch@1.4.1:
dependencies:
@@ -28099,7 +28097,7 @@ snapshots:
minipass-fetch@4.0.1:
dependencies:
minipass: 7.1.2
minipass: 7.1.3
minipass-sized: 1.0.3
minizlib: 3.1.0
optionalDependencies:
@@ -28140,7 +28138,7 @@ snapshots:
minizlib@3.1.0:
dependencies:
minipass: 7.1.2
minipass: 7.1.3
mitt@3.0.1: {}
@@ -28192,7 +28190,7 @@ snapshots:
diff: 8.0.3
escape-string-regexp: 4.0.0
find-up: 5.0.0
glob: 13.0.0
glob: 13.0.6
he: 1.2.0
js-yaml: 4.1.1
log-symbols: 4.1.0
@@ -28316,7 +28314,7 @@ snapshots:
needle@3.3.1:
dependencies:
iconv-lite: 0.6.3
sax: 1.4.4
sax: 1.5.0
optional: true
negotiator@0.6.3: {}
@@ -28405,7 +28403,7 @@ snapshots:
css-select: 5.2.2
he: 1.2.0
node-html-parser@7.0.2:
node-html-parser@7.1.0:
dependencies:
css-select: 5.2.2
he: 1.2.0
@@ -28496,7 +28494,7 @@ snapshots:
'@npmcli/redact': 3.2.2
jsonparse: 1.3.1
make-fetch-happen: 15.0.3
minipass: 7.1.2
minipass: 7.1.3
minipass-fetch: 4.0.1
minizlib: 3.1.0
npm-package-arg: 13.0.0
@@ -28846,7 +28844,7 @@ snapshots:
'@npmcli/run-script': 10.0.0
cacache: 20.0.1
fs-minipass: 3.0.3
minipass: 7.1.2
minipass: 7.1.3
npm-package-arg: 13.0.0
npm-packlist: 10.0.1
npm-pick-manifest: 10.0.0
@@ -28962,7 +28960,7 @@ snapshots:
path-scurry@2.0.0:
dependencies:
lru-cache: 11.2.4
minipass: 7.1.2
minipass: 7.1.3
path-scurry@2.0.2:
dependencies:
@@ -29687,7 +29685,7 @@ snapshots:
purgecss@7.0.2:
dependencies:
commander: 12.1.0
glob: 13.0.0
glob: 13.0.6
postcss: 8.5.6
postcss-selector-parser: 6.1.2
@@ -30183,7 +30181,7 @@ snapshots:
rimraf@6.0.1:
dependencies:
glob: 13.0.0
glob: 13.0.6
package-json-from-dist: 1.0.1
roarr@2.15.4:
@@ -30481,7 +30479,7 @@ snapshots:
'@parcel/watcher': 2.5.4
optional: true
sax@1.4.4: {}
sax@1.5.0: {}
saxes@5.0.1:
dependencies:
@@ -31052,7 +31050,7 @@ snapshots:
ssri@12.0.0:
dependencies:
minipass: 7.1.2
minipass: 7.1.3
ssri@13.0.0:
dependencies:
@@ -31516,7 +31514,7 @@ snapshots:
css-what: 6.2.2
csso: 5.0.5
picocolors: 1.1.1
sax: 1.4.4
sax: 1.5.0
swagger-jsdoc@6.2.8(openapi-types@12.1.3):
dependencies:
@@ -32592,7 +32590,7 @@ snapshots:
'@types/bonjour': 3.5.13
'@types/connect-history-api-fallback': 1.5.4
'@types/express': 4.17.23
'@types/express-serve-static-core': 5.1.0
'@types/express-serve-static-core': 5.1.1
'@types/serve-index': 1.9.4
'@types/serve-static': 1.15.10
'@types/sockjs': 0.3.36
@@ -32973,12 +32971,12 @@ snapshots:
xml2js@0.5.0:
dependencies:
sax: 1.4.4
sax: 1.5.0
xmlbuilder: 11.0.1
xml2js@0.6.2:
dependencies:
sax: 1.4.4
sax: 1.5.0
xmlbuilder: 11.0.1
xmlbuilder@11.0.1: {}