chore(nx): prepare commons

This commit is contained in:
Elian Doran
2025-04-22 15:07:48 +03:00
parent 84b6764166
commit 41cf38a26c
62 changed files with 17633 additions and 3739 deletions

3
packages/commons/dist/index.js vendored Normal file
View File

@@ -0,0 +1,3 @@
export * from './lib/commons.js';
//# sourceMappingURL=index.js.map

1
packages/commons/dist/index.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './lib/commons.js';\n"],"names":[],"rangeMappings":"","mappings":"AAAA,cAAc,mBAAmB"}

View File

@@ -0,0 +1,12 @@
var Command;
(function(Command) {
Command[Command["jumpToNote"] = 0] = "jumpToNote";
Command[Command["searchNotes"] = 1] = "searchNotes";
Command[Command["createNoteIntoInbox"] = 2] = "createNoteIntoInbox";
Command[Command["showRecentChanges"] = 3] = "showRecentChanges";
Command[Command["showOptions"] = 4] = "showOptions";
Command[Command["createAiChat"] = 5] = "createAiChat";
})(Command || (Command = {}));
export { };
//# sourceMappingURL=hidden_subtree.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../src/lib/hidden_subtree.ts"],"sourcesContent":["import { AttributeType } from \"./rows.js\";\n\ntype LauncherNoteType = \"launcher\" | \"search\" | \"doc\" | \"noteMap\" | \"contentWidget\" | \"book\" | \"file\" | \"image\" | \"text\" | \"relationMap\" | \"render\" | \"canvas\" | \"mermaid\" | \"webView\" | \"code\" | \"mindMap\" | \"geoMap\";\n\nenum Command {\n jumpToNote,\n searchNotes,\n createNoteIntoInbox,\n showRecentChanges,\n showOptions,\n createAiChat\n}\n\nexport interface HiddenSubtreeAttribute {\n type: AttributeType;\n name: string;\n isInheritable?: boolean;\n value?: string;\n}\n\nexport interface HiddenSubtreeItem {\n notePosition?: number;\n id: string;\n title: string;\n type: LauncherNoteType;\n icon?: string;\n attributes?: HiddenSubtreeAttribute[];\n children?: HiddenSubtreeItem[];\n isExpanded?: boolean;\n baseSize?: string;\n growthFactor?: string;\n targetNoteId?: \"_backendLog\" | \"_globalNoteMap\";\n builtinWidget?:\n | \"todayInJournal\"\n | \"bookmarks\"\n | \"spacer\"\n | \"backInHistoryButton\"\n | \"forwardInHistoryButton\"\n | \"syncStatus\"\n | \"protectedSession\"\n | \"calendar\"\n | \"quickSearch\"\n | \"aiChatLauncher\";\n command?: keyof typeof Command;\n}"],"names":["Command"],"rangeMappings":";;;;;;;;;","mappings":";UAIKA;;;;;;;GAAAA,YAAAA;AAgBL,WAwBC"}

3
packages/commons/dist/lib/i18n.js vendored Normal file
View File

@@ -0,0 +1,3 @@
export { };
//# sourceMappingURL=i18n.js.map

1
packages/commons/dist/lib/i18n.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../src/lib/i18n.ts"],"sourcesContent":["export interface Locale {\n id: string;\n name: string;\n /** `true` if the language is a right-to-left one, or `false` if it's left-to-right. */\n rtl?: boolean;\n /** `true` if the language is not supported by the application as a display language, but it is selectable by the user for the content. */\n contentOnly?: boolean;\n /** The value to pass to `--lang` for the Electron instance in order to set it as a locale. Not setting it will hide it from the list of supported locales. */\n electronLocale?: string;\n}"],"names":[],"rangeMappings":"","mappings":"AAAA,WASC"}

8
packages/commons/dist/lib/index.js vendored Normal file
View File

@@ -0,0 +1,8 @@
export * from "./i18n.js";
export * from "./options_interface.js";
export * from "./keyboard_actions_interface.js";
export * from "./hidden_subtree.js";
export * from "./rows.js";
export * from "./test-utils.js";
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../src/lib/index.ts"],"sourcesContent":["export * from \"./i18n.js\";\nexport * from \"./options_interface.js\";\nexport * from \"./keyboard_actions_interface.js\";\nexport * from \"./hidden_subtree.js\";\nexport * from \"./rows.js\";\nexport * from \"./test-utils.js\""],"names":[],"rangeMappings":";;;;;","mappings":"AAAA,cAAc,YAAY;AAC1B,cAAc,yBAAyB;AACvC,cAAc,kCAAkC;AAChD,cAAc,sBAAsB;AACpC,cAAc,YAAY;AAC1B,cAAc,kBAAiB"}

View File

@@ -0,0 +1,4 @@
var KeyboardActionNamesEnum;
export { };
//# sourceMappingURL=keyboard_actions_interface.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../src/lib/keyboard_actions_interface.ts"],"sourcesContent":["const enum KeyboardActionNamesEnum {\n backInNoteHistory,\n forwardInNoteHistory,\n jumpToNote,\n scrollToActiveNote,\n quickSearch,\n searchInSubtree,\n expandSubtree,\n collapseTree,\n collapseSubtree,\n sortChildNotes,\n createNoteAfter,\n createNoteInto,\n createNoteIntoInbox,\n deleteNotes,\n moveNoteUp,\n moveNoteDown,\n moveNoteUpInHierarchy,\n moveNoteDownInHierarchy,\n editNoteTitle,\n editBranchPrefix,\n cloneNotesTo,\n moveNotesTo,\n copyNotesToClipboard,\n pasteNotesFromClipboard,\n cutNotesToClipboard,\n selectAllNotesInParent,\n addNoteAboveToSelection,\n addNoteBelowToSelection,\n duplicateSubtree,\n openNewTab,\n closeActiveTab,\n reopenLastTab,\n activateNextTab,\n activatePreviousTab,\n openNewWindow,\n toggleTray,\n toggleZenMode,\n firstTab,\n secondTab,\n thirdTab,\n fourthTab,\n fifthTab,\n sixthTab,\n seventhTab,\n eigthTab,\n ninthTab,\n lastTab,\n showNoteSource,\n showOptions,\n showRevisions,\n showRecentChanges,\n showSQLConsole,\n showBackendLog,\n showCheatsheet,\n showHelp,\n addLinkToText,\n followLinkUnderCursor,\n insertDateTimeToText,\n pasteMarkdownIntoText,\n cutIntoNote,\n addIncludeNoteToText,\n editReadOnlyNote,\n addNewLabel,\n addNewRelation,\n toggleRibbonTabClassicEditor,\n toggleRibbonTabBasicProperties,\n toggleRibbonTabBookProperties,\n toggleRibbonTabFileProperties,\n toggleRibbonTabImageProperties,\n toggleRibbonTabOwnedAttributes,\n toggleRibbonTabInheritedAttributes,\n toggleRibbonTabPromotedAttributes,\n toggleRibbonTabNoteMap,\n toggleRibbonTabNoteInfo,\n toggleRibbonTabNotePaths,\n toggleRibbonTabSimilarNotes,\n toggleRightPane,\n printActiveNote,\n exportAsPdf,\n openNoteExternally,\n renderActiveNote,\n runActiveNote,\n toggleNoteHoisting,\n unhoist,\n reloadFrontendApp,\n openDevTools,\n findInText,\n toggleLeftPane,\n toggleFullscreen,\n zoomOut,\n zoomIn,\n zoomReset,\n copyWithoutFormatting,\n forceSaveRevision\n}\n\nexport type KeyboardActionNames = keyof typeof KeyboardActionNamesEnum;\n\nexport interface KeyboardShortcut {\n separator?: string;\n actionName?: KeyboardActionNames;\n description?: string;\n defaultShortcuts?: string[];\n effectiveShortcuts?: string[];\n /**\n * Scope here means on which element the keyboard shortcuts are attached - this means that for the shortcut to work,\n * the focus has to be inside the element.\n *\n * So e.g. shortcuts with \"note-tree\" scope work only when the focus is in note tree.\n * This allows to have the same shortcut have different actions attached based on the context\n * e.g. CTRL-C in note tree does something a bit different from CTRL-C in the text editor.\n */\n scope?: \"window\" | \"note-tree\" | \"text-detail\" | \"code-detail\";\n}\n\nexport interface KeyboardShortcutWithRequiredActionName extends KeyboardShortcut {\n actionName: KeyboardActionNames;\n}\n"],"names":[],"rangeMappings":";","mappings":";AAoHA,WAEC"}

View File

@@ -0,0 +1,3 @@
export { };
//# sourceMappingURL=options_interface.js.map

File diff suppressed because one or more lines are too long

27
packages/commons/dist/lib/rows.js vendored Normal file
View File

@@ -0,0 +1,27 @@
// TODO: Booleans should probably be numbers instead (as SQLite does not have booleans.);
// TODO: check against schema.sql which properties really are "optional"
/**
* There are many different Note types, some of which are entirely opaque to the
* end user. Those types should be used only for checking against, they are
* not for direct use.
*/ export const ALLOWED_NOTE_TYPES = [
"file",
"image",
"search",
"noteMap",
"launcher",
"doc",
"contentWidget",
"text",
"relationMap",
"render",
"canvas",
"mermaid",
"book",
"webView",
"code",
"mindMap",
"geoMap"
];
//# sourceMappingURL=rows.js.map

1
packages/commons/dist/lib/rows.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../src/lib/rows.ts"],"sourcesContent":["// TODO: Booleans should probably be numbers instead (as SQLite does not have booleans.);\n// TODO: check against schema.sql which properties really are \"optional\"\n\nexport interface AttachmentRow {\n attachmentId?: string;\n ownerId?: string;\n role: string;\n mime: string;\n title: string;\n position?: number;\n blobId?: string;\n isProtected?: boolean;\n dateModified?: string;\n utcDateModified?: string;\n utcDateScheduledForErasureSince?: string;\n isDeleted?: boolean;\n deleteId?: string;\n contentLength?: number;\n content?: Buffer | string;\n}\n\nexport interface RevisionRow {\n revisionId?: string;\n noteId: string;\n type: NoteType;\n mime: string;\n isProtected?: boolean;\n title: string;\n blobId?: string;\n dateLastEdited?: string;\n dateCreated: string;\n utcDateLastEdited?: string;\n utcDateCreated: string;\n utcDateModified: string;\n contentLength?: number;\n}\n\nexport interface RecentNoteRow {\n noteId: string;\n notePath: string;\n utcDateCreated?: string;\n}\n\n/**\n * Database representation of an option.\n *\n * Options are key-value pairs that are used to store information such as user preferences (for example\n * the current theme, sync server information), but also information about the state of the application).\n */\nexport interface OptionRow {\n /** The name of the option. */\n name: string;\n /** The value of the option. */\n value: string;\n /** `true` if the value should be synced across multiple instances (e.g. locale) or `false` if it should be local-only (e.g. theme). */\n isSynced: boolean;\n utcDateModified?: string;\n}\n\nexport interface EtapiTokenRow {\n etapiTokenId?: string;\n name: string;\n tokenHash: string;\n utcDateCreated?: string;\n utcDateModified?: string;\n isDeleted?: boolean;\n}\n\nexport interface BlobRow {\n blobId: string;\n content: string | Buffer;\n contentLength: number;\n dateModified: string;\n utcDateModified: string;\n}\n\nexport type AttributeType = \"label\" | \"relation\" | \"label-definition\" | \"relation-definition\";\n\nexport interface AttributeRow {\n attributeId?: string;\n noteId?: string;\n type: AttributeType;\n name: string;\n position?: number | null;\n value?: string;\n isInheritable?: boolean;\n utcDateModified?: string;\n}\n\nexport interface BranchRow {\n branchId?: string;\n noteId: string;\n parentNoteId: string;\n prefix?: string | null;\n notePosition?: number | null;\n isExpanded?: boolean;\n isDeleted?: boolean;\n utcDateModified?: string;\n}\n\n/**\n * There are many different Note types, some of which are entirely opaque to the\n * end user. Those types should be used only for checking against, they are\n * not for direct use.\n */\nexport const ALLOWED_NOTE_TYPES = [\n \"file\",\n \"image\",\n \"search\",\n \"noteMap\",\n \"launcher\",\n \"doc\",\n \"contentWidget\",\n \"text\",\n \"relationMap\",\n \"render\",\n \"canvas\",\n \"mermaid\",\n \"book\",\n \"webView\",\n \"code\",\n \"mindMap\",\n \"geoMap\"\n] as const;\nexport type NoteType = (typeof ALLOWED_NOTE_TYPES)[number];\n\nexport interface NoteRow {\n noteId: string;\n deleteId: string;\n title: string;\n type: NoteType;\n mime: string;\n isProtected: boolean;\n isDeleted: boolean;\n blobId: string;\n dateCreated: string;\n dateModified: string;\n utcDateCreated: string;\n utcDateModified: string;\n content?: string | Buffer;\n}\n\nexport interface NoteEmbeddingRow {\n embedId: string;\n noteId: string;\n providerId: string;\n modelId: string;\n dimension: number;\n embedding: Buffer;\n version: number;\n dateCreated: string;\n utcDateCreated: string;\n dateModified: string;\n utcDateModified: string;\n}\n"],"names":["ALLOWED_NOTE_TYPES"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,yFAAyF;AACzF,wEAAwE;AAmGxE;;;;CAIC,GACD,OAAO,MAAMA,qBAAqB;IAC9B;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACH,CAAU"}

55
packages/commons/dist/lib/test-utils.js vendored Normal file
View File

@@ -0,0 +1,55 @@
/**
* Reads the level of indentation of the first line and trims the identation for all the text by that amount.
*
* For example, for:
*
* ```json
* {
* "hello": "world"
* }
* ```
*
* it results in:
*
* ```json
* {
* "hello": "world"
* }
* ```
*
* This is meant to be used as a template string, where it allows the indentation of the template without affecting whitespace changes.
*
* @example const html = trimIndentation`\
* <h1>Heading 1</h1>
* <h2>Heading 2</h2>
* <h3>Heading 3</h3>
* <h4>Heading 4</h4>
* <h5>Heading 5</h5>
* <h6>Heading 6</h6>
* `;
* @param strings
* @returns
*/ export function trimIndentation(strings, ...values) {
// Combine the strings with the values using interpolation
let str = strings.reduce((acc, curr, index)=>{
return acc + curr + (values[index] !== undefined ? values[index] : '');
}, '');
// Count the number of spaces on the first line.
let numSpaces = 0;
while(str.charAt(numSpaces) == " " && numSpaces < str.length){
numSpaces++;
}
// Trim the indentation of the first line in all the lines.
const lines = str.split("\n");
const output = [];
for(let i = 0; i < lines.length; i++){
let numSpacesLine = 0;
while(str.charAt(numSpacesLine) == " " && numSpacesLine < str.length){
numSpacesLine++;
}
output.push(lines[i].substring(numSpacesLine));
}
return output.join("\n");
}
//# sourceMappingURL=test-utils.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../src/lib/test-utils.ts"],"sourcesContent":["/**\n * Reads the level of indentation of the first line and trims the identation for all the text by that amount.\n *\n * For example, for:\n *\n * ```json\n * {\n * \"hello\": \"world\"\n * }\n * ```\n *\n * it results in:\n *\n * ```json\n * {\n * \"hello\": \"world\"\n * }\n * ```\n *\n * This is meant to be used as a template string, where it allows the indentation of the template without affecting whitespace changes.\n *\n * @example const html = trimIndentation`\\\n * <h1>Heading 1</h1>\n * <h2>Heading 2</h2>\n * <h3>Heading 3</h3>\n * <h4>Heading 4</h4>\n * <h5>Heading 5</h5>\n * <h6>Heading 6</h6>\n * `;\n * @param strings\n * @returns\n */\nexport function trimIndentation(strings: TemplateStringsArray, ...values: any[]) {\n // Combine the strings with the values using interpolation\n let str = strings.reduce((acc, curr, index) => {\n return acc + curr + (values[index] !== undefined ? values[index] : '');\n }, '');\n\n // Count the number of spaces on the first line.\n let numSpaces = 0;\n while (str.charAt(numSpaces) == \" \" && numSpaces < str.length) {\n numSpaces++;\n }\n\n // Trim the indentation of the first line in all the lines.\n const lines = str.split(\"\\n\");\n const output = [];\n for (let i = 0; i < lines.length; i++) {\n let numSpacesLine = 0;\n while (str.charAt(numSpacesLine) == \" \" && numSpacesLine < str.length) {\n numSpacesLine++;\n }\n output.push(lines[i].substring(numSpacesLine));\n }\n return output.join(\"\\n\");\n}\n"],"names":["trimIndentation","strings","values","str","reduce","acc","curr","index","undefined","numSpaces","charAt","length","lines","split","output","i","numSpacesLine","push","substring","join"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BC,GACD,OAAO,SAASA,gBAAgBC,OAA6B,EAAE,GAAGC,MAAa;IAC3E,0DAA0D;IAC1D,IAAIC,MAAMF,QAAQG,MAAM,CAAC,CAACC,KAAKC,MAAMC;QACjC,OAAOF,MAAMC,OAAQJ,CAAAA,MAAM,CAACK,MAAM,KAAKC,YAAYN,MAAM,CAACK,MAAM,GAAG,EAAC;IACxE,GAAG;IAEH,gDAAgD;IAChD,IAAIE,YAAY;IAChB,MAAON,IAAIO,MAAM,CAACD,cAAc,OAAOA,YAAYN,IAAIQ,MAAM,CAAE;QAC3DF;IACJ;IAEA,2DAA2D;IAC3D,MAAMG,QAAQT,IAAIU,KAAK,CAAC;IACxB,MAAMC,SAAS,EAAE;IACjB,IAAK,IAAIC,IAAI,GAAGA,IAAIH,MAAMD,MAAM,EAAEI,IAAK;QACnC,IAAIC,gBAAgB;QACpB,MAAOb,IAAIO,MAAM,CAACM,kBAAkB,OAAOA,gBAAgBb,IAAIQ,MAAM,CAAE;YACnEK;QACJ;QACAF,OAAOG,IAAI,CAACL,KAAK,CAACG,EAAE,CAACG,SAAS,CAACF;IACnC;IACA,OAAOF,OAAOK,IAAI,CAAC;AACvB"}

View File

@@ -0,0 +1 @@
{"version":"5.7.3"}

View File

@@ -1,7 +0,0 @@
import { commons } from './commons.js';
describe('commons', () => {
it('should work', () => {
expect(commons()).toEqual('commons');
})
})

View File

@@ -1,3 +0,0 @@
export function commons(): string {
return 'commons';
}

View File

@@ -0,0 +1,45 @@
import { AttributeType } from "./rows.js";
type LauncherNoteType = "launcher" | "search" | "doc" | "noteMap" | "contentWidget" | "book" | "file" | "image" | "text" | "relationMap" | "render" | "canvas" | "mermaid" | "webView" | "code" | "mindMap" | "geoMap";
enum Command {
jumpToNote,
searchNotes,
createNoteIntoInbox,
showRecentChanges,
showOptions,
createAiChat
}
export interface HiddenSubtreeAttribute {
type: AttributeType;
name: string;
isInheritable?: boolean;
value?: string;
}
export interface HiddenSubtreeItem {
notePosition?: number;
id: string;
title: string;
type: LauncherNoteType;
icon?: string;
attributes?: HiddenSubtreeAttribute[];
children?: HiddenSubtreeItem[];
isExpanded?: boolean;
baseSize?: string;
growthFactor?: string;
targetNoteId?: "_backendLog" | "_globalNoteMap";
builtinWidget?:
| "todayInJournal"
| "bookmarks"
| "spacer"
| "backInHistoryButton"
| "forwardInHistoryButton"
| "syncStatus"
| "protectedSession"
| "calendar"
| "quickSearch"
| "aiChatLauncher";
command?: keyof typeof Command;
}

View File

@@ -0,0 +1,10 @@
export interface Locale {
id: string;
name: string;
/** `true` if the language is a right-to-left one, or `false` if it's left-to-right. */
rtl?: boolean;
/** `true` if the language is not supported by the application as a display language, but it is selectable by the user for the content. */
contentOnly?: boolean;
/** The value to pass to `--lang` for the Electron instance in order to set it as a locale. Not setting it will hide it from the list of supported locales. */
electronLocale?: string;
}

View File

@@ -0,0 +1,6 @@
export * from "./i18n.js";
export * from "./options_interface.js";
export * from "./keyboard_actions_interface.js";
export * from "./hidden_subtree.js";
export * from "./rows.js";
export * from "./test-utils.js"

View File

@@ -0,0 +1,119 @@
const enum KeyboardActionNamesEnum {
backInNoteHistory,
forwardInNoteHistory,
jumpToNote,
scrollToActiveNote,
quickSearch,
searchInSubtree,
expandSubtree,
collapseTree,
collapseSubtree,
sortChildNotes,
createNoteAfter,
createNoteInto,
createNoteIntoInbox,
deleteNotes,
moveNoteUp,
moveNoteDown,
moveNoteUpInHierarchy,
moveNoteDownInHierarchy,
editNoteTitle,
editBranchPrefix,
cloneNotesTo,
moveNotesTo,
copyNotesToClipboard,
pasteNotesFromClipboard,
cutNotesToClipboard,
selectAllNotesInParent,
addNoteAboveToSelection,
addNoteBelowToSelection,
duplicateSubtree,
openNewTab,
closeActiveTab,
reopenLastTab,
activateNextTab,
activatePreviousTab,
openNewWindow,
toggleTray,
toggleZenMode,
firstTab,
secondTab,
thirdTab,
fourthTab,
fifthTab,
sixthTab,
seventhTab,
eigthTab,
ninthTab,
lastTab,
showNoteSource,
showOptions,
showRevisions,
showRecentChanges,
showSQLConsole,
showBackendLog,
showCheatsheet,
showHelp,
addLinkToText,
followLinkUnderCursor,
insertDateTimeToText,
pasteMarkdownIntoText,
cutIntoNote,
addIncludeNoteToText,
editReadOnlyNote,
addNewLabel,
addNewRelation,
toggleRibbonTabClassicEditor,
toggleRibbonTabBasicProperties,
toggleRibbonTabBookProperties,
toggleRibbonTabFileProperties,
toggleRibbonTabImageProperties,
toggleRibbonTabOwnedAttributes,
toggleRibbonTabInheritedAttributes,
toggleRibbonTabPromotedAttributes,
toggleRibbonTabNoteMap,
toggleRibbonTabNoteInfo,
toggleRibbonTabNotePaths,
toggleRibbonTabSimilarNotes,
toggleRightPane,
printActiveNote,
exportAsPdf,
openNoteExternally,
renderActiveNote,
runActiveNote,
toggleNoteHoisting,
unhoist,
reloadFrontendApp,
openDevTools,
findInText,
toggleLeftPane,
toggleFullscreen,
zoomOut,
zoomIn,
zoomReset,
copyWithoutFormatting,
forceSaveRevision
}
export type KeyboardActionNames = keyof typeof KeyboardActionNamesEnum;
export interface KeyboardShortcut {
separator?: string;
actionName?: KeyboardActionNames;
description?: string;
defaultShortcuts?: string[];
effectiveShortcuts?: string[];
/**
* Scope here means on which element the keyboard shortcuts are attached - this means that for the shortcut to work,
* the focus has to be inside the element.
*
* So e.g. shortcuts with "note-tree" scope work only when the focus is in note tree.
* This allows to have the same shortcut have different actions attached based on the context
* e.g. CTRL-C in note tree does something a bit different from CTRL-C in the text editor.
*/
scope?: "window" | "note-tree" | "text-detail" | "code-detail";
}
export interface KeyboardShortcutWithRequiredActionName extends KeyboardShortcut {
actionName: KeyboardActionNames;
}

View File

@@ -0,0 +1,164 @@
import type { KeyboardActionNames } from "./keyboard_actions_interface.js";
/**
* A dictionary where the keys are the option keys (e.g. `theme`) and their corresponding values.
*/
export type OptionMap = Record<OptionNames, string>;
/**
* For each keyboard action, there is a corresponding option which identifies the key combination defined by the user.
*/
type KeyboardShortcutsOptions<T extends KeyboardActionNames> = {
[key in T as `keyboardShortcuts${Capitalize<key>}`]: string;
};
export type FontFamily = "theme" | "serif" | "sans-serif" | "monospace" | string;
export interface OptionDefinitions extends KeyboardShortcutsOptions<KeyboardActionNames> {
openNoteContexts: string;
lastDailyBackupDate: string;
lastWeeklyBackupDate: string;
lastMonthlyBackupDate: string;
dbVersion: string;
theme: string;
syncServerHost: string;
syncServerTimeout: string;
syncProxy: string;
mainFontFamily: FontFamily;
treeFontFamily: FontFamily;
detailFontFamily: FontFamily;
monospaceFontFamily: FontFamily;
spellCheckLanguageCode: string;
codeNotesMimeTypes: string;
headingStyle: string;
highlightsList: string;
customSearchEngineName: string;
customSearchEngineUrl: string;
locale: string;
formattingLocale: string;
codeBlockTheme: string;
textNoteEditorType: string;
layoutOrientation: string;
allowedHtmlTags: string;
documentId: string;
documentSecret: string;
passwordVerificationHash: string;
passwordVerificationSalt: string;
passwordDerivedKeySalt: string;
encryptedDataKey: string;
hoistedNoteId: string;
// Multi-Factor Authentication
mfaEnabled: boolean;
mfaMethod: string;
totpEncryptionSalt: string;
totpEncryptedSecret: string;
totpVerificationHash: string;
encryptedRecoveryCodes: boolean;
userSubjectIdentifierSaved: boolean;
recoveryCodeInitialVector: string;
recoveryCodeSecurityKey: string;
recoveryCodesEncrypted: string;
lastSyncedPull: number;
lastSyncedPush: number;
revisionSnapshotTimeInterval: number;
revisionSnapshotTimeIntervalTimeScale: number;
revisionSnapshotNumberLimit: number;
protectedSessionTimeout: number;
protectedSessionTimeoutTimeScale: number;
zoomFactor: number;
mainFontSize: number;
treeFontSize: number;
detailFontSize: number;
monospaceFontSize: number;
imageMaxWidthHeight: number;
imageJpegQuality: number;
leftPaneWidth: number;
rightPaneWidth: number;
eraseEntitiesAfterTimeInSeconds: number;
eraseEntitiesAfterTimeScale: number;
autoReadonlySizeText: number;
autoReadonlySizeCode: number;
maxContentWidth: number;
minTocHeadings: number;
eraseUnusedAttachmentsAfterSeconds: number;
eraseUnusedAttachmentsAfterTimeScale: number;
firstDayOfWeek: number;
firstWeekOfYear: number;
minDaysInFirstWeek: number;
languages: string;
// Appearance
splitEditorOrientation: "horziontal" | "vertical";
initialized: boolean;
isPasswordSet: boolean;
overrideThemeFonts: boolean;
spellCheckEnabled: boolean;
autoFixConsistencyIssues: boolean;
vimKeymapEnabled: boolean;
codeLineWrapEnabled: boolean;
leftPaneVisible: boolean;
rightPaneVisible: boolean;
nativeTitleBarVisible: boolean;
hideArchivedNotes_main: boolean;
debugModeEnabled: boolean;
autoCollapseNoteTree: boolean;
dailyBackupEnabled: boolean;
weeklyBackupEnabled: boolean;
monthlyBackupEnabled: boolean;
compressImages: boolean;
downloadImagesAutomatically: boolean;
checkForUpdates: boolean;
disableTray: boolean;
promotedAttributesOpenInRibbon: boolean;
editedNotesOpenInRibbon: boolean;
codeBlockWordWrap: boolean;
textNoteEditorMultilineToolbar: boolean;
backgroundEffects: boolean;
// Share settings
redirectBareDomain: boolean;
showLoginInShareTheme: boolean;
// AI/LLM integration options
aiEnabled: boolean;
aiProvider: string;
aiSystemPrompt: string;
aiTemperature: string;
openaiApiKey: string;
openaiDefaultModel: string;
openaiEmbeddingModel: string;
openaiBaseUrl: string;
anthropicApiKey: string;
anthropicDefaultModel: string;
voyageEmbeddingModel: string;
voyageApiKey: string;
anthropicBaseUrl: string;
ollamaEnabled: boolean;
ollamaBaseUrl: string;
ollamaDefaultModel: string;
ollamaEmbeddingModel: string;
codeOpenAiModel: string;
aiProviderPrecedence: string;
// Embedding-related options
embeddingAutoUpdateEnabled: boolean;
embeddingUpdateInterval: number;
embeddingBatchSize: number;
embeddingDefaultDimension: number;
embeddingsDefaultProvider: string;
embeddingProviderPrecedence: string;
enableAutomaticIndexing: boolean;
embeddingGenerationLocation: string;
embeddingDimensionStrategy: string;
embeddingSimilarityThreshold: number;
maxNotesPerLlmQuery: number;
}
export type OptionNames = keyof OptionDefinitions;
export type FilterOptionsByType<U> = {
[K in keyof OptionDefinitions]: OptionDefinitions[K] extends U ? K : never;
}[keyof OptionDefinitions];

View File

@@ -0,0 +1,155 @@
// TODO: Booleans should probably be numbers instead (as SQLite does not have booleans.);
// TODO: check against schema.sql which properties really are "optional"
export interface AttachmentRow {
attachmentId?: string;
ownerId?: string;
role: string;
mime: string;
title: string;
position?: number;
blobId?: string;
isProtected?: boolean;
dateModified?: string;
utcDateModified?: string;
utcDateScheduledForErasureSince?: string;
isDeleted?: boolean;
deleteId?: string;
contentLength?: number;
content?: Buffer | string;
}
export interface RevisionRow {
revisionId?: string;
noteId: string;
type: NoteType;
mime: string;
isProtected?: boolean;
title: string;
blobId?: string;
dateLastEdited?: string;
dateCreated: string;
utcDateLastEdited?: string;
utcDateCreated: string;
utcDateModified: string;
contentLength?: number;
}
export interface RecentNoteRow {
noteId: string;
notePath: string;
utcDateCreated?: string;
}
/**
* Database representation of an option.
*
* Options are key-value pairs that are used to store information such as user preferences (for example
* the current theme, sync server information), but also information about the state of the application).
*/
export interface OptionRow {
/** The name of the option. */
name: string;
/** The value of the option. */
value: string;
/** `true` if the value should be synced across multiple instances (e.g. locale) or `false` if it should be local-only (e.g. theme). */
isSynced: boolean;
utcDateModified?: string;
}
export interface EtapiTokenRow {
etapiTokenId?: string;
name: string;
tokenHash: string;
utcDateCreated?: string;
utcDateModified?: string;
isDeleted?: boolean;
}
export interface BlobRow {
blobId: string;
content: string | Buffer;
contentLength: number;
dateModified: string;
utcDateModified: string;
}
export type AttributeType = "label" | "relation" | "label-definition" | "relation-definition";
export interface AttributeRow {
attributeId?: string;
noteId?: string;
type: AttributeType;
name: string;
position?: number | null;
value?: string;
isInheritable?: boolean;
utcDateModified?: string;
}
export interface BranchRow {
branchId?: string;
noteId: string;
parentNoteId: string;
prefix?: string | null;
notePosition?: number | null;
isExpanded?: boolean;
isDeleted?: boolean;
utcDateModified?: string;
}
/**
* There are many different Note types, some of which are entirely opaque to the
* end user. Those types should be used only for checking against, they are
* not for direct use.
*/
export const ALLOWED_NOTE_TYPES = [
"file",
"image",
"search",
"noteMap",
"launcher",
"doc",
"contentWidget",
"text",
"relationMap",
"render",
"canvas",
"mermaid",
"book",
"webView",
"code",
"mindMap",
"geoMap"
] as const;
export type NoteType = (typeof ALLOWED_NOTE_TYPES)[number];
export interface NoteRow {
noteId: string;
deleteId: string;
title: string;
type: NoteType;
mime: string;
isProtected: boolean;
isDeleted: boolean;
blobId: string;
dateCreated: string;
dateModified: string;
utcDateCreated: string;
utcDateModified: string;
content?: string | Buffer;
}
export interface NoteEmbeddingRow {
embedId: string;
noteId: string;
providerId: string;
modelId: string;
dimension: number;
embedding: Buffer;
version: number;
dateCreated: string;
utcDateCreated: string;
dateModified: string;
utcDateModified: string;
}

View File

@@ -0,0 +1,14 @@
import { describe, it, expect } from "vitest";
import { trimIndentation } from "./test-utils.js";
describe("Utils", () => {
it("trims indentation", () => {
expect(trimIndentation`\
Hello
world
123`).toBe(`\
Hello
world
123`);
});
});

View File

@@ -0,0 +1,56 @@
/**
* Reads the level of indentation of the first line and trims the identation for all the text by that amount.
*
* For example, for:
*
* ```json
* {
* "hello": "world"
* }
* ```
*
* it results in:
*
* ```json
* {
* "hello": "world"
* }
* ```
*
* This is meant to be used as a template string, where it allows the indentation of the template without affecting whitespace changes.
*
* @example const html = trimIndentation`\
* <h1>Heading 1</h1>
* <h2>Heading 2</h2>
* <h3>Heading 3</h3>
* <h4>Heading 4</h4>
* <h5>Heading 5</h5>
* <h6>Heading 6</h6>
* `;
* @param strings
* @returns
*/
export function trimIndentation(strings: TemplateStringsArray, ...values: any[]) {
// Combine the strings with the values using interpolation
let str = strings.reduce((acc, curr, index) => {
return acc + curr + (values[index] !== undefined ? values[index] : '');
}, '');
// Count the number of spaces on the first line.
let numSpaces = 0;
while (str.charAt(numSpaces) == " " && numSpaces < str.length) {
numSpaces++;
}
// Trim the indentation of the first line in all the lines.
const lines = str.split("\n");
const output = [];
for (let i = 0; i < lines.length; i++) {
let numSpacesLine = 0;
while (str.charAt(numSpacesLine) == " " && numSpacesLine < str.length) {
numSpacesLine++;
}
output.push(lines[i].substring(numSpacesLine));
}
return output.join("\n");
}