diff --git a/apps/server/src/routes/index.ts b/apps/server/src/routes/index.ts index da0174999f..57708686c7 100644 --- a/apps/server/src/routes/index.ts +++ b/apps/server/src/routes/index.ts @@ -7,7 +7,7 @@ import assetPath from "../services/asset_path.js"; import attributeService from "../services/attributes.js"; import config from "../services/config.js"; import { getCurrentLocale } from "../services/i18n.js"; -import { generateCss, generateIconRegistry, getIconPacks, MIME_TO_EXTENSION_MAPPINGS } from "../services/icon_packs.js"; +import { icon_packs as iconPackService } from "@triliumnext/core"; import log from "../services/log.js"; import optionService from "../services/options.js"; import protectedSessionService from "../services/protected_session.js"; @@ -30,7 +30,7 @@ export function bootstrap(req: Request, res: Response) { const theme = options.theme; const themeNote = attributeService.getNoteWithLabel("appTheme", theme); const nativeTitleBarVisible = options.nativeTitleBarVisible === "true"; - const iconPacks = getIconPacks(); + const iconPacks = iconPackService.getIconPacks(); const currentLocale = getCurrentLocale(); res.send({ @@ -62,12 +62,12 @@ export function bootstrap(req: Request, res: Response) { currentLocale, isRtl: !!currentLocale.rtl, iconPackCss: iconPacks - .map(p => generateCss(p, p.builtin - ? `${assetPath}/fonts/${p.fontAttachmentId}.${MIME_TO_EXTENSION_MAPPINGS[p.fontMime]}` + .map(p => iconPackService.generateCss(p, p.builtin + ? `${assetPath}/fonts/${p.fontAttachmentId}.${iconPackService.MIME_TO_EXTENSION_MAPPINGS[p.fontMime]}` : `api/attachments/download/${p.fontAttachmentId}`)) .filter(Boolean) .join("\n\n"), - iconRegistry: generateIconRegistry(iconPacks), + iconRegistry: iconPackService.generateIconRegistry(iconPacks), TRILIUM_SAFE_MODE: !!process.env.TRILIUM_SAFE_MODE }); } diff --git a/apps/server/src/services/export/zip/share_theme.ts b/apps/server/src/services/export/zip/share_theme.ts index 534ccf785b..0998a7244c 100644 --- a/apps/server/src/services/export/zip/share_theme.ts +++ b/apps/server/src/services/export/zip/share_theme.ts @@ -9,7 +9,7 @@ import type BBranch from "../../../becca/entities/bbranch.js"; import type BNote from "../../../becca/entities/bnote.js"; import { getClientDir, getShareThemeAssetDir } from "../../../routes/assets"; import { getDefaultTemplatePath, readTemplate, renderNoteForExport } from "../../../share/content_renderer"; -import { getIconPacks, MIME_TO_EXTENSION_MAPPINGS, ProcessedIconPack } from "../../icon_packs"; +import { icon_packs as iconPackService } from "@triliumnext/core"; import log from "../../log"; import NoteMeta, { NoteMetaFile } from "../../meta/note_meta"; import { RESOURCE_DIR } from "../../resource_dir"; @@ -31,7 +31,7 @@ export default class ShareThemeExportProvider extends ZipExportProvider { private indexMeta: NoteMeta | null = null; private searchIndex: Map = new Map(); private rootMeta: NoteMeta | null = null; - private iconPacks: ProcessedIconPack[] = []; + private iconPacks: iconPackService.ProcessedIconPack[] = []; prepareMeta(metaFile: NoteMetaFile): void { const assets = [ @@ -56,7 +56,7 @@ export default class ShareThemeExportProvider extends ZipExportProvider { dataFileName: "index.html" }; this.rootMeta = metaFile.files[0]; - this.iconPacks = getIconPacks(); + this.iconPacks = iconPackService.getIconPacks(); metaFile.files.push(this.indexMeta); } @@ -165,7 +165,7 @@ export default class ShareThemeExportProvider extends ZipExportProvider { // Inject the custom fonts. for (const iconPack of this.iconPacks) { - const extension = MIME_TO_EXTENSION_MAPPINGS[iconPack.fontMime]; + const extension = iconPackService.MIME_TO_EXTENSION_MAPPINGS[iconPack.fontMime]; let fontData: Uint8Array | undefined; if (iconPack.builtin) { fontData = readFileSync(join(getClientDir(), "fonts", `${iconPack.fontAttachmentId}.${extension}`)); diff --git a/apps/server/src/services/utils.ts b/apps/server/src/services/utils.ts index 5ad481211d..86cfd87f3a 100644 --- a/apps/server/src/services/utils.ts +++ b/apps/server/src/services/utils.ts @@ -343,10 +343,6 @@ export function processStringOrBuffer(data: string | Buffer | null) { } } -export function safeExtractMessageAndStackFromError(err: unknown): [errMessage: string, errStack: string | undefined] { - return (err instanceof Error) ? [err.message, err.stack] as const : ["Unknown Error", undefined] as const; -} - /** * Normalizes URL by removing trailing slashes and fixing double slashes. * Preserves the protocol (http://, https://) but removes trailing slashes from the rest. @@ -453,9 +449,14 @@ function slugify(text: string) { .replace(/(^-|-$)+/g, ""); // trim dashes } +/** @deprecated */ export const escapeHtml = coreUtils.escapeHtml; +/** @deprecated */ export const unescapeHtml = coreUtils.unescapeHtml; +/** @deprecated */ export const randomSecureToken = coreUtils.randomSecureToken; +/** @deprecated */ +export const safeExtractMessageAndStackFromError = coreUtils.safeExtractMessageAndStackFromError; export default { compareVersions, diff --git a/apps/server/src/share/content_renderer.ts b/apps/server/src/share/content_renderer.ts index c777c5cbcb..bd4be030fc 100644 --- a/apps/server/src/share/content_renderer.ts +++ b/apps/server/src/share/content_renderer.ts @@ -12,7 +12,6 @@ import BAttachment from '../becca/entities/battachment.js'; import type BBranch from "../becca/entities/bbranch.js"; import BNote from "../becca/entities/bnote.js"; import assetPath, { assetUrlFragment } from "../services/asset_path.js"; -import { generateCss, getIconPacks, MIME_TO_EXTENSION_MAPPINGS, ProcessedIconPack } from "../services/icon_packs.js"; import log from "../services/log.js"; import options from "../services/options.js"; import utils, { getResourceDir, isDev, safeExtractMessageAndStackFromError } from "../services/utils.js"; @@ -21,6 +20,7 @@ import SBranch from "./shaca/entities/sbranch.js"; import type SNote from "./shaca/entities/snote.js"; import shaca from "./shaca/shaca.js"; import shareRoot from "./share_root.js"; +import { icon_packs as iconPackService } from "@triliumnext/core"; const shareAdjustedAssetPath = isDev ? assetPath : `../${assetPath}`; const templateCache: Map = new Map(); @@ -69,7 +69,7 @@ function getSharedSubTreeRoot(note: SNote | BNote | undefined): Subroot { return getSharedSubTreeRoot(parentBranch.getParentNote()); } -export function renderNoteForExport(note: BNote, parentBranch: BBranch, basePath: string, ancestors: string[], iconPacks: ProcessedIconPack[]) { +export function renderNoteForExport(note: BNote, parentBranch: BBranch, basePath: string, ancestors: string[], iconPacks: iconPackService.ProcessedIconPack[]) { const subRoot: Subroot = { branch: parentBranch, note: parentBranch.getNote() @@ -95,7 +95,7 @@ export function renderNoteForExport(note: BNote, parentBranch: BBranch, basePath faviconUrl: `${basePath}favicon.ico`, ancestors, isStatic: true, - iconPackCss: iconPacks.map(p => generateCss(p, `${basePath}assets/icon-pack-${p.prefix.toLowerCase()}.${MIME_TO_EXTENSION_MAPPINGS[p.fontMime]}`)) + iconPackCss: iconPacks.map(p => iconPackService.generateCss(p, `${basePath}assets/icon-pack-${p.prefix.toLowerCase()}.${iconPackService.MIME_TO_EXTENSION_MAPPINGS[p.fontMime]}`)) .filter(Boolean) .join("\n\n"), iconPackSupportedPrefixes: iconPacks.map(p => p.prefix) @@ -136,7 +136,7 @@ export function renderNoteContent(note: SNote) { const customLogoId = note.getRelation("shareLogo")?.value; const logoUrl = customLogoId ? `api/images/${customLogoId}/image.png` : `../${assetUrlFragment}/images/icon-color.svg`; - const iconPacks = getIconPacks().filter(p => p.builtin || !!shaca.notes[p.manifestNoteId]); + const iconPacks = iconPackService.getIconPacks().filter(p => p.builtin || !!shaca.notes[p.manifestNoteId]); return renderNoteContentInternal(note, { subRoot, @@ -147,8 +147,8 @@ export function renderNoteContent(note: SNote) { ancestors, isStatic: false, faviconUrl: note.hasRelation("shareFavicon") ? `api/notes/${note.getRelationValue("shareFavicon")}/download` : `../favicon.ico`, - iconPackCss: iconPacks.map(p => generateCss(p, p.builtin - ? `/share/assets/fonts/${p.fontAttachmentId}.${MIME_TO_EXTENSION_MAPPINGS[p.fontMime]}` + iconPackCss: iconPacks.map(p => iconPackService.generateCss(p, p.builtin + ? `/share/assets/fonts/${p.fontAttachmentId}.${iconPackService.MIME_TO_EXTENSION_MAPPINGS[p.fontMime]}` : `/share/api/attachments/${p.fontAttachmentId}/download` )) .filter(Boolean) diff --git a/packages/trilium-core/src/index.ts b/packages/trilium-core/src/index.ts index 28191e328b..561b6d8d38 100644 --- a/packages/trilium-core/src/index.ts +++ b/packages/trilium-core/src/index.ts @@ -20,6 +20,7 @@ export { default as app_info } from "./services/app_info"; export { default as keyboard_actions } from "./services/keyboard_actions"; export { default as entity_changes } from "./services/entity_changes"; export { default as hidden_subtree } from "./services/hidden_subtree"; +export * as icon_packs from "./services/icon_packs"; export { getContext, type ExecutionContext } from "./services/context"; export * as cls from "./services/context"; export * from "./errors"; diff --git a/apps/server/src/services/icon_pack_boxicons-v2.json b/packages/trilium-core/src/services/icon_pack_boxicons-v2.json similarity index 100% rename from apps/server/src/services/icon_pack_boxicons-v2.json rename to packages/trilium-core/src/services/icon_pack_boxicons-v2.json diff --git a/apps/server/src/services/icon_packs.spec.ts b/packages/trilium-core/src/services/icon_packs.spec.ts similarity index 100% rename from apps/server/src/services/icon_packs.spec.ts rename to packages/trilium-core/src/services/icon_packs.spec.ts diff --git a/apps/server/src/services/icon_packs.ts b/packages/trilium-core/src/services/icon_packs.ts similarity index 86% rename from apps/server/src/services/icon_packs.ts rename to packages/trilium-core/src/services/icon_packs.ts index 8f01eef445..becea99469 100644 --- a/apps/server/src/services/icon_packs.ts +++ b/packages/trilium-core/src/services/icon_packs.ts @@ -3,9 +3,9 @@ import { IconRegistry } from "@triliumnext/commons"; import type BAttachment from "../becca/entities/battachment"; import type BNote from "../becca/entities/bnote"; import boxiconsManifest from "./icon_pack_boxicons-v2.json" with { type: "json" }; -import log from "./log"; +import { getLog } from "./log"; import search from "./search/services/search"; -import { safeExtractMessageAndStackFromError } from "./utils"; +import { safeExtractMessageAndStackFromError } from "./utils/index"; const PREFERRED_MIME_TYPE = [ "font/woff2", @@ -64,7 +64,7 @@ export function getIconPacks() { if (!iconPack) return false; if (iconPack.prefix === "bx" || usedPrefixes.has(iconPack.prefix)) { - log.info(`Skipping icon pack with duplicate prefix '${iconPack.prefix}': ${iconPack.title} (${iconPack.manifestNoteId})`); + getLog().info(`Skipping icon pack with duplicate prefix '${iconPack.prefix}': ${iconPack.title} (${iconPack.manifestNoteId})`); return false; } usedPrefixes.add(iconPack.prefix); @@ -103,25 +103,25 @@ export function generateIconRegistry(iconPacks: ProcessedIconPack[]): IconRegist export function processIconPack(iconPackNote: BNote): ProcessedIconPack | undefined { const manifest = iconPackNote.getJsonContentSafely() as IconPackManifest; if (!manifest) { - log.error(`Icon pack is missing JSON manifest (or has syntax errors): ${iconPackNote.title} (${iconPackNote.noteId})`); + getLog().error(`Icon pack is missing JSON manifest (or has syntax errors): ${iconPackNote.title} (${iconPackNote.noteId})`); return; } const attachment = determineBestFontAttachment(iconPackNote); if (!attachment || !attachment.attachmentId) { - log.error(`Icon pack is missing WOFF/WOFF2/TTF attachment: ${iconPackNote.title} (${iconPackNote.noteId})`); + getLog().error(`Icon pack is missing WOFF/WOFF2/TTF attachment: ${iconPackNote.title} (${iconPackNote.noteId})`); return; } const prefix = iconPackNote.getLabelValue("iconPack"); if (!prefix) { - log.error(`Icon pack is missing 'iconPack' label defining its prefix: ${iconPackNote.title} (${iconPackNote.noteId})`); + getLog().error(`Icon pack is missing 'iconPack' label defining its prefix: ${iconPackNote.title} (${iconPackNote.noteId})`); return; } // Ensure prefix is alphanumeric only, dashes and underscores. if (!/^[a-zA-Z0-9-_]+$/.test(prefix)) { - log.error(`Icon pack has invalid 'iconPack' prefix (only alphanumeric characters, dashes and underscores are allowed): ${iconPackNote.title} (${iconPackNote.noteId})`); + getLog().error(`Icon pack has invalid 'iconPack' prefix (only alphanumeric characters, dashes and underscores are allowed): ${iconPackNote.title} (${iconPackNote.noteId})`); return; } @@ -185,7 +185,7 @@ export function generateCss({ manifest, fontMime, builtin, fontAttachmentId, pre ${iconDeclarations.join("\n")} `; } catch (e) { - log.error(safeExtractMessageAndStackFromError(e)); + getLog().error(safeExtractMessageAndStackFromError(e)); return null; } } diff --git a/packages/trilium-core/src/services/search/services/search.ts b/packages/trilium-core/src/services/search/services/search.ts index bfa8207525..f344e86565 100644 --- a/packages/trilium-core/src/services/search/services/search.ts +++ b/packages/trilium-core/src/services/search/services/search.ts @@ -5,7 +5,7 @@ export default { console.warn("Ignore search ", note.title); }, - searchNotes(searchString: string, opts: {}): BNote[] { + searchNotes(searchString: string, opts?: {}): BNote[] { console.warn("Ignore search", searchString); return []; } diff --git a/packages/trilium-core/src/services/utils/index.ts b/packages/trilium-core/src/services/utils/index.ts index e966f72374..f172452fff 100644 --- a/packages/trilium-core/src/services/utils/index.ts +++ b/packages/trilium-core/src/services/utils/index.ts @@ -126,3 +126,7 @@ export const unescapeHtml = unescape; export function randomSecureToken(bytes = 32) { return encodeBase64(getCrypto().randomBytes(32)); } + +export function safeExtractMessageAndStackFromError(err: unknown): [errMessage: string, errStack: string | undefined] { + return (err instanceof Error) ? [err.message, err.stack] as const : ["Unknown Error", undefined] as const; +}