mirror of
https://github.com/zadam/trilium.git
synced 2026-03-27 22:30:18 +01:00
Compare commits
19 Commits
feature/st
...
standalone
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ec2160eff | ||
|
|
6c75df70e0 | ||
|
|
0211535f73 | ||
|
|
2d4027c214 | ||
|
|
5b3fb315d7 | ||
|
|
24650edd62 | ||
|
|
d29d1428ed | ||
|
|
91d526b15f | ||
|
|
22c86cf3b5 | ||
|
|
a0573c439b | ||
|
|
050cdd0a85 | ||
|
|
55f09fe21a | ||
|
|
f069b41df6 | ||
|
|
f81369d643 | ||
|
|
f1d7d34f1a | ||
|
|
ce1f7a4274 | ||
|
|
6ce1d31ceb | ||
|
|
ecb467f2b7 | ||
|
|
4ffaadd481 |
@@ -40,12 +40,14 @@
|
||||
"color": "5.0.3",
|
||||
"debounce": "3.0.0",
|
||||
"draggabilly": "3.0.0",
|
||||
"fflate": "0.8.2",
|
||||
"force-graph": "1.51.2",
|
||||
"globals": "17.4.0",
|
||||
"i18next": "25.10.10",
|
||||
"i18next-http-backend": "3.0.2",
|
||||
"jquery": "4.0.0",
|
||||
"jquery.fancytree": "2.38.5",
|
||||
"js-md5": "0.8.3",
|
||||
"js-sha1": "0.7.0",
|
||||
"js-sha256": "0.11.1",
|
||||
"js-sha512": "0.9.0",
|
||||
|
||||
@@ -5,6 +5,12 @@
|
||||
|
||||
import { getContext, routes } from "@triliumnext/core";
|
||||
|
||||
export interface UploadedFile {
|
||||
originalname: string;
|
||||
mimetype: string;
|
||||
buffer: Uint8Array;
|
||||
}
|
||||
|
||||
export interface BrowserRequest {
|
||||
method: string;
|
||||
url: string;
|
||||
@@ -13,6 +19,7 @@ export interface BrowserRequest {
|
||||
query: Record<string, string | undefined>;
|
||||
headers?: Record<string, string>;
|
||||
body?: unknown;
|
||||
file?: UploadedFile;
|
||||
}
|
||||
|
||||
export interface BrowserResponse {
|
||||
@@ -154,8 +161,9 @@ export class BrowserRouter {
|
||||
const query = parseQuery(url.search);
|
||||
const upperMethod = method.toUpperCase();
|
||||
|
||||
// Parse JSON body if it's an ArrayBuffer and content-type suggests JSON
|
||||
// Parse body based on content-type
|
||||
let parsedBody = body;
|
||||
let uploadedFile: UploadedFile | undefined;
|
||||
if (body instanceof ArrayBuffer && headers) {
|
||||
const contentType = headers['content-type'] || headers['Content-Type'] || '';
|
||||
if (contentType.includes('application/json')) {
|
||||
@@ -166,9 +174,31 @@ export class BrowserRouter {
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[Router] Failed to parse JSON body:', e);
|
||||
// Keep original body if JSON parsing fails
|
||||
parsedBody = body;
|
||||
}
|
||||
} else if (contentType.includes('multipart/form-data')) {
|
||||
try {
|
||||
// Reconstruct a Response so we can use the native FormData parser
|
||||
const response = new Response(body, { headers: { 'content-type': contentType } });
|
||||
const formData = await response.formData();
|
||||
const formFields: Record<string, string> = {};
|
||||
for (const [key, value] of formData.entries()) {
|
||||
if (typeof value === 'string') {
|
||||
formFields[key] = value;
|
||||
} else {
|
||||
// File field (Blob) — multer uses the field name "upload"
|
||||
const fileBuffer = new Uint8Array(await value.arrayBuffer());
|
||||
uploadedFile = {
|
||||
originalname: value.name,
|
||||
mimetype: value.type || 'application/octet-stream',
|
||||
buffer: fileBuffer
|
||||
};
|
||||
}
|
||||
}
|
||||
parsedBody = formFields;
|
||||
} catch (e) {
|
||||
console.warn('[Router] Failed to parse multipart body:', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Find matching route
|
||||
@@ -191,7 +221,8 @@ export class BrowserRouter {
|
||||
params,
|
||||
query,
|
||||
headers: headers ?? {},
|
||||
body: parsedBody
|
||||
body: parsedBody,
|
||||
file: uploadedFile
|
||||
};
|
||||
|
||||
try {
|
||||
|
||||
@@ -35,6 +35,7 @@ function toExpressLikeReq(req: BrowserRequest) {
|
||||
body: req.body,
|
||||
headers: req.headers ?? {},
|
||||
method: req.method,
|
||||
file: req.file,
|
||||
get originalUrl() { return req.url; }
|
||||
};
|
||||
}
|
||||
@@ -121,6 +122,45 @@ function createRoute(router: BrowserRouter) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Async variant of createRoute for handlers that return Promises (e.g. import).
|
||||
* Uses transactionalAsync (manual BEGIN/COMMIT/ROLLBACK) instead of the synchronous
|
||||
* transactional() wrapper, which would commit an empty transaction immediately when
|
||||
* passed an async callback.
|
||||
*/
|
||||
function createAsyncRoute(router: BrowserRouter) {
|
||||
return (method: HttpMethod, path: string, _middleware: any[], handler: (req: any, res: any) => Promise<unknown>, resultHandler?: ((req: any, res: any, result: unknown) => unknown) | null) => {
|
||||
router.register(method, path, (req: BrowserRequest) => {
|
||||
return getContext().init(async () => {
|
||||
setContextFromHeaders(req);
|
||||
const expressLikeReq = toExpressLikeReq(req);
|
||||
const mockRes = createMockExpressResponse();
|
||||
const result = await getSql().transactionalAsync(() => handler(expressLikeReq, mockRes));
|
||||
|
||||
// If the handler used the mock response (e.g. image routes that call res.send()),
|
||||
// return it as a raw response so BrowserRouter doesn't JSON-serialize it.
|
||||
if (mockRes._used) {
|
||||
return {
|
||||
[RAW_RESPONSE]: true as const,
|
||||
status: mockRes._status,
|
||||
headers: mockRes._headers,
|
||||
body: mockRes._body
|
||||
};
|
||||
}
|
||||
|
||||
if (resultHandler) {
|
||||
// Create a minimal response object that captures what apiResultHandler sets.
|
||||
const res = createResultHandlerResponse();
|
||||
resultHandler(expressLikeReq, res, result);
|
||||
return res.result;
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a mock Express response object that captures calls to set(), send(), sendStatus(), etc.
|
||||
* Used for route handlers (like image routes) that write directly to the response.
|
||||
@@ -219,7 +259,7 @@ export function registerRoutes(router: BrowserRouter): void {
|
||||
const apiRoute = createApiRoute(router, true);
|
||||
routes.buildSharedApiRoutes({
|
||||
route: createRoute(router),
|
||||
asyncRoute: createRoute(router),
|
||||
asyncRoute: createAsyncRoute(router),
|
||||
apiRoute,
|
||||
asyncApiRoute: createApiRoute(router, false),
|
||||
apiResultHandler,
|
||||
@@ -227,7 +267,9 @@ export function registerRoutes(router: BrowserRouter): void {
|
||||
checkApiAuthOrElectron: noopMiddleware,
|
||||
checkAppNotInitialized,
|
||||
checkCredentials: noopMiddleware,
|
||||
loginRateLimiter: noopMiddleware
|
||||
loginRateLimiter: noopMiddleware,
|
||||
uploadMiddlewareWithErrorHandling: noopMiddleware,
|
||||
csrfMiddleware: noopMiddleware
|
||||
});
|
||||
apiRoute('get', '/bootstrap', bootstrapRoute);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { CryptoProvider } from "@triliumnext/core";
|
||||
import { sha1 } from "js-sha1";
|
||||
import { sha256 } from "js-sha256";
|
||||
import { sha512 } from "js-sha512";
|
||||
import { md5 } from "js-md5";
|
||||
|
||||
interface Cipher {
|
||||
update(data: Uint8Array): Uint8Array;
|
||||
@@ -15,11 +16,18 @@ const CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
*/
|
||||
export default class BrowserCryptoProvider implements CryptoProvider {
|
||||
|
||||
createHash(algorithm: "sha1" | "sha512", content: string | Uint8Array): Uint8Array {
|
||||
createHash(algorithm: "md5" | "sha1" | "sha512", content: string | Uint8Array): Uint8Array {
|
||||
const data = typeof content === "string" ? content :
|
||||
new TextDecoder().decode(content);
|
||||
|
||||
const hexHash = algorithm === "sha1" ? sha1(data) : sha512(data);
|
||||
let hexHash: string;
|
||||
if (algorithm === "md5") {
|
||||
hexHash = md5(data);
|
||||
} else if (algorithm === "sha1") {
|
||||
hexHash = sha1(data);
|
||||
} else {
|
||||
hexHash = sha512(data);
|
||||
}
|
||||
|
||||
// Convert hex string to Uint8Array
|
||||
const bytes = new Uint8Array(hexHash.length / 2);
|
||||
|
||||
@@ -501,9 +501,12 @@ export default class BrowserSqlProvider implements DatabaseProvider {
|
||||
|
||||
// Helper function to execute within a transaction
|
||||
const executeTransaction = (beginStatement: string, ...args: unknown[]): T => {
|
||||
// If we're already in a transaction, use SAVEPOINTs for nesting
|
||||
// This mimics better-sqlite3's behavior
|
||||
if (self._inTransaction) {
|
||||
// If we're already in a transaction (either tracked via JS flag or via actual SQLite
|
||||
// autocommit state), use SAVEPOINTs for nesting — this handles the case where a manual
|
||||
// BEGIN was issued directly (e.g. transactionalAsync) without going through transaction().
|
||||
const sqliteInTransaction = self.db?.pointer !== undefined
|
||||
&& (self.sqlite3!.capi as any).sqlite3_get_autocommit(self.db!.pointer) === 0;
|
||||
if (self._inTransaction || sqliteInTransaction) {
|
||||
const savepointName = `sp_${++savepointCounter}_${Date.now()}`;
|
||||
self.db!.exec(`SAVEPOINT ${savepointName}`);
|
||||
try {
|
||||
|
||||
27
apps/client-standalone/src/lightweight/zip_provider.ts
Normal file
27
apps/client-standalone/src/lightweight/zip_provider.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import type { ZipEntry, ZipProvider } from "@triliumnext/core/src/services/import/zip_provider.js";
|
||||
import { unzip } from "fflate";
|
||||
|
||||
export default class BrowserZipProvider implements ZipProvider {
|
||||
readZipFile(
|
||||
buffer: Uint8Array,
|
||||
processEntry: (entry: ZipEntry, readContent: () => Promise<Uint8Array>) => Promise<void>
|
||||
): Promise<void> {
|
||||
return new Promise<void>((res, rej) => {
|
||||
unzip(buffer, async (err, files) => {
|
||||
if (err) { rej(err); return; }
|
||||
|
||||
try {
|
||||
for (const [fileName, data] of Object.entries(files)) {
|
||||
await processEntry(
|
||||
{ fileName },
|
||||
() => Promise.resolve(data)
|
||||
);
|
||||
}
|
||||
res();
|
||||
} catch (e) {
|
||||
rej(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -55,6 +55,7 @@ let BrowserSqlProvider: typeof import('./lightweight/sql_provider').default;
|
||||
let WorkerMessagingProvider: typeof import('./lightweight/messaging_provider').default;
|
||||
let BrowserExecutionContext: typeof import('./lightweight/cls_provider').default;
|
||||
let BrowserCryptoProvider: typeof import('./lightweight/crypto_provider').default;
|
||||
let BrowserZipProvider: typeof import('./lightweight/zip_provider').default;
|
||||
let FetchRequestProvider: typeof import('./lightweight/request_provider').default;
|
||||
let StandalonePlatformProvider: typeof import('./lightweight/platform_provider').default;
|
||||
let translationProvider: typeof import('./lightweight/translation_provider').default;
|
||||
@@ -82,6 +83,7 @@ async function loadModules(): Promise<void> {
|
||||
messagingModule,
|
||||
clsModule,
|
||||
cryptoModule,
|
||||
zipModule,
|
||||
requestModule,
|
||||
platformModule,
|
||||
translationModule,
|
||||
@@ -91,6 +93,7 @@ async function loadModules(): Promise<void> {
|
||||
import('./lightweight/messaging_provider.js'),
|
||||
import('./lightweight/cls_provider.js'),
|
||||
import('./lightweight/crypto_provider.js'),
|
||||
import('./lightweight/zip_provider.js'),
|
||||
import('./lightweight/request_provider.js'),
|
||||
import('./lightweight/platform_provider.js'),
|
||||
import('./lightweight/translation_provider.js'),
|
||||
@@ -101,6 +104,7 @@ async function loadModules(): Promise<void> {
|
||||
WorkerMessagingProvider = messagingModule.default;
|
||||
BrowserExecutionContext = clsModule.default;
|
||||
BrowserCryptoProvider = cryptoModule.default;
|
||||
BrowserZipProvider = zipModule.default;
|
||||
FetchRequestProvider = requestModule.default;
|
||||
StandalonePlatformProvider = platformModule.default;
|
||||
translationProvider = translationModule.default;
|
||||
@@ -152,11 +156,17 @@ async function initialize(): Promise<void> {
|
||||
await coreModule.initializeCore({
|
||||
executionContext: new BrowserExecutionContext(),
|
||||
crypto: new BrowserCryptoProvider(),
|
||||
zip: new BrowserZipProvider(),
|
||||
messaging: messagingProvider!,
|
||||
request: new FetchRequestProvider(),
|
||||
platform: new StandalonePlatformProvider(queryString),
|
||||
translations: translationProvider,
|
||||
schema: schemaModule.default,
|
||||
getDemoArchive: async () => {
|
||||
const response = await fetch("/server-assets/db/demo.zip");
|
||||
if (!response.ok) return null;
|
||||
return new Uint8Array(await response.arrayBuffer());
|
||||
},
|
||||
dbConfig: {
|
||||
provider: sqlProvider!,
|
||||
isReadOnly: false,
|
||||
|
||||
12
apps/desktop-standalone/.github/FUNDING.yml
vendored
12
apps/desktop-standalone/.github/FUNDING.yml
vendored
@@ -1,12 +0,0 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: shalithasuranga
|
||||
patreon: shalithasuranga
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
18
apps/desktop-standalone/.gitignore
vendored
18
apps/desktop-standalone/.gitignore
vendored
@@ -1,18 +0,0 @@
|
||||
# Developer tools' files
|
||||
.lite_workspace.lua
|
||||
|
||||
# Neutralinojs binaries and builds
|
||||
/bin
|
||||
/dist
|
||||
|
||||
# Neutralinojs client (minified)
|
||||
neutralino.js
|
||||
|
||||
# Neutralinojs related files
|
||||
.storage
|
||||
*.log
|
||||
.tmp
|
||||
|
||||
# Files managed by the build script
|
||||
resources
|
||||
neutralino.config.json
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Neutralinojs and contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,15 +0,0 @@
|
||||
# neutralinojs-minimal
|
||||
|
||||
The default template for a Neutralinojs app. It's possible to use your favorite frontend framework by using [these steps](https://neutralino.js.org/docs/getting-started/using-frontend-libraries).
|
||||
|
||||
## Contributors
|
||||
|
||||
[](https://github.com/neutralinojs/neutralinojs-minimal/graphs/contributors)
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
||||
## Icon credits
|
||||
|
||||
- `trayIcon.png` - Made by [Freepik](https://www.freepik.com) and downloaded from [Flaticon](https://www.flaticon.com)
|
||||
@@ -1,83 +0,0 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/neutralinojs/neutralinojs/main/schemas/neutralino.config.schema.json",
|
||||
"applicationId": "js.neutralino.sample",
|
||||
"version": "1.0.0",
|
||||
"defaultMode": "window",
|
||||
"port": 0,
|
||||
"documentRoot": "/resources/",
|
||||
"url": "/",
|
||||
"enableServer": true,
|
||||
"enableNativeAPI": true,
|
||||
"tokenSecurity": "one-time",
|
||||
"logging": {
|
||||
"enabled": true,
|
||||
"writeToLogFile": true
|
||||
},
|
||||
"nativeAllowList": [
|
||||
"app.*",
|
||||
"os.*",
|
||||
"debug.log"
|
||||
],
|
||||
"globalVariables": {
|
||||
"TEST1": "Hello",
|
||||
"TEST2": [
|
||||
2,
|
||||
4,
|
||||
5
|
||||
],
|
||||
"TEST3": {
|
||||
"value1": 10,
|
||||
"value2": {}
|
||||
}
|
||||
},
|
||||
"modes": {
|
||||
"window": {
|
||||
"title": "Trilium Notes Lite",
|
||||
"width": 800,
|
||||
"height": 500,
|
||||
"minWidth": 400,
|
||||
"minHeight": 200,
|
||||
"center": true,
|
||||
"fullScreen": false,
|
||||
"alwaysOnTop": false,
|
||||
"icon": "/resources/assets/icon.png",
|
||||
"enableInspector": true,
|
||||
"borderless": false,
|
||||
"maximize": false,
|
||||
"hidden": false,
|
||||
"resizable": true,
|
||||
"exitProcessOnClose": true
|
||||
},
|
||||
"browser": {
|
||||
"globalVariables": {
|
||||
"TEST": "Test value browser"
|
||||
},
|
||||
"nativeBlockList": [
|
||||
"filesystem.*"
|
||||
]
|
||||
},
|
||||
"cloud": {
|
||||
"url": "/resources/#cloud",
|
||||
"nativeAllowList": [
|
||||
"app.*"
|
||||
]
|
||||
},
|
||||
"chrome": {
|
||||
"width": 800,
|
||||
"height": 500,
|
||||
"args": "--user-agent=\"Neutralinojs chrome mode\"",
|
||||
"nativeBlockList": [
|
||||
"filesystem.*",
|
||||
"os.*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"binaryName": "standalone-desktop",
|
||||
"resourcesPath": "/resources/",
|
||||
"extensionsPath": "/extensions/",
|
||||
"clientLibrary": "/resources/js/neutralino.js",
|
||||
"binaryVersion": "6.4.0",
|
||||
"clientVersion": "6.4.0"
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"name": "@triliumnext/standalone-desktop",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "tsx scripts/build.ts",
|
||||
"dev": "tsx scripts/dev.ts"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"packageManager": "pnpm@10.28.0",
|
||||
"devDependencies": {
|
||||
"@neutralinojs/neu": "11.6.0"
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import { execSync } from "child_process";
|
||||
import BuildHelper from "../../../scripts/build-utils";
|
||||
|
||||
const build = new BuildHelper("apps/standalone-desktop");
|
||||
|
||||
async function main() {
|
||||
build.triggerBuildAndCopyTo("apps/client-standalone", "../resources");
|
||||
build.copy("neutralino.template.config.json", "../neutralino.config.json");
|
||||
execSync("pnpm neu update", { cwd: build.projectDir, stdio: "inherit" });
|
||||
execSync("pnpm neu build", { cwd: build.projectDir, stdio: "inherit" });
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,18 +0,0 @@
|
||||
import { execSync } from "child_process";
|
||||
import { readFileSync, writeFileSync } from "fs";
|
||||
|
||||
function main() {
|
||||
patchTemplate();
|
||||
console.warn("Make sure to run the Vite dev server in a separate terminal:");
|
||||
console.warn(" cd apps/client-standalone");
|
||||
console.warn(" pnpm dev");
|
||||
execSync("pnpm neu run", { stdio: "inherit" });
|
||||
}
|
||||
|
||||
function patchTemplate() {
|
||||
const template = JSON.parse(readFileSync("neutralino.template.config.json", "utf-8"));
|
||||
template.url = "http://localhost:5173/";
|
||||
writeFileSync("neutralino.config.json", JSON.stringify(template, null, 2), "utf-8");
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,6 +1,7 @@
|
||||
import { getLog, initializeCore, sql_init } from "@triliumnext/core";
|
||||
import ClsHookedExecutionContext from "@triliumnext/server/src/cls_provider.js";
|
||||
import NodejsCryptoProvider from "@triliumnext/server/src/crypto_provider.js";
|
||||
import NodejsZipProvider from "@triliumnext/server/src/zip_provider.js";
|
||||
import dataDirs from "@triliumnext/server/src/services/data_dir.js";
|
||||
import options from "@triliumnext/server/src/services/options.js";
|
||||
import port from "@triliumnext/server/src/services/port.js";
|
||||
@@ -133,12 +134,14 @@ async function main() {
|
||||
}
|
||||
},
|
||||
crypto: new NodejsCryptoProvider(),
|
||||
zip: new NodejsZipProvider(),
|
||||
request: new NodeRequestProvider(),
|
||||
executionContext: new ClsHookedExecutionContext(),
|
||||
messaging: new WebSocketMessagingProvider(),
|
||||
schema: fs.readFileSync(require.resolve("@triliumnext/core/src/assets/schema.sql"), "utf-8"),
|
||||
platform: new DesktopPlatformProvider(),
|
||||
translations: (await import("@triliumnext/server/src/services/i18n.js")).initializeTranslations,
|
||||
getDemoArchive: async () => fs.readFileSync(require.resolve("@triliumnext/server/src/assets/db/demo.zip")),
|
||||
extraAppInfo: {
|
||||
nodeVersion: process.version,
|
||||
dataDirectory: path.resolve(dataDirs.TRILIUM_DATA_DIR)
|
||||
|
||||
@@ -62,7 +62,7 @@ export function startElectron(callback: () => void): DeferredPromise<void> {
|
||||
|
||||
export async function importData(path: string) {
|
||||
const buffer = await createImportZip(path);
|
||||
const importService = (await import("@triliumnext/server/src/services/import/zip.js")).default;
|
||||
const { zipImportService } = (await import("@triliumnext/core"));
|
||||
const context = new TaskContext("no-progress-reporting", "importNotes", null);
|
||||
const becca = (await import("@triliumnext/server/src/becca/becca.js")).default;
|
||||
|
||||
@@ -70,7 +70,7 @@ export async function importData(path: string) {
|
||||
if (!rootNote) {
|
||||
throw new Error("Missing root note for import.");
|
||||
}
|
||||
await importService.importZip(context, buffer, rootNote, {
|
||||
await zipImportService.importZip(context, buffer, rootNote, {
|
||||
preserveIds: true
|
||||
});
|
||||
}
|
||||
@@ -106,19 +106,18 @@ function waitForEnd(archive: Archiver, stream: WriteStream) {
|
||||
export async function extractZip(zipFilePath: string, outputPath: string, ignoredFiles?: Set<string>) {
|
||||
const promise = deferred<void>();
|
||||
setTimeout(async () => {
|
||||
// Then extract the zip.
|
||||
const { readZipFile, readContent } = (await import("@triliumnext/server/src/services/import/zip.js"));
|
||||
await readZipFile(await fs.readFile(zipFilePath), async (zip, entry) => {
|
||||
const { getZipProvider } = (await import("@triliumnext/core"));
|
||||
const zipProvider = getZipProvider();
|
||||
const buffer = await fs.readFile(zipFilePath);
|
||||
await zipProvider.readZipFile(buffer, async (entry, readContent) => {
|
||||
// We ignore directories since they can appear out of order anyway.
|
||||
if (!entry.fileName.endsWith("/") && !ignoredFiles?.has(entry.fileName)) {
|
||||
const destPath = path.join(outputPath, entry.fileName);
|
||||
const fileContent = await readContent(zip, entry);
|
||||
const fileContent = await readContent();
|
||||
|
||||
await fsExtra.mkdirs(path.dirname(destPath));
|
||||
await fs.writeFile(destPath, fileContent);
|
||||
}
|
||||
|
||||
zip.readEntry();
|
||||
});
|
||||
promise.resolve();
|
||||
}, 1000);
|
||||
|
||||
@@ -68,7 +68,6 @@
|
||||
"axios": "1.13.6",
|
||||
"bindings": "1.5.0",
|
||||
"bootstrap": "5.3.8",
|
||||
"chardet": "2.1.1",
|
||||
"cheerio": "1.2.0",
|
||||
"chokidar": "5.0.0",
|
||||
"cls-hooked": "4.2.2",
|
||||
@@ -108,8 +107,7 @@
|
||||
"safe-compare": "1.1.4",
|
||||
"sax": "1.6.0",
|
||||
"serve-favicon": "2.5.1",
|
||||
"stream-throttle": "0.1.3",
|
||||
"strip-bom": "5.0.0",
|
||||
"stream-throttle": "0.1.3",
|
||||
"striptags": "3.2.0",
|
||||
"supertest": "7.2.2",
|
||||
"swagger-jsdoc": "6.2.8",
|
||||
|
||||
@@ -4,6 +4,7 @@ import { join } from "path";
|
||||
import { initializeCore } from "@triliumnext/core";
|
||||
import ClsHookedExecutionContext from "../src/cls_provider.js";
|
||||
import NodejsCryptoProvider from "../src/crypto_provider.js";
|
||||
import NodejsZipProvider from "../src/zip_provider.js";
|
||||
import ServerPlatformProvider from "../src/platform_provider.js";
|
||||
import BetterSqlite3Provider from "../src/sql_provider.js";
|
||||
import { initializeTranslations } from "../src/services/i18n.js";
|
||||
@@ -27,6 +28,7 @@ beforeAll(async () => {
|
||||
onTransactionRollback() {}
|
||||
},
|
||||
crypto: new NodejsCryptoProvider(),
|
||||
zip: new NodejsZipProvider(),
|
||||
executionContext: new ClsHookedExecutionContext(),
|
||||
schema: readFileSync(require.resolve("@triliumnext/core/src/assets/schema.sql"), "utf-8"),
|
||||
platform: new ServerPlatformProvider(),
|
||||
|
||||
@@ -6,7 +6,7 @@ const randtoken = generator({ source: "crypto" });
|
||||
|
||||
export default class NodejsCryptoProvider implements CryptoProvider {
|
||||
|
||||
createHash(algorithm: "sha1", content: string | Uint8Array): Uint8Array {
|
||||
createHash(algorithm: "md5" | "sha1" | "sha512", content: string | Uint8Array): Uint8Array {
|
||||
return crypto.createHash(algorithm).update(content).digest();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { NoteParams, SearchParams } from "@triliumnext/core";
|
||||
import { NoteParams, SearchParams, zipImportService } from "@triliumnext/core";
|
||||
import type { Request, Router } from "express";
|
||||
import type { ParsedQs } from "qs";
|
||||
|
||||
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 noteService from "../services/notes.js";
|
||||
import SearchContext from "../services/search/search_context.js";
|
||||
import searchService from "../services/search/services/search.js";
|
||||
|
||||
@@ -10,6 +10,7 @@ import path from "path";
|
||||
|
||||
import ClsHookedExecutionContext from "./cls_provider.js";
|
||||
import NodejsCryptoProvider from "./crypto_provider.js";
|
||||
import NodejsZipProvider from "./zip_provider.js";
|
||||
import ServerPlatformProvider from "./platform_provider.js";
|
||||
import dataDirs from "./services/data_dir.js";
|
||||
import port from "./services/port.js";
|
||||
@@ -51,12 +52,14 @@ async function startApplication() {
|
||||
}
|
||||
},
|
||||
crypto: new NodejsCryptoProvider(),
|
||||
zip: new NodejsZipProvider(),
|
||||
request: new NodeRequestProvider(),
|
||||
executionContext: new ClsHookedExecutionContext(),
|
||||
messaging: new WebSocketMessagingProvider(),
|
||||
schema: fs.readFileSync(require.resolve("@triliumnext/core/src/assets/schema.sql"), "utf-8"),
|
||||
platform: new ServerPlatformProvider(),
|
||||
translations: (await import("./services/i18n.js")).initializeTranslations,
|
||||
getDemoArchive: async () => fs.readFileSync(require.resolve("@triliumnext/server/src/assets/db/demo.zip")),
|
||||
extraAppInfo: {
|
||||
nodeVersion: process.version,
|
||||
dataDirectory: path.resolve(dataDirs.TRILIUM_DATA_DIR)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { RenderMarkdownResponse, ToMarkdownResponse } from "@triliumnext/commons";
|
||||
import { markdownImportService } from "@triliumnext/core";
|
||||
import type { Request } from "express";
|
||||
|
||||
import markdownService from "../../services/import/markdown.js";
|
||||
import markdown from "../../services/export/markdown.js";
|
||||
import { RenderMarkdownResponse, ToMarkdownResponse } from "@triliumnext/commons";
|
||||
|
||||
function renderMarkdown(req: Request) {
|
||||
const { markdownContent } = req.body;
|
||||
@@ -10,7 +10,7 @@ function renderMarkdown(req: Request) {
|
||||
throw new Error('markdownContent parameter is required and must be a string');
|
||||
}
|
||||
return {
|
||||
htmlContent: markdownService.renderToHtml(markdownContent, "")
|
||||
htmlContent: markdownImportService.renderToHtml(markdownContent, "")
|
||||
} satisfies RenderMarkdownResponse;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ import etapiTokensApiRoutes from "./api/etapi_tokens.js";
|
||||
import exportRoute from "./api/export.js";
|
||||
import filesRoute from "./api/files.js";
|
||||
import fontsRoute from "./api/fonts.js";
|
||||
import importRoute from "./api/import.js";
|
||||
import loginApiRoute from "./api/login.js";
|
||||
import metricsRoute from "./api/metrics.js";
|
||||
import otherRoute from "./api/other.js";
|
||||
@@ -89,7 +88,9 @@ function register(app: express.Application) {
|
||||
checkApiAuthOrElectron: auth.checkApiAuthOrElectron,
|
||||
checkAppNotInitialized: auth.checkAppNotInitialized,
|
||||
checkCredentials: auth.checkCredentials,
|
||||
loginRateLimiter
|
||||
loginRateLimiter,
|
||||
uploadMiddlewareWithErrorHandling,
|
||||
csrfMiddleware
|
||||
});
|
||||
|
||||
route(PUT, "/api/notes/:noteId/file", [auth.checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware], filesRoute.updateFile, apiResultHandler);
|
||||
@@ -130,8 +131,6 @@ function register(app: express.Application) {
|
||||
// route(GET, "/api/revisions/:revisionId/download", [auth.checkApiAuthOrElectron], revisionsApiRoute.downloadRevision);
|
||||
|
||||
route(GET, "/api/branches/:branchId/export/:type/:format/:version/:taskId", [auth.checkApiAuthOrElectron], exportRoute.exportBranch);
|
||||
asyncRoute(PST, "/api/notes/:parentNoteId/notes-import", [auth.checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware], importRoute.importNotesToBranch, apiResultHandler);
|
||||
route(PST, "/api/notes/:parentNoteId/attachments-import", [auth.checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware], importRoute.importAttachmentsToNote, apiResultHandler);
|
||||
|
||||
// :filename is not used by trilium, but instead used for "save as" to assign a human-readable filename
|
||||
|
||||
|
||||
@@ -46,10 +46,6 @@ function putEntityChange(entityChange: EntityChange) {
|
||||
cls.putEntityChange(entityChange);
|
||||
}
|
||||
|
||||
function ignoreEntityChangeIds() {
|
||||
cls.getContext().set("ignoreEntityChangeIds", true);
|
||||
}
|
||||
|
||||
function get(key: string) {
|
||||
return cls.getContext().get(key);
|
||||
}
|
||||
@@ -62,7 +58,10 @@ function reset() {
|
||||
cls.getContext().reset();
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
export const wrap = cls.wrap;
|
||||
/** @deprecated */
|
||||
export const ignoreEntityChangeIds = cls.ignoreEntityChangeIds;
|
||||
|
||||
export default {
|
||||
init,
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { getCrypto,utils as coreUtils } from "@triliumnext/core";
|
||||
import chardet from "chardet";
|
||||
import { binary_utils,getCrypto, utils as coreUtils } from "@triliumnext/core";
|
||||
import crypto from "crypto";
|
||||
import { release as osRelease } from "os";
|
||||
import path from "path";
|
||||
import stripBom from "strip-bom";
|
||||
|
||||
const osVersion = osRelease().split('.').map(Number);
|
||||
|
||||
@@ -27,10 +25,6 @@ export function randomString(length: number): string {
|
||||
return coreUtils.randomString(length);
|
||||
}
|
||||
|
||||
export function md5(content: crypto.BinaryLike) {
|
||||
return crypto.createHash("md5").update(content).digest("hex");
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
export function hashedBlobId(content: string | Buffer) {
|
||||
return coreUtils.hashedBlobId(content);
|
||||
@@ -138,35 +132,6 @@ export function getResourceDir() {
|
||||
return path.join(__dirname, "..");
|
||||
}
|
||||
|
||||
/**
|
||||
* For buffers, they are scanned for a supported encoding and decoded (UTF-8, UTF-16). In some cases, the BOM is also stripped.
|
||||
*
|
||||
* For strings, they are returned immediately without any transformation.
|
||||
*
|
||||
* For nullish values, an empty string is returned.
|
||||
*
|
||||
* @param data the string or buffer to process.
|
||||
* @returns the string representation of the buffer, or the same string is it's a string.
|
||||
*/
|
||||
export function processStringOrBuffer(data: string | Buffer | null) {
|
||||
if (!data) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!Buffer.isBuffer(data)) {
|
||||
return data;
|
||||
}
|
||||
|
||||
const detectedEncoding = chardet.detect(data);
|
||||
switch (detectedEncoding) {
|
||||
case "UTF-16LE":
|
||||
return stripBom(data.toString("utf-16le"));
|
||||
case "UTF-8":
|
||||
default:
|
||||
return data.toString("utf-8");
|
||||
}
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
export const escapeHtml = coreUtils.escapeHtml;
|
||||
/** @deprecated */
|
||||
@@ -183,6 +148,7 @@ export const isEmptyOrWhitespace = coreUtils.isEmptyOrWhitespace;
|
||||
export const normalizeUrl = coreUtils.normalizeUrl;
|
||||
export const timeLimit = coreUtils.timeLimit;
|
||||
export const sanitizeSqlIdentifier = coreUtils.sanitizeSqlIdentifier;
|
||||
export const processStringOrBuffer = binary_utils.processStringOrBuffer;
|
||||
|
||||
export function waitForStreamToFinish(stream: any): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -207,7 +173,6 @@ export default {
|
||||
isMac,
|
||||
isStringNote,
|
||||
isWindows,
|
||||
md5,
|
||||
newEntityId,
|
||||
normalize,
|
||||
quoteRegex,
|
||||
|
||||
46
apps/server/src/zip_provider.ts
Normal file
46
apps/server/src/zip_provider.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import type { ZipEntry, ZipProvider } from "@triliumnext/core/src/services/import/zip_provider.js";
|
||||
import type { Stream } from "stream";
|
||||
import yauzl from "yauzl";
|
||||
|
||||
function streamToBuffer(stream: Stream): Promise<Buffer> {
|
||||
const chunks: Uint8Array[] = [];
|
||||
stream.on("data", (chunk: Uint8Array) => chunks.push(chunk));
|
||||
return new Promise((res, rej) => {
|
||||
stream.on("end", () => res(Buffer.concat(chunks)));
|
||||
stream.on("error", rej);
|
||||
});
|
||||
}
|
||||
|
||||
export default class NodejsZipProvider implements ZipProvider {
|
||||
readZipFile(
|
||||
buffer: Uint8Array,
|
||||
processEntry: (entry: ZipEntry, readContent: () => Promise<Uint8Array>) => Promise<void>
|
||||
): Promise<void> {
|
||||
return new Promise<void>((res, rej) => {
|
||||
yauzl.fromBuffer(Buffer.from(buffer), { lazyEntries: true, validateEntrySizes: false }, (err, zipfile) => {
|
||||
if (err) { rej(err); return; }
|
||||
if (!zipfile) { rej(new Error("Unable to read zip file.")); return; }
|
||||
|
||||
zipfile.readEntry();
|
||||
zipfile.on("entry", async (entry: yauzl.Entry) => {
|
||||
try {
|
||||
const readContent = () => new Promise<Uint8Array>((res, rej) => {
|
||||
zipfile.openReadStream(entry, (err, readStream) => {
|
||||
if (err) { rej(err); return; }
|
||||
if (!readStream) { rej(new Error("Unable to read content.")); return; }
|
||||
streamToBuffer(readStream).then(res, rej);
|
||||
});
|
||||
});
|
||||
|
||||
await processEntry({ fileName: entry.fileName }, readContent);
|
||||
} catch (e) {
|
||||
rej(e);
|
||||
}
|
||||
zipfile.readEntry();
|
||||
});
|
||||
zipfile.on("end", res);
|
||||
zipfile.on("error", rej);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -10,12 +10,14 @@
|
||||
"@braintree/sanitize-url": "7.1.1",
|
||||
"@triliumnext/commons": "workspace:*",
|
||||
"async-mutex": "0.5.0",
|
||||
"chardet": "2.1.1",
|
||||
"escape-html": "1.0.3",
|
||||
"i18next": "25.10.10",
|
||||
"mime-types": "3.0.2",
|
||||
"node-html-parser": "7.1.0",
|
||||
"sanitize-filename": "1.6.4",
|
||||
"sanitize-html": "2.17.2",
|
||||
"strip-bom": "5.0.0",
|
||||
"unescape": "1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -6,9 +6,11 @@ import { SqlService, SqlServiceParams } from "./services/sql/sql";
|
||||
import { initMessaging, MessagingProvider } from "./services/messaging/index";
|
||||
import { initRequest, RequestProvider } from "./services/request";
|
||||
import { initTranslations, TranslationProvider } from "./services/i18n";
|
||||
import { initSchema } from "./services/sql_init";
|
||||
import { initSchema, initDemoArchive } from "./services/sql_init";
|
||||
import appInfo from "./services/app_info";
|
||||
import { type PlatformProvider, initPlatform } from "./services/platform";
|
||||
import { type ZipProvider, initZipProvider } from "./services/import/zip_provider";
|
||||
import markdown from "./services/import/markdown";
|
||||
|
||||
export { getLog } from "./services/log";
|
||||
export type * from "./services/sql/types";
|
||||
@@ -99,18 +101,25 @@ export type { RequestProvider, ExecOpts, CookieJar } from "./services/request";
|
||||
export type * from "./meta";
|
||||
export * as routeHelpers from "./routes/helpers";
|
||||
|
||||
export { getZipProvider, type ZipProvider } from "./services/import/zip_provider";
|
||||
export { default as zipImportService } from "./services/import/zip";
|
||||
|
||||
export * as becca_easy_mocking from "./test/becca_easy_mocking";
|
||||
export * as becca_mocking from "./test/becca_mocking";
|
||||
|
||||
export async function initializeCore({ dbConfig, executionContext, crypto, translations, messaging, request, schema, extraAppInfo, platform }: {
|
||||
export { default as markdownImportService } from "./services/import/markdown";
|
||||
|
||||
export async function initializeCore({ dbConfig, executionContext, crypto, zip, translations, messaging, request, schema, extraAppInfo, platform, getDemoArchive }: {
|
||||
dbConfig: SqlServiceParams,
|
||||
executionContext: ExecutionContext,
|
||||
crypto: CryptoProvider,
|
||||
zip: ZipProvider,
|
||||
translations: TranslationProvider,
|
||||
platform: PlatformProvider,
|
||||
schema: string,
|
||||
messaging?: MessagingProvider,
|
||||
request?: RequestProvider,
|
||||
getDemoArchive?: () => Promise<Uint8Array | null>,
|
||||
extraAppInfo?: {
|
||||
nodeVersion: string;
|
||||
dataDirectory: string;
|
||||
@@ -120,9 +129,13 @@ export async function initializeCore({ dbConfig, executionContext, crypto, trans
|
||||
initLog();
|
||||
await initTranslations(translations);
|
||||
initCrypto(crypto);
|
||||
initZipProvider(zip);
|
||||
initContext(executionContext);
|
||||
initSql(new SqlService(dbConfig, getLog()));
|
||||
initSchema(schema);
|
||||
if (getDemoArchive) {
|
||||
initDemoArchive(getDemoArchive);
|
||||
}
|
||||
Object.assign(appInfo, extraAppInfo);
|
||||
if (messaging) {
|
||||
initMessaging(messaging);
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
import { becca_loader, ValidationError } from "@triliumnext/core";
|
||||
import type { Request } from "express";
|
||||
import path from "path";
|
||||
import type { File } from "../../services/import/common.js";
|
||||
|
||||
type ImportRequest<P> = Omit<Request<P>, "file"> & { file?: File };
|
||||
|
||||
import becca from "../../becca/becca.js";
|
||||
import type BNote from "../../becca/entities/bnote.js";
|
||||
import cls from "../../services/cls.js";
|
||||
import enexImportService from "../../services/import/enex.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 { getLog } from "../../services/log.js";
|
||||
import TaskContext from "../../services/task_context.js";
|
||||
import { safeExtractMessageAndStackFromError } from "../../services/utils.js";
|
||||
import { safeExtractMessageAndStackFromError } from "../../services/utils/index.js";
|
||||
import * as cls from "../../services/context.js";
|
||||
import { ValidationError } from "../../errors.js";
|
||||
import becca_loader from "../../becca/becca_loader.js";
|
||||
import { extname } from "../../services/utils/path.js";
|
||||
|
||||
async function importNotesToBranch(req: Request<{ parentNoteId: string }>) {
|
||||
async function importNotesToBranch(req: ImportRequest<{ parentNoteId: string }>) {
|
||||
const { parentNoteId } = req.params;
|
||||
const { taskId, last } = req.body;
|
||||
|
||||
@@ -34,7 +38,7 @@ async function importNotesToBranch(req: Request<{ parentNoteId: string }>) {
|
||||
|
||||
const parentNote = becca.getNoteOrThrow(parentNoteId);
|
||||
|
||||
const extension = path.extname(file.originalname).toLowerCase();
|
||||
const extension = extname(file.originalname).toLowerCase();
|
||||
|
||||
// running all the event handlers on imported notes (and attributes) is slow
|
||||
// and may produce unintended consequences
|
||||
@@ -58,21 +62,22 @@ async function importNotesToBranch(req: Request<{ parentNoteId: string }>) {
|
||||
return importResult;
|
||||
}
|
||||
} else if (extension === ".enex" && options.explodeArchives) {
|
||||
const importResult = await enexImportService.importEnex(taskContext, file, parentNote);
|
||||
if (!Array.isArray(importResult)) {
|
||||
note = importResult;
|
||||
} else {
|
||||
return importResult;
|
||||
}
|
||||
throw "ENEX import is currently not supported. Please use the desktop app to import ENEX files and then sync with the server.";
|
||||
// const importResult = await enexImportService.importEnex(taskContext, file, parentNote);
|
||||
// if (!Array.isArray(importResult)) {
|
||||
// note = importResult;
|
||||
// } else {
|
||||
// return importResult;
|
||||
// }
|
||||
} else {
|
||||
note = await singleImportService.importSingleFile(taskContext, file, parentNote);
|
||||
note = singleImportService.importSingleFile(taskContext, file, parentNote);
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
const [errMessage, errStack] = safeExtractMessageAndStackFromError(e);
|
||||
const message = `Import failed with following error: '${errMessage}'. More details might be in the logs.`;
|
||||
taskContext.reportError(message);
|
||||
|
||||
log.error(message + errStack);
|
||||
getLog().error(message + errStack);
|
||||
|
||||
return [500, message];
|
||||
}
|
||||
@@ -99,7 +104,7 @@ async function importNotesToBranch(req: Request<{ parentNoteId: string }>) {
|
||||
return note.getPojo();
|
||||
}
|
||||
|
||||
function importAttachmentsToNote(req: Request<{ parentNoteId: string }>) {
|
||||
function importAttachmentsToNote(req: ImportRequest<{ parentNoteId: string }>) {
|
||||
const { parentNoteId } = req.params;
|
||||
const { taskId, last } = req.body;
|
||||
|
||||
@@ -126,7 +131,7 @@ function importAttachmentsToNote(req: Request<{ parentNoteId: string }>) {
|
||||
const message = `Import failed with following error: '${errMessage}'. More details might be in the logs.`;
|
||||
taskContext.reportError(message);
|
||||
|
||||
log.error(message + errStack);
|
||||
getLog().error(message + errStack);
|
||||
|
||||
return [500, message];
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import { EditedNotesResponse, RevisionItem, RevisionPojo } from "@triliumnext/commons";
|
||||
import type { Request, Response } from "express";
|
||||
import path from "path";
|
||||
|
||||
import becca from "../../becca/becca.js";
|
||||
import type BNote from "../../becca/entities/bnote.js";
|
||||
@@ -10,6 +9,7 @@ import eraseService from "../../services/erase.js";
|
||||
import { NotePojo } from "../../becca/becca-interface.js";
|
||||
import { becca_service, binary_utils, cls, getSql } from "../../index.js";
|
||||
import { formatDownloadTitle, getContentDisposition } from "../../services/utils/index.js";
|
||||
import { extname } from "../../services/utils/path.js";
|
||||
|
||||
interface NotePath {
|
||||
noteId: string;
|
||||
@@ -67,7 +67,7 @@ function getRevisionFilename(revision: BRevision) {
|
||||
throw new Error("Missing creation date for revision.");
|
||||
}
|
||||
|
||||
const extension = path.extname(filename);
|
||||
const extension = extname(filename);
|
||||
const date = revision.dateCreated
|
||||
.substr(0, 19)
|
||||
.replace(" ", "_")
|
||||
|
||||
@@ -15,7 +15,7 @@ function getStatus() {
|
||||
|
||||
async function setupNewDocument(req: Request) {
|
||||
const { skipDemoDb } = req.query;
|
||||
await sqlInit.createInitialDatabase(!!skipDemoDb);
|
||||
await sqlInit.createInitialDatabase(skipDemoDb !== undefined);
|
||||
}
|
||||
|
||||
function setupSyncFromServer(req: Request): Promise<SetupSyncFromServerResponse> {
|
||||
|
||||
@@ -25,6 +25,7 @@ import similarNotesRoute from "./api/similar_notes";
|
||||
import imageRoute from "./api/image";
|
||||
import setupApiRoute from "./api/setup";
|
||||
import filesRoute from "./api/files";
|
||||
import importRoute from "./api/import";
|
||||
|
||||
// TODO: Deduplicate with routes.ts
|
||||
const GET = "get",
|
||||
@@ -44,9 +45,11 @@ interface SharedApiRoutesContext {
|
||||
checkAppNotInitialized: any;
|
||||
loginRateLimiter: any;
|
||||
checkCredentials: any;
|
||||
uploadMiddlewareWithErrorHandling: any;
|
||||
csrfMiddleware: any;
|
||||
}
|
||||
|
||||
export function buildSharedApiRoutes({ route, asyncRoute, apiRoute, asyncApiRoute, checkApiAuth, apiResultHandler, checkApiAuthOrElectron, checkAppNotInitialized, checkCredentials, loginRateLimiter }: SharedApiRoutesContext) {
|
||||
export function buildSharedApiRoutes({ route, asyncRoute, apiRoute, asyncApiRoute, checkApiAuth, apiResultHandler, checkApiAuthOrElectron, checkAppNotInitialized, checkCredentials, loginRateLimiter, uploadMiddlewareWithErrorHandling, csrfMiddleware }: SharedApiRoutesContext) {
|
||||
apiRoute(GET, '/api/tree', treeApiRoute.getTree);
|
||||
apiRoute(PST, '/api/tree/load', treeApiRoute.load);
|
||||
|
||||
@@ -136,6 +139,9 @@ export function buildSharedApiRoutes({ route, asyncRoute, apiRoute, asyncApiRout
|
||||
route(PST, "/api/sync/queue-sector/:entityName/:sector", [checkApiAuth], syncApiRoute.queueSector, apiResultHandler);
|
||||
route(GET, "/api/sync/stats", [], syncApiRoute.getStats, apiResultHandler);
|
||||
|
||||
asyncRoute(PST, "/api/notes/:parentNoteId/notes-import", [checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware], importRoute.importNotesToBranch, apiResultHandler);
|
||||
route(PST, "/api/notes/:parentNoteId/attachments-import", [checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware], importRoute.importAttachmentsToNote, apiResultHandler);
|
||||
|
||||
apiRoute(GET, "/api/quick-search/:searchString", searchRoute.quickSearch);
|
||||
apiRoute(GET, "/api/search-note/:noteId", searchRoute.searchFromNote);
|
||||
apiRoute(PST, "/api/search-and-execute-note/:noteId", searchRoute.searchAndExecute);
|
||||
|
||||
@@ -77,3 +77,7 @@ export function getAndClearEntityChangeIds() {
|
||||
|
||||
return entityChangeIds;
|
||||
}
|
||||
|
||||
export function ignoreEntityChangeIds() {
|
||||
getContext().set("ignoreEntityChangeIds", true);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ interface Cipher {
|
||||
|
||||
export interface CryptoProvider {
|
||||
|
||||
createHash(algorithm: "sha1" | "sha512", content: string | Uint8Array): Uint8Array;
|
||||
createHash(algorithm: "md5" | "sha1" | "sha512", content: string | Uint8Array): Uint8Array;
|
||||
randomBytes(size: number): Uint8Array;
|
||||
randomString(length: number): string;
|
||||
createCipheriv(algorithm: "aes-128-cbc", key: Uint8Array, iv: Uint8Array): Cipher;
|
||||
|
||||
10
packages/trilium-core/src/services/export/markdown.ts
Normal file
10
packages/trilium-core/src/services/export/markdown.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
// TODO: Move this to a dedicated file someday.
|
||||
export const ADMONITION_TYPE_MAPPINGS: Record<string, string> = {
|
||||
note: "NOTE",
|
||||
tip: "TIP",
|
||||
important: "IMPORTANT",
|
||||
caution: "CAUTION",
|
||||
warning: "WARNING"
|
||||
};
|
||||
|
||||
export const DEFAULT_ADMONITION_TYPE = ADMONITION_TYPE_MAPPINGS.note;
|
||||
@@ -1,5 +1,5 @@
|
||||
export default {
|
||||
saveImageToAttachment(noteId: string, imageBuffer: Uint8Array, title: string, b1: boolean, b2: boolean) {
|
||||
saveImageToAttachment(noteId: string, imageBuffer: Uint8Array, title: string, b1?: boolean, b2?: boolean) {
|
||||
console.warn("Image save ignored", noteId, title);
|
||||
|
||||
return {
|
||||
@@ -10,5 +10,13 @@ export default {
|
||||
|
||||
updateImage(noteId: string, imageBuffer: Uint8Array, title: string) {
|
||||
console.warn("Image update ignored", noteId, title);
|
||||
},
|
||||
|
||||
saveImage(noteId: string, imageBuffer: Uint8Array, title: string, b1?: boolean, b2?: boolean) {
|
||||
console.warn("Image save ignored", noteId, title);
|
||||
|
||||
return {
|
||||
note: null
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export interface File {
|
||||
originalname: string;
|
||||
mimetype: string;
|
||||
buffer: string | Buffer;
|
||||
buffer: string | Buffer | Uint8Array;
|
||||
}
|
||||
@@ -1,20 +1,22 @@
|
||||
import type { AttributeType } from "@triliumnext/commons";
|
||||
import { dayjs } from "@triliumnext/commons";
|
||||
import { sanitize, utils } from "@triliumnext/core";
|
||||
import sax from "sax";
|
||||
import stream from "stream";
|
||||
import { Throttle } from "stream-throttle";
|
||||
|
||||
import type BNote from "../../becca/entities/bnote.js";
|
||||
import date_utils from "../date_utils.js";
|
||||
import date_utils from "../utils/date.js";
|
||||
import * as utils from "../utils/index.js";
|
||||
import imageService from "../image.js";
|
||||
import log from "../log.js";
|
||||
import { getLog } from "../log.js";
|
||||
import noteService from "../notes.js";
|
||||
import protectedSessionService from "../protected_session.js";
|
||||
import sql from "../sql.js";
|
||||
import type TaskContext from "../task_context.js";
|
||||
import { escapeHtml, fromBase64,md5 } from "../utils.js";
|
||||
import { escapeHtml, md5 } from "../utils/index.js";
|
||||
import { decodeBase64 } from "../utils/binary.js";
|
||||
import type { File } from "./common.js";
|
||||
import { sanitizeHtml } from "../sanitizer.js";
|
||||
import { getSql } from "../sql/index.js";
|
||||
|
||||
/**
|
||||
* date format is e.g. 20181121T193703Z or 2013-04-14T16:19:00.000Z (Mac evernote, see #3496)
|
||||
@@ -38,7 +40,7 @@ interface Attribute {
|
||||
|
||||
interface Resource {
|
||||
title: string;
|
||||
content?: Buffer | string;
|
||||
content?: Uint8Array | string;
|
||||
mime?: string;
|
||||
attributes: Attribute[];
|
||||
}
|
||||
@@ -117,7 +119,7 @@ function importEnex(taskContext: TaskContext<"importNotes">, file: File, parentN
|
||||
"\u2611 "
|
||||
);
|
||||
|
||||
content = sanitize.sanitizeHtml(content);
|
||||
content = sanitizeHtml(content);
|
||||
|
||||
return content;
|
||||
}
|
||||
@@ -138,7 +140,7 @@ function importEnex(taskContext: TaskContext<"importNotes">, file: File, parentN
|
||||
|
||||
saxStream.on("error", (e) => {
|
||||
// unhandled errors will throw, since this is a proper node event emitter.
|
||||
log.error(`error when parsing ENEX file: ${e}`);
|
||||
getLog().error(`error when parsing ENEX file: ${e}`);
|
||||
// clear the error
|
||||
(saxStream._parser as any).error = null;
|
||||
saxStream._parser.resume();
|
||||
@@ -235,6 +237,8 @@ function importEnex(taskContext: TaskContext<"importNotes">, file: File, parentN
|
||||
}
|
||||
});
|
||||
|
||||
const sql = getSql();
|
||||
|
||||
function updateDates(note: BNote, utcDateCreated?: string, utcDateModified?: string) {
|
||||
// it's difficult to force custom dateCreated and dateModified to Note entity, so we do it post-creation with SQL
|
||||
const dateCreated = formatDateTimeToLocalDbFormat(utcDateCreated, false);
|
||||
@@ -295,7 +299,7 @@ function importEnex(taskContext: TaskContext<"importNotes">, file: File, parentN
|
||||
}
|
||||
|
||||
if (typeof resource.content === "string") {
|
||||
resource.content = fromBase64(resource.content);
|
||||
resource.content = decodeBase64(resource.content);
|
||||
}
|
||||
|
||||
const hash = md5(resource.content);
|
||||
@@ -359,7 +363,7 @@ function importEnex(taskContext: TaskContext<"importNotes">, file: File, parentN
|
||||
content += imageLink;
|
||||
}
|
||||
} catch (e: any) {
|
||||
log.error(`error when saving image from ENEX file: ${e.message}`);
|
||||
getLog().error(`error when saving image from ENEX file: ${e.message}`);
|
||||
createFileNote();
|
||||
}
|
||||
} else {
|
||||
@@ -367,7 +371,7 @@ function importEnex(taskContext: TaskContext<"importNotes">, file: File, parentN
|
||||
}
|
||||
}
|
||||
|
||||
content = sanitize.sanitizeHtml(content);
|
||||
content = sanitizeHtml(content);
|
||||
|
||||
// save updated content with links to files/images
|
||||
noteEntity.setContent(content);
|
||||
@@ -1,17 +1,15 @@
|
||||
|
||||
|
||||
import { getMimeTypeFromMarkdownName, MIME_TYPE_AUTO } from "@triliumnext/commons";
|
||||
import { normalizeMimeTypeForCKEditor } from "@triliumnext/commons";
|
||||
import { sanitize } from "@triliumnext/core";
|
||||
import { parse, Renderer, type Tokens,use } from "marked";
|
||||
|
||||
import { ADMONITION_TYPE_MAPPINGS } from "../export/markdown.js";
|
||||
import utils from "../utils.js";
|
||||
import wikiLinkInternalLink from "./markdown/wikilink_internal_link.js";
|
||||
import wikiLinkTransclusion from "./markdown/wikilink_transclusion.js";
|
||||
import importUtils from "./utils.js";
|
||||
import { escapeHtml } from "../utils/index.js";
|
||||
import { sanitizeHtml } from "../sanitizer.js";
|
||||
|
||||
const escape = utils.escapeHtml;
|
||||
const escape = escapeHtml;
|
||||
|
||||
/**
|
||||
* Keep renderer code up to date with https://github.com/markedjs/marked/blob/master/src/Renderer.ts.
|
||||
@@ -151,7 +149,7 @@ function renderToHtml(content: string, title: string) {
|
||||
|
||||
// h1 handling needs to come before sanitization
|
||||
html = importUtils.handleH1(html, title);
|
||||
html = sanitize.sanitizeHtml(html);
|
||||
html = sanitizeHtml(html);
|
||||
|
||||
// Add a trailing semicolon to CSS styles.
|
||||
html = html.replaceAll(/(<(img|figure|col).*?style=".*?)"/g, "$1;\"");
|
||||
@@ -1,8 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
import mimeTypes from "mime-types";
|
||||
import path from "path";
|
||||
import { types as extToMime } from "mime-types";
|
||||
import type { NoteType, TaskData } from "@triliumnext/commons";
|
||||
import { extname } from "../utils/path";
|
||||
|
||||
const CODE_MIME_TYPES = new Set([
|
||||
"application/json",
|
||||
@@ -84,10 +84,10 @@ function getMime(fileName: string) {
|
||||
return "text/x-dockerfile";
|
||||
}
|
||||
|
||||
const ext = path.extname(fileNameLc);
|
||||
const ext = extname(fileNameLc);
|
||||
const mimeFromExt = EXTENSION_TO_MIME.get(ext);
|
||||
|
||||
return mimeFromExt || mimeTypes.lookup(fileNameLc);
|
||||
return mimeFromExt || extToMime[ext.slice(1)] || false;
|
||||
}
|
||||
|
||||
function getType(options: TaskData<"importNotes">, mime: string): NoteType {
|
||||
@@ -1,12 +1,10 @@
|
||||
|
||||
|
||||
import { sanitize } from "@triliumnext/core";
|
||||
import xml2js from "xml2js";
|
||||
|
||||
import type BNote from "../../becca/entities/bnote.js";
|
||||
import noteService from "../../services/notes.js";
|
||||
import protectedSessionService from "../protected_session.js";
|
||||
import type TaskContext from "../task_context.js";
|
||||
import { sanitizeHtml } from "../sanitizer.js";
|
||||
const parseString = xml2js.parseString;
|
||||
|
||||
interface OpmlXml {
|
||||
@@ -29,7 +27,7 @@ interface OpmlOutline {
|
||||
outline: OpmlOutline[];
|
||||
}
|
||||
|
||||
async function importOpml(taskContext: TaskContext<"importNotes">, fileBuffer: string | Buffer, parentNote: BNote) {
|
||||
async function importOpml(taskContext: TaskContext<"importNotes">, fileBuffer: string | Uint8Array, parentNote: BNote) {
|
||||
const xml = await new Promise<OpmlXml>((resolve, reject) => {
|
||||
parseString(fileBuffer, (err: any, result: OpmlXml) => {
|
||||
if (err) {
|
||||
@@ -65,7 +63,7 @@ async function importOpml(taskContext: TaskContext<"importNotes">, fileBuffer: s
|
||||
throw new Error(`Unrecognized OPML version ${opmlVersion}`);
|
||||
}
|
||||
|
||||
content = sanitize.sanitizeHtml(content || "");
|
||||
content = sanitizeHtml(content || "");
|
||||
|
||||
const { note } = noteService.createNewNote({
|
||||
parentNoteId,
|
||||
@@ -6,10 +6,10 @@ import { dirname } from "path";
|
||||
import becca from "../../becca/becca.js";
|
||||
import BNote from "../../becca/entities/bnote.js";
|
||||
import TaskContext from "../task_context.js";
|
||||
import cls from "../cls.js";
|
||||
import sql_init from "../sql_init.js";
|
||||
import single from "./single.js";
|
||||
import stripBom from "strip-bom";
|
||||
import { getContext } from "../context.js";
|
||||
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
async function testImport(fileName: string, mimetype: string) {
|
||||
@@ -20,7 +20,7 @@ async function testImport(fileName: string, mimetype: string) {
|
||||
});
|
||||
|
||||
return new Promise<{ buffer: Buffer; importedNote: BNote }>((resolve, reject) => {
|
||||
cls.init(async () => {
|
||||
getContext().init(async () => {
|
||||
const rootNote = becca.getNote("root");
|
||||
if (!rootNote) {
|
||||
reject("Missing root note.");
|
||||
@@ -36,6 +36,10 @@ async function testImport(fileName: string, mimetype: string) {
|
||||
},
|
||||
rootNote as BNote
|
||||
);
|
||||
if (importedNote === null) {
|
||||
reject("Import failed.");
|
||||
return;
|
||||
}
|
||||
resolve({
|
||||
buffer,
|
||||
importedNote
|
||||
@@ -1,16 +1,17 @@
|
||||
import type { NoteType } from "@triliumnext/commons";
|
||||
import { sanitize, utils } from "@triliumnext/core";
|
||||
|
||||
import type BNote from "../../becca/entities/bnote.js";
|
||||
import imageService from "../../services/image.js";
|
||||
import noteService from "../../services/notes.js";
|
||||
import { processStringOrBuffer } from "../../services/utils.js";
|
||||
import protectedSessionService from "../protected_session.js";
|
||||
import type TaskContext from "../task_context.js";
|
||||
import type { File } from "./common.js";
|
||||
import markdownService from "./markdown.js";
|
||||
import mimeService from "./mime.js";
|
||||
import importUtils from "./utils.js";
|
||||
import { getNoteTitle } from "../utils/index.js";
|
||||
import { sanitizeHtml } from "../sanitizer.js";
|
||||
import { processStringOrBuffer } from "../utils/binary.js";
|
||||
|
||||
function importSingleFile(taskContext: TaskContext<"importNotes">, file: File, parentNote: BNote) {
|
||||
const mime = mimeService.getMime(file.originalname) || file.mimetype;
|
||||
@@ -57,7 +58,7 @@ function importFile(taskContext: TaskContext<"importNotes">, file: File, parentN
|
||||
const mime = mimeService.getMime(originalName) || file.mimetype;
|
||||
const { note } = noteService.createNewNote({
|
||||
parentNoteId: parentNote.noteId,
|
||||
title: utils.getNoteTitle(originalName, mime === "application/pdf", { mime }),
|
||||
title: getNoteTitle(originalName, mime === "application/pdf", { mime }),
|
||||
content: file.buffer,
|
||||
isProtected: parentNote.isProtected && protectedSessionService.isProtectedSessionAvailable(),
|
||||
type: "file",
|
||||
@@ -72,7 +73,7 @@ function importFile(taskContext: TaskContext<"importNotes">, file: File, parentN
|
||||
}
|
||||
|
||||
function importCodeNote(taskContext: TaskContext<"importNotes">, file: File, parentNote: BNote) {
|
||||
const title = utils.getNoteTitle(file.originalname, !!taskContext.data?.replaceUnderscoresWithSpaces);
|
||||
const title = getNoteTitle(file.originalname, !!taskContext.data?.replaceUnderscoresWithSpaces);
|
||||
const content = processStringOrBuffer(file.buffer);
|
||||
const detectedMime = mimeService.getMime(file.originalname) || file.mimetype;
|
||||
const mime = mimeService.normalizeMimeType(detectedMime);
|
||||
@@ -97,7 +98,7 @@ function importCodeNote(taskContext: TaskContext<"importNotes">, file: File, par
|
||||
}
|
||||
|
||||
function importCustomType(taskContext: TaskContext<"importNotes">, file: File, parentNote: BNote, type: NoteType, mime: string) {
|
||||
const title = utils.getNoteTitle(file.originalname, !!taskContext.data?.replaceUnderscoresWithSpaces);
|
||||
const title = getNoteTitle(file.originalname, !!taskContext.data?.replaceUnderscoresWithSpaces);
|
||||
const content = processStringOrBuffer(file.buffer);
|
||||
|
||||
const { note } = noteService.createNewNote({
|
||||
@@ -115,7 +116,7 @@ function importCustomType(taskContext: TaskContext<"importNotes">, file: File, p
|
||||
}
|
||||
|
||||
function importPlainText(taskContext: TaskContext<"importNotes">, file: File, parentNote: BNote) {
|
||||
const title = utils.getNoteTitle(file.originalname, !!taskContext.data?.replaceUnderscoresWithSpaces);
|
||||
const title = getNoteTitle(file.originalname, !!taskContext.data?.replaceUnderscoresWithSpaces);
|
||||
const plainTextContent = processStringOrBuffer(file.buffer);
|
||||
const htmlContent = convertTextToHtml(plainTextContent);
|
||||
|
||||
@@ -150,13 +151,13 @@ function convertTextToHtml(text: string) {
|
||||
}
|
||||
|
||||
function importMarkdown(taskContext: TaskContext<"importNotes">, file: File, parentNote: BNote) {
|
||||
const title = utils.getNoteTitle(file.originalname, !!taskContext.data?.replaceUnderscoresWithSpaces);
|
||||
const title = getNoteTitle(file.originalname, !!taskContext.data?.replaceUnderscoresWithSpaces);
|
||||
|
||||
const markdownContent = processStringOrBuffer(file.buffer);
|
||||
let htmlContent = markdownService.renderToHtml(markdownContent, title);
|
||||
|
||||
if (taskContext.data?.safeImport) {
|
||||
htmlContent = sanitize.sanitizeHtml(htmlContent);
|
||||
htmlContent = sanitizeHtml(htmlContent);
|
||||
}
|
||||
|
||||
const { note } = noteService.createNewNote({
|
||||
@@ -179,12 +180,12 @@ function importHtml(taskContext: TaskContext<"importNotes">, file: File, parentN
|
||||
// Try to get title from HTML first, fall back to filename
|
||||
// We do this before sanitization since that turns all <h1>s into <h2>
|
||||
const htmlTitle = importUtils.extractHtmlTitle(content);
|
||||
const title = htmlTitle || utils.getNoteTitle(file.originalname, !!taskContext.data?.replaceUnderscoresWithSpaces);
|
||||
const title = htmlTitle || getNoteTitle(file.originalname, !!taskContext.data?.replaceUnderscoresWithSpaces);
|
||||
|
||||
content = importUtils.handleH1(content, title);
|
||||
|
||||
if (taskContext?.data?.safeImport) {
|
||||
content = sanitize.sanitizeHtml(content);
|
||||
content = sanitizeHtml(content);
|
||||
}
|
||||
|
||||
const { note } = noteService.createNewNote({
|
||||
@@ -1,6 +1,4 @@
|
||||
"use strict";
|
||||
|
||||
import { unescapeHtml } from "../utils.js";
|
||||
import { unescapeHtml } from "../utils";
|
||||
|
||||
function handleH1(content: string, title: string) {
|
||||
let isFirstH1Handled = false;
|
||||
@@ -7,9 +7,9 @@ import zip, { removeTriliumTags } from "./zip.js";
|
||||
import becca from "../../becca/becca.js";
|
||||
import BNote from "../../becca/entities/bnote.js";
|
||||
import TaskContext from "../task_context.js";
|
||||
import cls from "../cls.js";
|
||||
import sql_init from "../sql_init.js";
|
||||
import { trimIndentation } from "@triliumnext/commons";
|
||||
import { getContext } from "../context.js";
|
||||
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
async function testImport(fileName: string) {
|
||||
@@ -19,7 +19,7 @@ async function testImport(fileName: string) {
|
||||
});
|
||||
|
||||
return new Promise<{ importedNote: BNote; rootNote: BNote }>((resolve, reject) => {
|
||||
cls.init(async () => {
|
||||
getContext().init(async () => {
|
||||
const rootNote = becca.getNote("root");
|
||||
if (!rootNote) {
|
||||
expect(rootNote).toBeTruthy();
|
||||
@@ -1,10 +1,6 @@
|
||||
|
||||
|
||||
import { ALLOWED_NOTE_TYPES, type NoteType } from "@triliumnext/commons";
|
||||
import { sanitize, utils } from "@triliumnext/core";
|
||||
import path from "path";
|
||||
import type { Stream } from "stream";
|
||||
import yauzl from "yauzl";
|
||||
import { basename, dirname } from "../utils/path.js";
|
||||
import { getZipProvider } from "./zip_provider.js";
|
||||
|
||||
import becca from "../../becca/becca.js";
|
||||
import BAttachment from "../../becca/entities/battachment.js";
|
||||
@@ -12,16 +8,17 @@ import BAttribute from "../../becca/entities/battribute.js";
|
||||
import BBranch from "../../becca/entities/bbranch.js";
|
||||
import type BNote from "../../becca/entities/bnote.js";
|
||||
import attributeService from "../../services/attributes.js";
|
||||
import log from "../../services/log.js";
|
||||
import { getLog } from "../../services/log.js";
|
||||
import noteService from "../../services/notes.js";
|
||||
import { newEntityId, processStringOrBuffer, unescapeHtml } from "../../services/utils.js";
|
||||
import type AttributeMeta from "../meta/attribute_meta.js";
|
||||
import type NoteMeta from "../meta/note_meta.js";
|
||||
import { getNoteTitle, newEntityId, removeFileExtension, unescapeHtml } from "../../services/utils/index.js";
|
||||
import { processStringOrBuffer } from "../../services/utils/binary.js";
|
||||
import protectedSessionService from "../protected_session.js";
|
||||
import type TaskContext from "../task_context.js";
|
||||
import treeService from "../tree.js";
|
||||
import markdownService from "./markdown.js";
|
||||
import mimeService from "./mime.js";
|
||||
import { AttributeMeta, NoteMeta } from "../../meta.js";
|
||||
import { sanitizeHtml } from "../sanitizer.js";
|
||||
|
||||
interface MetaFile {
|
||||
files: NoteMeta[];
|
||||
@@ -31,7 +28,7 @@ interface ImportZipOpts {
|
||||
preserveIds?: boolean;
|
||||
}
|
||||
|
||||
async function importZip(taskContext: TaskContext<"importNotes">, fileBuffer: Buffer, importRootNote: BNote, opts?: ImportZipOpts): Promise<BNote> {
|
||||
async function importZip(taskContext: TaskContext<"importNotes">, fileBuffer: Uint8Array, importRootNote: BNote, opts?: ImportZipOpts): Promise<BNote> {
|
||||
/** maps from original noteId (in ZIP file) to newly generated noteId */
|
||||
const noteIdMap: Record<string, string> = {};
|
||||
/** type maps from original attachmentId (in ZIP file) to newly generated attachmentId */
|
||||
@@ -140,7 +137,7 @@ async function importZip(taskContext: TaskContext<"importNotes">, fileBuffer: Bu
|
||||
if (parentNoteMeta?.noteId) {
|
||||
parentNoteId = parentNoteMeta.isImportRoot ? importRootNote.noteId : getNewNoteId(parentNoteMeta.noteId);
|
||||
} else {
|
||||
const parentPath = path.dirname(filePath);
|
||||
const parentPath = dirname(filePath);
|
||||
|
||||
if (parentPath === ".") {
|
||||
parentNoteId = importRootNote.noteId;
|
||||
@@ -162,7 +159,7 @@ async function importZip(taskContext: TaskContext<"importNotes">, fileBuffer: Bu
|
||||
|
||||
// in case we lack metadata, we treat e.g. "Programming.html" and "Programming" as the same note
|
||||
// (one data file, the other directory for children)
|
||||
const filePathNoExt = utils.removeFileExtension(filePath);
|
||||
const filePathNoExt = removeFileExtension(filePath);
|
||||
|
||||
if (filePathNoExt in createdPaths) {
|
||||
return createdPaths[filePathNoExt];
|
||||
@@ -199,7 +196,7 @@ async function importZip(taskContext: TaskContext<"importNotes">, fileBuffer: Bu
|
||||
}
|
||||
|
||||
if (!attributeService.isAttributeType(attr.type)) {
|
||||
log.error(`Unrecognized attribute type ${attr.type}`);
|
||||
getLog().error(`Unrecognized attribute type ${attr.type}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -217,8 +214,8 @@ async function importZip(taskContext: TaskContext<"importNotes">, fileBuffer: Bu
|
||||
}
|
||||
|
||||
if (taskContext.data?.safeImport) {
|
||||
attr.name = sanitize.sanitizeHtml(attr.name);
|
||||
attr.value = sanitize.sanitizeHtml(attr.value);
|
||||
attr.name = sanitizeHtml(attr.name);
|
||||
attr.value = sanitizeHtml(attr.value);
|
||||
}
|
||||
|
||||
attributes.push(attr);
|
||||
@@ -234,7 +231,7 @@ async function importZip(taskContext: TaskContext<"importNotes">, fileBuffer: Bu
|
||||
return;
|
||||
}
|
||||
|
||||
const noteTitle = utils.getNoteTitle(filePath, !!taskContext.data?.replaceUnderscoresWithSpaces, noteMeta);
|
||||
const noteTitle = getNoteTitle(filePath, !!taskContext.data?.replaceUnderscoresWithSpaces, noteMeta);
|
||||
const parentNoteId = getParentNoteId(filePath, parentNoteMeta);
|
||||
|
||||
if (!parentNoteId) {
|
||||
@@ -269,10 +266,10 @@ async function importZip(taskContext: TaskContext<"importNotes">, fileBuffer: Bu
|
||||
url = url.substr(2);
|
||||
}
|
||||
|
||||
absUrl = path.dirname(filePath);
|
||||
absUrl = dirname(filePath);
|
||||
|
||||
while (url.startsWith("../")) {
|
||||
absUrl = path.dirname(absUrl);
|
||||
absUrl = dirname(absUrl);
|
||||
|
||||
url = url.substr(3);
|
||||
}
|
||||
@@ -318,7 +315,7 @@ async function importZip(taskContext: TaskContext<"importNotes">, fileBuffer: Bu
|
||||
});
|
||||
|
||||
if (taskContext.data?.safeImport) {
|
||||
content = sanitize.sanitizeHtml(content);
|
||||
content = sanitizeHtml(content);
|
||||
}
|
||||
|
||||
content = content.replace(/<html.*<body[^>]*>/gis, "");
|
||||
@@ -333,7 +330,7 @@ async function importZip(taskContext: TaskContext<"importNotes">, fileBuffer: Bu
|
||||
try {
|
||||
url = decodeURIComponent(url).trim();
|
||||
} catch (e: any) {
|
||||
log.error(`Cannot parse image URL '${url}', keeping original. Error: ${e.message}.`);
|
||||
getLog().error(`Cannot parse image URL '${url}', keeping original. Error: ${e.message}.`);
|
||||
return `src="${url}"`;
|
||||
}
|
||||
|
||||
@@ -344,9 +341,9 @@ async function importZip(taskContext: TaskContext<"importNotes">, fileBuffer: Bu
|
||||
const target = getEntityIdFromRelativeUrl(url, filePath);
|
||||
|
||||
if (target.attachmentId) {
|
||||
return `src="api/attachments/${target.attachmentId}/image/${path.basename(url)}"`;
|
||||
return `src="api/attachments/${target.attachmentId}/image/${basename(url)}"`;
|
||||
} else if (target.noteId) {
|
||||
return `src="api/images/${target.noteId}/${path.basename(url)}"`;
|
||||
return `src="api/images/${target.noteId}/${basename(url)}"`;
|
||||
}
|
||||
return match;
|
||||
|
||||
@@ -356,7 +353,7 @@ async function importZip(taskContext: TaskContext<"importNotes">, fileBuffer: Bu
|
||||
try {
|
||||
url = decodeURIComponent(url).trim();
|
||||
} catch (e: any) {
|
||||
log.error(`Cannot parse link URL '${url}', keeping original. Error: ${e.message}.`);
|
||||
getLog().error(`Cannot parse link URL '${url}', keeping original. Error: ${e.message}.`);
|
||||
return `href="${url}"`;
|
||||
}
|
||||
|
||||
@@ -392,7 +389,7 @@ async function importZip(taskContext: TaskContext<"importNotes">, fileBuffer: Bu
|
||||
return content;
|
||||
}
|
||||
|
||||
function processNoteContent(noteMeta: NoteMeta | undefined, type: string, mime: string, content: string | Buffer, noteTitle: string, filePath: string) {
|
||||
function processNoteContent(noteMeta: NoteMeta | undefined, type: string, mime: string, content: string | Uint8Array, noteTitle: string, filePath: string) {
|
||||
if ((noteMeta?.format === "markdown" || (!noteMeta && taskContext.data?.textImportedAsText && ["text/markdown", "text/x-markdown", "text/mdx"].includes(mime))) && typeof content === "string") {
|
||||
content = markdownService.renderToHtml(content, noteTitle);
|
||||
}
|
||||
@@ -414,7 +411,7 @@ async function importZip(taskContext: TaskContext<"importNotes">, fileBuffer: Bu
|
||||
return content;
|
||||
}
|
||||
|
||||
function saveNote(filePath: string, content: string | Buffer) {
|
||||
function saveNote(filePath: string, content: string | Uint8Array) {
|
||||
const { parentNoteMeta, noteMeta, attachmentMeta } = getMeta(filePath);
|
||||
|
||||
if (noteMeta?.noImport) {
|
||||
@@ -467,7 +464,7 @@ async function importZip(taskContext: TaskContext<"importNotes">, fileBuffer: Bu
|
||||
content = processStringOrBuffer(content);
|
||||
}
|
||||
|
||||
const noteTitle = utils.getNoteTitle(filePath, taskContext.data?.replaceUnderscoresWithSpaces || false, noteMeta);
|
||||
const noteTitle = getNoteTitle(filePath, taskContext.data?.replaceUnderscoresWithSpaces || false, noteMeta);
|
||||
|
||||
content = processNoteContent(noteMeta, type, mime, content, noteTitle || "", filePath);
|
||||
|
||||
@@ -551,46 +548,42 @@ async function importZip(taskContext: TaskContext<"importNotes">, fileBuffer: Bu
|
||||
noteId,
|
||||
type: "label",
|
||||
name: "originalFileName",
|
||||
value: path.basename(filePath)
|
||||
value: basename(filePath)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// we're running two passes in order to obtain critical information first (meta file and root)
|
||||
const topLevelItems = new Set<string>();
|
||||
await readZipFile(fileBuffer, async (zipfile: yauzl.ZipFile, entry: yauzl.Entry) => {
|
||||
const zipProvider = getZipProvider();
|
||||
|
||||
await zipProvider.readZipFile(fileBuffer, async (entry, readContent) => {
|
||||
const filePath = normalizeFilePath(entry.fileName);
|
||||
|
||||
// make sure that the meta file is loaded before the rest of the files is processed.
|
||||
if (filePath === "!!!meta.json") {
|
||||
const content = await readContent(zipfile, entry);
|
||||
|
||||
metaFile = JSON.parse(content.toString("utf-8"));
|
||||
const content = await readContent();
|
||||
metaFile = JSON.parse(new TextDecoder("utf-8").decode(content));
|
||||
}
|
||||
|
||||
// determine the root of the .zip (i.e. if it has only one top-level folder then the root is that folder, or the root of the archive if there are multiple top-level folders).
|
||||
const firstSlash = filePath.indexOf("/");
|
||||
const topLevelPath = (firstSlash !== -1 ? filePath.substring(0, firstSlash) : filePath);
|
||||
topLevelItems.add(topLevelPath);
|
||||
|
||||
zipfile.readEntry();
|
||||
});
|
||||
|
||||
topLevelPath = (topLevelItems.size > 1 ? "" : topLevelItems.values().next().value ?? "");
|
||||
|
||||
await readZipFile(fileBuffer, async (zipfile: yauzl.ZipFile, entry: yauzl.Entry) => {
|
||||
await zipProvider.readZipFile(fileBuffer, async (entry, readContent) => {
|
||||
const filePath = normalizeFilePath(entry.fileName);
|
||||
|
||||
if (/\/$/.test(entry.fileName)) {
|
||||
saveDirectory(filePath);
|
||||
} else if (filePath !== "!!!meta.json") {
|
||||
const content = await readContent(zipfile, entry);
|
||||
|
||||
saveNote(filePath, content);
|
||||
saveNote(filePath, await readContent());
|
||||
}
|
||||
|
||||
taskContext.increaseProgressCount();
|
||||
zipfile.readEntry();
|
||||
});
|
||||
|
||||
for (const noteId of createdNoteIds) {
|
||||
@@ -613,7 +606,7 @@ async function importZip(taskContext: TaskContext<"importNotes">, fileBuffer: Bu
|
||||
if (attr.type !== "relation" || attr.value in becca.notes) {
|
||||
new BAttribute(attr).save();
|
||||
} else {
|
||||
log.info(`Relation not imported since the target note doesn't exist: ${JSON.stringify(attr)}`);
|
||||
getLog().info(`Relation not imported since the target note doesn't exist: ${JSON.stringify(attr)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -639,43 +632,6 @@ function normalizeFilePath(filePath: string): string {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
function streamToBuffer(stream: Stream): Promise<Buffer> {
|
||||
const chunks: Uint8Array[] = [];
|
||||
stream.on("data", (chunk) => chunks.push(chunk));
|
||||
|
||||
return new Promise((res, rej) => stream.on("end", () => res(Buffer.concat(chunks))));
|
||||
}
|
||||
|
||||
export function readContent(zipfile: yauzl.ZipFile, entry: yauzl.Entry): Promise<Buffer> {
|
||||
return new Promise((res, rej) => {
|
||||
zipfile.openReadStream(entry, (err, readStream) => {
|
||||
if (err) rej(err);
|
||||
if (!readStream) throw new Error("Unable to read content.");
|
||||
|
||||
streamToBuffer(readStream).then(res);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function readZipFile(buffer: Buffer, processEntryCallback: (zipfile: yauzl.ZipFile, entry: yauzl.Entry) => Promise<void>) {
|
||||
return new Promise<void>((res, rej) => {
|
||||
yauzl.fromBuffer(buffer, { lazyEntries: true, validateEntrySizes: false }, (err, zipfile) => {
|
||||
if (err) rej(err);
|
||||
if (!zipfile) throw new Error("Unable to read zip file.");
|
||||
|
||||
zipfile.readEntry();
|
||||
zipfile.on("entry", async (entry) => {
|
||||
try {
|
||||
await processEntryCallback(zipfile, entry);
|
||||
} catch (e) {
|
||||
rej(e);
|
||||
}
|
||||
});
|
||||
zipfile.on("end", res);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function resolveNoteType(type: string | undefined): NoteType {
|
||||
// BC for ZIPs created in Trilium 0.57 and older
|
||||
switch (type) {
|
||||
25
packages/trilium-core/src/services/import/zip_provider.ts
Normal file
25
packages/trilium-core/src/services/import/zip_provider.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
export interface ZipEntry {
|
||||
fileName: string;
|
||||
}
|
||||
|
||||
export interface ZipProvider {
|
||||
/**
|
||||
* Iterates over every entry in a ZIP buffer, calling `processEntry` for each one.
|
||||
* `readContent()` inside the callback reads the raw bytes of that entry on demand.
|
||||
*/
|
||||
readZipFile(
|
||||
buffer: Uint8Array,
|
||||
processEntry: (entry: ZipEntry, readContent: () => Promise<Uint8Array>) => Promise<void>
|
||||
): Promise<void>;
|
||||
}
|
||||
|
||||
let zipProvider: ZipProvider | null = null;
|
||||
|
||||
export function initZipProvider(provider: ZipProvider) {
|
||||
zipProvider = provider;
|
||||
}
|
||||
|
||||
export function getZipProvider(): ZipProvider {
|
||||
if (!zipProvider) throw new Error("ZipProvider not initialized.");
|
||||
return zipProvider;
|
||||
}
|
||||
@@ -312,6 +312,26 @@ export class SqlService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Async-safe transaction wrapper for use in Web Workers and other single-threaded async contexts.
|
||||
* Uses manual BEGIN/COMMIT/ROLLBACK because the synchronous `transactional()` cannot await promises.
|
||||
*/
|
||||
async transactionalAsync<T>(func: () => Promise<T>): Promise<T> {
|
||||
this.execute("BEGIN IMMEDIATE");
|
||||
try {
|
||||
const result = await func();
|
||||
this.execute("COMMIT");
|
||||
if (!this.dbConnection.inTransaction) {
|
||||
this.params.onTransactionCommit();
|
||||
}
|
||||
return result;
|
||||
} catch (e) {
|
||||
this.execute("ROLLBACK");
|
||||
this.params.onTransactionRollback();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
fillParamList(paramIds: string[] | Set<string>, truncate = true) {
|
||||
if ("length" in paramIds && paramIds.length === 0) {
|
||||
return;
|
||||
|
||||
@@ -15,11 +15,16 @@ import migrationService from "./migration";
|
||||
export const dbReady = deferred<void>();
|
||||
|
||||
let schema: string;
|
||||
let getDemoArchive: (() => Promise<Uint8Array | null>) | null = null;
|
||||
|
||||
export function initSchema(schemaStr: string) {
|
||||
schema = schemaStr;
|
||||
}
|
||||
|
||||
export function initDemoArchive(fn: () => Promise<Uint8Array | null>) {
|
||||
getDemoArchive = fn;
|
||||
}
|
||||
|
||||
function schemaExists() {
|
||||
return !!getSql().getValue(/*sql*/`SELECT name FROM sqlite_master
|
||||
WHERE type = 'table' AND name = 'options'`);
|
||||
@@ -177,21 +182,23 @@ async function createInitialDatabase(skipDemoDb?: boolean) {
|
||||
});
|
||||
|
||||
// Import demo content.
|
||||
log.info("Importing demo content...");
|
||||
if (!skipDemoDb && getDemoArchive) {
|
||||
log.info("Importing demo content...");
|
||||
const demoFile = await getDemoArchive();
|
||||
if (demoFile) {
|
||||
const { default: zipImportService } = await import("./import/zip.js");
|
||||
const dummyTaskContext = new TaskContext("no-progress-reporting", "importNotes", null);
|
||||
await zipImportService.importZip(dummyTaskContext, demoFile, rootNote);
|
||||
}
|
||||
}
|
||||
|
||||
const dummyTaskContext = new TaskContext("no-progress-reporting", "importNotes", null);
|
||||
|
||||
// if (demoFile) {
|
||||
// await zipImportService.importZip(dummyTaskContext, demoFile, rootNote);
|
||||
// }
|
||||
|
||||
// Post-demo.
|
||||
// Post-demo: pick the first visible (non-system) child of root as the start note.
|
||||
// System notes have IDs starting with "_" and should not be navigated to on startup.
|
||||
// Falls back to "root" if no visible child exists (e.g. empty database).
|
||||
sql.transactional(() => {
|
||||
// this needs to happen after ZIP import,
|
||||
// the previous solution was to move option initialization here, but then the important parts of initialization
|
||||
// are not all in one transaction (because ZIP import is async and thus not transactional)
|
||||
|
||||
const startNoteId = sql.getValue("SELECT noteId FROM branches WHERE parentNoteId = 'root' AND isDeleted = 0 ORDER BY notePosition");
|
||||
const startNoteId = sql.getValue<string | null>(
|
||||
"SELECT noteId FROM branches WHERE parentNoteId = 'root' AND isDeleted = 0 AND substr(noteId, 1, 1) != '_' ORDER BY notePosition"
|
||||
) ?? "root";
|
||||
|
||||
optionService.setOption(
|
||||
"openNoteContexts",
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import chardet from "chardet";
|
||||
import stripBom from "strip-bom";
|
||||
|
||||
const utf8Decoder = new TextDecoder("utf-8");
|
||||
const utf8Encoder = new TextEncoder();
|
||||
|
||||
@@ -59,3 +62,32 @@ export function wrapStringOrBuffer(stringOrBuffer: string | Uint8Array) {
|
||||
return stringOrBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For buffers, they are scanned for a supported encoding and decoded (UTF-8, UTF-16). In some cases, the BOM is also stripped.
|
||||
*
|
||||
* For strings, they are returned immediately without any transformation.
|
||||
*
|
||||
* For nullish values, an empty string is returned.
|
||||
*
|
||||
* @param data the string or buffer to process.
|
||||
* @returns the string representation of the buffer, or the same string is it's a string.
|
||||
*/
|
||||
export function processStringOrBuffer(data: string | Uint8Array | null) {
|
||||
if (!data) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (typeof data === "string") {
|
||||
return data;
|
||||
}
|
||||
|
||||
const detectedEncoding = chardet.detect(data);
|
||||
switch (detectedEncoding) {
|
||||
case "UTF-16LE":
|
||||
return stripBom(new TextDecoder("utf-16le").decode(data));
|
||||
case "UTF-8":
|
||||
default:
|
||||
return utf8Decoder.decode(data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,11 @@ export function hash(text: string) {
|
||||
return encodeBase64(getCrypto().createHash("sha1", text.normalize()));
|
||||
}
|
||||
|
||||
export function md5(content: string | Uint8Array) {
|
||||
const bytes = getCrypto().createHash("md5", content);
|
||||
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
||||
}
|
||||
|
||||
export function isStringNote(type: string | undefined, mime: string) {
|
||||
return (type && STRING_NOTE_TYPES.has(type)) || mime.startsWith("text/") || STRING_MIME_TYPES.has(mime);
|
||||
}
|
||||
|
||||
@@ -16,3 +16,12 @@ export function basename(filePath: string): string {
|
||||
const lastSlash = Math.max(filePath.lastIndexOf("/"), filePath.lastIndexOf("\\"));
|
||||
return filePath.substring(lastSlash + 1);
|
||||
}
|
||||
|
||||
/** Returns the directory part of a file path, or "." if there is none. */
|
||||
export function dirname(filePath: string): string {
|
||||
const normalized = filePath.replace(/\\/g, "/");
|
||||
const lastSlash = normalized.lastIndexOf("/");
|
||||
if (lastSlash === -1) return ".";
|
||||
if (lastSlash === 0) return "/";
|
||||
return normalized.substring(0, lastSlash);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"compilerOptions": {
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"target": "ES2020",
|
||||
"rootDir": "src",
|
||||
"outDir": "dist",
|
||||
"tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo",
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/vitest",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"target": "ES2020",
|
||||
"types": [
|
||||
"vitest"
|
||||
],
|
||||
|
||||
394
pnpm-lock.yaml
generated
394
pnpm-lock.yaml
generated
@@ -160,7 +160,7 @@ importers:
|
||||
devDependencies:
|
||||
'@redocly/cli':
|
||||
specifier: 2.25.1
|
||||
version: 2.25.1(@opentelemetry/api@1.9.0)(bufferutil@4.0.9)(core-js@3.46.0)(encoding@0.1.13)(utf-8-validate@5.0.10)
|
||||
version: 2.25.1(@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
|
||||
@@ -489,6 +489,9 @@ importers:
|
||||
draggabilly:
|
||||
specifier: 3.0.0
|
||||
version: 3.0.0
|
||||
fflate:
|
||||
specifier: 0.8.2
|
||||
version: 0.8.2
|
||||
force-graph:
|
||||
specifier: 1.51.2
|
||||
version: 1.51.2
|
||||
@@ -507,6 +510,9 @@ importers:
|
||||
jquery.fancytree:
|
||||
specifier: 2.38.5
|
||||
version: 2.38.5(jquery@4.0.0)
|
||||
js-md5:
|
||||
specifier: 0.8.3
|
||||
version: 0.8.3
|
||||
js-sha1:
|
||||
specifier: 0.7.0
|
||||
version: 0.7.0
|
||||
@@ -878,9 +884,6 @@ importers:
|
||||
bootstrap:
|
||||
specifier: 5.3.8
|
||||
version: 5.3.8(@popperjs/core@2.11.8)
|
||||
chardet:
|
||||
specifier: 2.1.1
|
||||
version: 2.1.1
|
||||
cheerio:
|
||||
specifier: 1.2.0
|
||||
version: 1.2.0
|
||||
@@ -1001,9 +1004,6 @@ importers:
|
||||
stream-throttle:
|
||||
specifier: 0.1.3
|
||||
version: 0.1.3
|
||||
strip-bom:
|
||||
specifier: 5.0.0
|
||||
version: 5.0.0
|
||||
striptags:
|
||||
specifier: 3.2.0
|
||||
version: 3.2.0
|
||||
@@ -1041,12 +1041,6 @@ importers:
|
||||
specifier: 17.3.1
|
||||
version: 17.3.1
|
||||
|
||||
apps/standalone-desktop:
|
||||
devDependencies:
|
||||
'@neutralinojs/neu':
|
||||
specifier: 11.6.0
|
||||
version: 11.6.0
|
||||
|
||||
apps/web-clipper:
|
||||
dependencies:
|
||||
cash-dom:
|
||||
@@ -1713,6 +1707,9 @@ importers:
|
||||
async-mutex:
|
||||
specifier: 0.5.0
|
||||
version: 0.5.0
|
||||
chardet:
|
||||
specifier: 2.1.1
|
||||
version: 2.1.1
|
||||
escape-html:
|
||||
specifier: 1.0.3
|
||||
version: 1.0.3
|
||||
@@ -1731,6 +1728,9 @@ importers:
|
||||
sanitize-html:
|
||||
specifier: 2.17.2
|
||||
version: 2.17.2
|
||||
strip-bom:
|
||||
specifier: 5.0.0
|
||||
version: 5.0.0
|
||||
unescape:
|
||||
specifier: 1.0.1
|
||||
version: 1.0.1
|
||||
@@ -1752,7 +1752,7 @@ importers:
|
||||
version: 7.2.2
|
||||
turndown-attendant:
|
||||
specifier: 0.0.3
|
||||
version: 0.0.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)
|
||||
version: 0.0.3(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||
|
||||
packages:
|
||||
|
||||
@@ -4289,10 +4289,6 @@ packages:
|
||||
'@napi-rs/wasm-runtime@1.1.1':
|
||||
resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==}
|
||||
|
||||
'@neutralinojs/neu@11.6.0':
|
||||
resolution: {integrity: sha512-S1LKPZSFwh29XrajhvXimhiCgewI17GQDreETQGDiGRyfKlGM9WadpdcwT/GKbHK42VK1KI1hnNsHOR5HeGnlA==}
|
||||
hasBin: true
|
||||
|
||||
'@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1':
|
||||
resolution: {integrity: sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==}
|
||||
|
||||
@@ -8514,10 +8510,6 @@ packages:
|
||||
config-chain@1.1.13:
|
||||
resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
|
||||
|
||||
configstore@5.0.1:
|
||||
resolution: {integrity: sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
configstore@7.1.0:
|
||||
resolution: {integrity: sha512-N4oog6YJWbR9kGyXvS7jEykLDXIE2C0ILYqNBZBp9iwiJpoCBWYsuAdW6PPFn6w06jjnC+3JstVvWHO4cZqvRg==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -8666,10 +8658,6 @@ packages:
|
||||
crypto-js@4.2.0:
|
||||
resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
|
||||
|
||||
crypto-random-string@2.0.0:
|
||||
resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
csrf-csrf@4.0.3:
|
||||
resolution: {integrity: sha512-DaygOzelL4Qo1pHwI9LPyZL+X2456/OzpT596kNeZGiTSqKVDOk/9PPJ+FjzZacjMUEusOHw3WJKe1RW4iUhrw==}
|
||||
|
||||
@@ -8955,10 +8943,6 @@ packages:
|
||||
resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d@1.0.2:
|
||||
resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==}
|
||||
engines: {node: '>=0.12'}
|
||||
|
||||
dagre-d3-es@7.0.14:
|
||||
resolution: {integrity: sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==}
|
||||
|
||||
@@ -9018,15 +9002,6 @@ packages:
|
||||
supports-color:
|
||||
optional: true
|
||||
|
||||
debug@4.3.1:
|
||||
resolution: {integrity: sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==}
|
||||
engines: {node: '>=6.0'}
|
||||
peerDependencies:
|
||||
supports-color: '*'
|
||||
peerDependenciesMeta:
|
||||
supports-color:
|
||||
optional: true
|
||||
|
||||
debug@4.3.7:
|
||||
resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==}
|
||||
engines: {node: '>=6.0'}
|
||||
@@ -9253,10 +9228,6 @@ packages:
|
||||
domutils@3.2.2:
|
||||
resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
|
||||
|
||||
dot-prop@5.3.0:
|
||||
resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
dot-prop@9.0.0:
|
||||
resolution: {integrity: sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -9306,9 +9277,6 @@ packages:
|
||||
engines: {node: '>=18.0.0'}
|
||||
hasBin: true
|
||||
|
||||
edit-json-file@1.8.1:
|
||||
resolution: {integrity: sha512-x8L381+GwqxQejPipwrUZIyAg5gDQ9tLVwiETOspgXiaQztLsrOm7luBW5+Pe31aNezuzDY79YyzF+7viCRPXA==}
|
||||
|
||||
ee-first@1.1.1:
|
||||
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
|
||||
|
||||
@@ -9521,16 +9489,9 @@ packages:
|
||||
es-toolkit@1.39.5:
|
||||
resolution: {integrity: sha512-z9V0qU4lx1TBXDNFWfAASWk6RNU6c6+TJBKE+FLIg8u0XJ6Yw58Hi0yX8ftEouj6p1QARRlXLFfHbIli93BdQQ==}
|
||||
|
||||
es5-ext@0.10.64:
|
||||
resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==}
|
||||
engines: {node: '>=0.10'}
|
||||
|
||||
es6-error@4.1.1:
|
||||
resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==}
|
||||
|
||||
es6-iterator@2.0.3:
|
||||
resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==}
|
||||
|
||||
es6-promise-pool@2.5.0:
|
||||
resolution: {integrity: sha512-VHErXfzR/6r/+yyzPKeBvO0lgjfC5cbDCQWjWwMZWSb6YU39TGIl51OUmCfWCq4ylMdJSB8zkz2vIuIeIxXApA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -9541,10 +9502,6 @@ packages:
|
||||
es6-promise@4.2.8:
|
||||
resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==}
|
||||
|
||||
es6-symbol@3.1.4:
|
||||
resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==}
|
||||
engines: {node: '>=0.12'}
|
||||
|
||||
esbuild-loader@4.3.0:
|
||||
resolution: {integrity: sha512-D7HeJNdkDKKMarPQO/3dlJT6RwN2YJO7ENU6RPlpOz5YxSHnUNi2yvW41Bckvi1EVwctIaLzlb0ni5ag2GINYA==}
|
||||
peerDependencies:
|
||||
@@ -9690,10 +9647,6 @@ packages:
|
||||
jiti:
|
||||
optional: true
|
||||
|
||||
esniff@2.0.1:
|
||||
resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==}
|
||||
engines: {node: '>=0.10'}
|
||||
|
||||
espree@10.4.0:
|
||||
resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
@@ -9740,9 +9693,6 @@ packages:
|
||||
ev-emitter@2.1.2:
|
||||
resolution: {integrity: sha512-jQ5Ql18hdCQ4qS+RCrbLfz1n+Pags27q5TwMKvZyhp5hh2UULUYZUy1keqj6k6SYsdqIYjnmz7xyyEY0V67B8Q==}
|
||||
|
||||
event-emitter@0.3.5:
|
||||
resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==}
|
||||
|
||||
event-target-shim@5.0.1:
|
||||
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -9825,9 +9775,6 @@ packages:
|
||||
resolution: {integrity: sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
ext@1.7.0:
|
||||
resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==}
|
||||
|
||||
extend-shallow@2.0.1:
|
||||
resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -9978,9 +9925,6 @@ packages:
|
||||
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
find-value@1.0.13:
|
||||
resolution: {integrity: sha512-epNL4mnl3HUYrwVQtZ8s0nxkE4ogAoSqO1V1fa670Ww1fXp8Yr74zNS9Aib/vLNf0rq0AF/4mboo7ev5XkikXQ==}
|
||||
|
||||
firefox-profile@4.7.0:
|
||||
resolution: {integrity: sha512-aGApEu5bfCNbA4PGUZiRJAIU6jKmghV2UVdklXAofnNtiDjqYw0czLS46W7IfFqVKgKhFB8Ao2YoNGHY4BoIMQ==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -10835,10 +10779,6 @@ packages:
|
||||
resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==}
|
||||
engines: {node: '>= 12'}
|
||||
|
||||
ip-regex@4.3.0:
|
||||
resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
ipaddr.js@1.9.1:
|
||||
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
|
||||
engines: {node: '>= 0.10'}
|
||||
@@ -11004,10 +10944,6 @@ packages:
|
||||
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
|
||||
engines: {node: '>=0.12.0'}
|
||||
|
||||
is-obj@2.0.0:
|
||||
resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
is-path-inside@3.0.3:
|
||||
resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -11100,9 +11036,6 @@ packages:
|
||||
resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-typedarray@1.0.0:
|
||||
resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==}
|
||||
|
||||
is-unicode-supported@0.1.0:
|
||||
resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -11111,9 +11044,6 @@ packages:
|
||||
resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
is-url@1.2.4:
|
||||
resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==}
|
||||
|
||||
is-weakmap@2.0.2:
|
||||
resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -11137,10 +11067,6 @@ packages:
|
||||
resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
is2@2.0.9:
|
||||
resolution: {integrity: sha512-rZkHeBn9Zzq52sd9IUIV3a5mfwBY+o2HePMh0wkGBM4z4qjvy2GwVxQ6nNXSfw6MmVP6gf1QIlWjiOavhM3x5g==}
|
||||
engines: {node: '>=v0.10.0'}
|
||||
|
||||
isarray@0.0.1:
|
||||
resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==}
|
||||
|
||||
@@ -11188,9 +11114,6 @@ packages:
|
||||
resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
iterate-object@1.3.5:
|
||||
resolution: {integrity: sha512-eL23u8oFooYTq6TtJKjp2RYjZnCkUYQvC0T/6fJfWykXJ3quvdDdzKZ3CEjy8b3JGOvLTjDYMEMIp5243R906A==}
|
||||
|
||||
iterator.prototype@1.1.5:
|
||||
resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -11256,6 +11179,9 @@ packages:
|
||||
resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
js-md5@0.8.3:
|
||||
resolution: {integrity: sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ==}
|
||||
|
||||
js-sha1@0.7.0:
|
||||
resolution: {integrity: sha512-oQZ1Mo7440BfLSv9TX87VNEyU52pXPVG19F9PL3gTgNt0tVxlZ8F4O6yze3CLuLx28TxotxvlyepCNaaV0ZjMw==}
|
||||
|
||||
@@ -11805,10 +11731,6 @@ packages:
|
||||
resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
make-dir@3.1.0:
|
||||
resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
make-dir@4.0.0:
|
||||
resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -12291,9 +12213,6 @@ packages:
|
||||
ms@2.0.0:
|
||||
resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
|
||||
|
||||
ms@2.1.2:
|
||||
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
||||
|
||||
ms@2.1.3:
|
||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||
|
||||
@@ -12400,9 +12319,6 @@ packages:
|
||||
resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==}
|
||||
engines: {node: '>= 0.4.0'}
|
||||
|
||||
next-tick@1.1.0:
|
||||
resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
|
||||
|
||||
ngraph.events@1.2.2:
|
||||
resolution: {integrity: sha512-JsUbEOzANskax+WSYiAPETemLWYXmixuPAlmZmhIbIj6FH/WDgEGCGnRwUQBK0GjOnVm8Ui+e5IJ+5VZ4e32eQ==}
|
||||
|
||||
@@ -13086,10 +13002,6 @@ packages:
|
||||
png-chunks-extract@1.0.0:
|
||||
resolution: {integrity: sha512-ZiVwF5EJ0DNZyzAqld8BP1qyJBaGOFaq9zl579qfbkcmOwWLLO4I9L8i2O4j3HkI6/35i0nKG2n+dZplxiT89Q==}
|
||||
|
||||
png2icons@2.0.1:
|
||||
resolution: {integrity: sha512-GDEQJr8OG4e6JMp7mABtXFSEpgJa1CCpbQiAR+EjhkHJHnUL9zPPtbOrjsMD8gUbikgv3j7x404b0YJsV3aVFA==}
|
||||
hasBin: true
|
||||
|
||||
pngjs@6.0.0:
|
||||
resolution: {integrity: sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==}
|
||||
engines: {node: '>=12.13.0'}
|
||||
@@ -13572,9 +13484,6 @@ packages:
|
||||
quickselect@3.0.0:
|
||||
resolution: {integrity: sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==}
|
||||
|
||||
r-json@1.3.1:
|
||||
resolution: {integrity: sha512-5nhRFfjVMQdrwKUfUlRpDUCocdKtjSnYZ1R/86mpZDV3MfsZ3dYYNjSGuMX+mPBvFvQBhdzxSqxkuLPLv4uFGg==}
|
||||
|
||||
rand-token@1.0.1:
|
||||
resolution: {integrity: sha512-Zri5SfJmEzBJ3IexFdigvPSCamslJ7UjLkUn0tlgH7COJvaUr5V7FyUYgKifEMTw7gFO8ZLcWjcU+kq8akipzg==}
|
||||
engines: {node: '>= 10'}
|
||||
@@ -13776,10 +13685,6 @@ packages:
|
||||
resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==}
|
||||
engines: {node: '>= 10.13.0'}
|
||||
|
||||
recursive-readdir@2.2.3:
|
||||
resolution: {integrity: sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
|
||||
redoc@2.5.1:
|
||||
resolution: {integrity: sha512-LmqA+4A3CmhTllGG197F0arUpmChukAj9klfSdxNRemT9Hr07xXr7OGKu4PHzBs359sgrJ+4JwmOlM7nxLPGMg==}
|
||||
engines: {node: '>=6.9', npm: '>=3.0.0'}
|
||||
@@ -14568,9 +14473,6 @@ packages:
|
||||
spacetrim@0.11.59:
|
||||
resolution: {integrity: sha512-lLYsktklSRKprreOm7NXReW8YiX2VBjbgmXYEziOoGf/qsJqAEACaDvoTtUOycwjpaSh+bT8eu0KrJn7UNxiCg==}
|
||||
|
||||
spawn-command@1.0.0:
|
||||
resolution: {integrity: sha512-zsboEQnjeF6tSJ8SRnojMr22HyFEaRaohgTt0Kgx3BgzkXYiboh09vpmZVIq1HOLzkFZDgFJJfwGUqSbb5fQQQ==}
|
||||
|
||||
spawn-sync@1.0.15:
|
||||
resolution: {integrity: sha512-9DWBgrgYZzNghseho0JOuh+5fg9u6QWhAWa51QC7+U5rCheZ/j1DrEZnyE0RBBRqZ9uEXGPgSSM0nky6burpVw==}
|
||||
|
||||
@@ -14997,9 +14899,6 @@ packages:
|
||||
engines: {node: '>=18'}
|
||||
deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
||||
|
||||
tcp-port-used@1.0.2:
|
||||
resolution: {integrity: sha512-l7ar8lLUD3XS1V2lfoJlCBaeoaWo/2xfYt81hM7VlvR4RrMVFqfmzfhLVk40hAb368uitje5gPtBRL1m/DGvLA==}
|
||||
|
||||
temp@0.9.4:
|
||||
resolution: {integrity: sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
@@ -15274,9 +15173,6 @@ packages:
|
||||
resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
type@2.7.3:
|
||||
resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==}
|
||||
|
||||
typed-array-buffer@1.0.3:
|
||||
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -15293,9 +15189,6 @@ packages:
|
||||
resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
typedarray-to-buffer@3.1.5:
|
||||
resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==}
|
||||
|
||||
typedarray@0.0.6:
|
||||
resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
|
||||
|
||||
@@ -15462,10 +15355,6 @@ packages:
|
||||
resolution: {integrity: sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg==}
|
||||
engines: {node: ^18.17.0 || >=20.5.0}
|
||||
|
||||
unique-string@2.0.0:
|
||||
resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
unist-util-find-after@5.0.0:
|
||||
resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==}
|
||||
|
||||
@@ -15596,10 +15485,6 @@ packages:
|
||||
resolution: {integrity: sha512-PCKbdWw85JsYMvmCv5GH3kXmM66rCd9m1hBEDutPNv94b/pqCMT4NtcKyeWYvLFiE8b+ha1Jdl8XAaUdPn5QTg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
utf-8-validate@5.0.10:
|
||||
resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==}
|
||||
engines: {node: '>=6.14.2'}
|
||||
|
||||
utf-8-validate@6.0.5:
|
||||
resolution: {integrity: sha512-EYZR+OpIXp9Y1eG1iueg8KRsY8TuT8VNgnanZ0uA3STqhHQTLwbl+WX76/9X5OY12yQubymBpaBSmMPkSTQcKA==}
|
||||
engines: {node: '>=6.14.2'}
|
||||
@@ -15852,12 +15737,6 @@ packages:
|
||||
vt-pbf@3.1.3:
|
||||
resolution: {integrity: sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==}
|
||||
|
||||
w-json@1.3.10:
|
||||
resolution: {integrity: sha512-XadVyw0xE+oZ5FGApXsdswv96rOhStzKqL53uSe5UaTadABGkWIg1+DTx8kiZ/VqTZTBneoL0l65RcPe4W3ecw==}
|
||||
|
||||
w-json@1.3.11:
|
||||
resolution: {integrity: sha512-Xa8vTinB5XBIYZlcN8YyHpE625pBU6k+lvCetTQM+FKxRtLJxAY9zUVZbRqCqkMeEGbQpKvGUzwh4wZKGem+ag==}
|
||||
|
||||
w3c-hr-time@1.0.2:
|
||||
resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==}
|
||||
deprecated: Use your platform's native performance.now() and performance.timeOrigin.
|
||||
@@ -15980,10 +15859,6 @@ packages:
|
||||
resolution: {integrity: sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==}
|
||||
engines: {node: '>=0.8.0'}
|
||||
|
||||
websocket@1.0.35:
|
||||
resolution: {integrity: sha512-/REy6amwPZl44DDzvRCkaI1q1bIiQB0mEFQLUrhz3z2EK91cp3n72rAjUlrTP0zV22HJIUOVHQGPxhFRjxjt+Q==}
|
||||
engines: {node: '>=4.0.0'}
|
||||
|
||||
webworkify@1.5.0:
|
||||
resolution: {integrity: sha512-AMcUeyXAhbACL8S2hqqdqOLqvJ8ylmIbNwUIqQujRSouf4+eUFaXbG6F1Rbu+srlJMmxQWsiU7mOJi0nMBfM1g==}
|
||||
|
||||
@@ -16122,9 +15997,6 @@ packages:
|
||||
wrappy@1.0.2:
|
||||
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
||||
|
||||
write-file-atomic@3.0.3:
|
||||
resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==}
|
||||
|
||||
write-file-atomic@7.0.1:
|
||||
resolution: {integrity: sha512-OTIk8iR8/aCRWBqvxrzxR0hgxWpnYBblY1S5hDWBQfk/VFmJwzmJgQFN3WsoUKHISv2eAwe+PpbUzyL1CKTLXg==}
|
||||
engines: {node: ^20.17.0 || >=22.9.0}
|
||||
@@ -16182,10 +16054,6 @@ packages:
|
||||
eslint:
|
||||
optional: true
|
||||
|
||||
xdg-basedir@4.0.0:
|
||||
resolution: {integrity: sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
xdg-basedir@5.1.0:
|
||||
resolution: {integrity: sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -16231,11 +16099,6 @@ packages:
|
||||
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
yaeti@0.0.6:
|
||||
resolution: {integrity: sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==}
|
||||
engines: {node: '>=0.10.32'}
|
||||
deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
|
||||
|
||||
yallist@3.1.1:
|
||||
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
|
||||
|
||||
@@ -16301,9 +16164,6 @@ packages:
|
||||
resolution: {integrity: sha512-k1isifdbpNSFEHFJ1ZY4YDewv0IH9FR61lDetaRMD3j2ae3bIXGV+7c+LHCqtQGofSd8PIyV4X6+dHMAnSr60A==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
yazl@3.3.1:
|
||||
resolution: {integrity: sha512-BbETDVWG+VcMUle37k5Fqp//7SDOK2/1+T7X8TD96M3D9G8jK5VLUdQVdVjGi8im7FGkazX7kk5hkU8X4L5Bng==}
|
||||
|
||||
yn@3.1.1:
|
||||
resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -16331,10 +16191,6 @@ packages:
|
||||
zip-dir@2.0.0:
|
||||
resolution: {integrity: sha512-uhlsJZWz26FLYXOD6WVuq+fIcZ3aBPGo/cFdiLlv3KNwpa52IF3ISV8fLhQLiqVu5No3VhlqlgthN6gehil1Dg==}
|
||||
|
||||
zip-lib@1.3.1:
|
||||
resolution: {integrity: sha512-fgtJsv4yuqbgo7MC2F2n2pVlAGO9VjHOzmK2p9yPw8LKNRfAbm7Mmvw0Ji6AZRDAqJqT3XGe6AzwwI6LggobVA==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
zip-stream@6.0.1:
|
||||
resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==}
|
||||
engines: {node: '>= 14'}
|
||||
@@ -17778,6 +17634,8 @@ snapshots:
|
||||
'@ckeditor/ckeditor5-widget': 47.6.1
|
||||
ckeditor5: 47.6.1
|
||||
es-toolkit: 1.39.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@ckeditor/ckeditor5-import-word@47.6.1':
|
||||
dependencies:
|
||||
@@ -17813,6 +17671,8 @@ snapshots:
|
||||
'@ckeditor/ckeditor5-ui': 47.6.1
|
||||
'@ckeditor/ckeditor5-utils': 47.6.1
|
||||
ckeditor5: 47.6.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@ckeditor/ckeditor5-line-height@47.6.1':
|
||||
dependencies:
|
||||
@@ -17837,6 +17697,8 @@ snapshots:
|
||||
'@ckeditor/ckeditor5-widget': 47.6.1
|
||||
ckeditor5: 47.6.1
|
||||
es-toolkit: 1.39.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@ckeditor/ckeditor5-list-multi-level@47.6.1':
|
||||
dependencies:
|
||||
@@ -20357,30 +20219,6 @@ snapshots:
|
||||
'@tybys/wasm-util': 0.10.1
|
||||
optional: true
|
||||
|
||||
'@neutralinojs/neu@11.6.0':
|
||||
dependencies:
|
||||
'@electron/asar': 3.4.1
|
||||
chalk: 4.1.2
|
||||
chokidar: 3.6.0
|
||||
commander: 7.2.0
|
||||
configstore: 5.0.1
|
||||
edit-json-file: 1.8.1
|
||||
follow-redirects: 1.15.11(debug@4.4.3)
|
||||
fs-extra: 9.1.0
|
||||
pe-library: 1.0.1
|
||||
png2icons: 2.0.1
|
||||
postject: 1.0.0-alpha.6
|
||||
recursive-readdir: 2.2.3
|
||||
resedit: 2.0.3
|
||||
spawn-command: 1.0.0
|
||||
tcp-port-used: 1.0.2
|
||||
uuid: 8.3.2
|
||||
websocket: 1.0.35
|
||||
zip-lib: 1.3.1
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
- supports-color
|
||||
|
||||
'@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1':
|
||||
dependencies:
|
||||
eslint-scope: 5.1.1
|
||||
@@ -21396,7 +21234,7 @@ snapshots:
|
||||
dependencies:
|
||||
ulid: 2.4.0
|
||||
|
||||
'@redocly/cli@2.25.1(@opentelemetry/api@1.9.0)(bufferutil@4.0.9)(core-js@3.46.0)(encoding@0.1.13)(utf-8-validate@5.0.10)':
|
||||
'@redocly/cli@2.25.1(@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)
|
||||
@@ -21422,7 +21260,7 @@ snapshots:
|
||||
redoc: 2.5.1(core-js@3.46.0)(encoding@0.1.13)(mobx@6.15.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(styled-components@6.3.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4))
|
||||
semver: 7.7.4
|
||||
set-cookie-parser: 2.7.2
|
||||
simple-websocket: 9.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)
|
||||
simple-websocket: 9.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||
styled-components: 6.3.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
ulid: 3.0.2
|
||||
undici: 6.24.0
|
||||
@@ -25433,6 +25271,7 @@ snapshots:
|
||||
bufferutil@4.0.9:
|
||||
dependencies:
|
||||
node-gyp-build: 4.8.4
|
||||
optional: true
|
||||
|
||||
bundle-name@4.1.0:
|
||||
dependencies:
|
||||
@@ -26055,15 +25894,6 @@ snapshots:
|
||||
ini: 1.3.8
|
||||
proto-list: 1.2.4
|
||||
|
||||
configstore@5.0.1:
|
||||
dependencies:
|
||||
dot-prop: 5.3.0
|
||||
graceful-fs: 4.2.11
|
||||
make-dir: 3.1.0
|
||||
unique-string: 2.0.0
|
||||
write-file-atomic: 3.0.3
|
||||
xdg-basedir: 4.0.0
|
||||
|
||||
configstore@7.1.0:
|
||||
dependencies:
|
||||
atomically: 2.1.0
|
||||
@@ -26220,8 +26050,6 @@ snapshots:
|
||||
|
||||
crypto-js@4.2.0: {}
|
||||
|
||||
crypto-random-string@2.0.0: {}
|
||||
|
||||
csrf-csrf@4.0.3:
|
||||
dependencies:
|
||||
http-errors: 2.0.1
|
||||
@@ -26573,11 +26401,6 @@ snapshots:
|
||||
d3-transition: 3.0.1(d3-selection@3.0.0)
|
||||
d3-zoom: 3.0.0
|
||||
|
||||
d@1.0.2:
|
||||
dependencies:
|
||||
es5-ext: 0.10.64
|
||||
type: 2.7.3
|
||||
|
||||
dagre-d3-es@7.0.14:
|
||||
dependencies:
|
||||
d3: 7.9.0
|
||||
@@ -26633,10 +26456,6 @@ snapshots:
|
||||
dependencies:
|
||||
ms: 2.0.0
|
||||
|
||||
debug@4.3.1:
|
||||
dependencies:
|
||||
ms: 2.1.2
|
||||
|
||||
debug@4.3.7:
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
@@ -26846,10 +26665,6 @@ snapshots:
|
||||
domelementtype: 2.3.0
|
||||
domhandler: 5.0.3
|
||||
|
||||
dot-prop@5.3.0:
|
||||
dependencies:
|
||||
is-obj: 2.0.0
|
||||
|
||||
dot-prop@9.0.0:
|
||||
dependencies:
|
||||
type-fest: 4.41.0
|
||||
@@ -26917,14 +26732,6 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
edit-json-file@1.8.1:
|
||||
dependencies:
|
||||
find-value: 1.0.13
|
||||
iterate-object: 1.3.5
|
||||
r-json: 1.3.1
|
||||
set-value: 4.1.0
|
||||
w-json: 1.3.11
|
||||
|
||||
ee-first@1.1.1: {}
|
||||
|
||||
ejs@5.0.1: {}
|
||||
@@ -27314,32 +27121,14 @@ snapshots:
|
||||
|
||||
es-toolkit@1.39.5: {}
|
||||
|
||||
es5-ext@0.10.64:
|
||||
dependencies:
|
||||
es6-iterator: 2.0.3
|
||||
es6-symbol: 3.1.4
|
||||
esniff: 2.0.1
|
||||
next-tick: 1.1.0
|
||||
|
||||
es6-error@4.1.1: {}
|
||||
|
||||
es6-iterator@2.0.3:
|
||||
dependencies:
|
||||
d: 1.0.2
|
||||
es5-ext: 0.10.64
|
||||
es6-symbol: 3.1.4
|
||||
|
||||
es6-promise-pool@2.5.0: {}
|
||||
|
||||
es6-promise@3.3.1: {}
|
||||
|
||||
es6-promise@4.2.8: {}
|
||||
|
||||
es6-symbol@3.1.4:
|
||||
dependencies:
|
||||
d: 1.0.2
|
||||
ext: 1.7.0
|
||||
|
||||
esbuild-loader@4.3.0(webpack@5.101.3(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.27.4)):
|
||||
dependencies:
|
||||
esbuild: 0.25.12
|
||||
@@ -27611,13 +27400,6 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
esniff@2.0.1:
|
||||
dependencies:
|
||||
d: 1.0.2
|
||||
es5-ext: 0.10.64
|
||||
event-emitter: 0.3.5
|
||||
type: 2.7.3
|
||||
|
||||
espree@10.4.0:
|
||||
dependencies:
|
||||
acorn: 8.16.0
|
||||
@@ -27656,11 +27438,6 @@ snapshots:
|
||||
|
||||
ev-emitter@2.1.2: {}
|
||||
|
||||
event-emitter@0.3.5:
|
||||
dependencies:
|
||||
d: 1.0.2
|
||||
es5-ext: 0.10.64
|
||||
|
||||
event-target-shim@5.0.1: {}
|
||||
|
||||
eventemitter3@4.0.7: {}
|
||||
@@ -27829,10 +27606,6 @@ snapshots:
|
||||
ext-list: 2.2.2
|
||||
sort-keys-length: 1.0.1
|
||||
|
||||
ext@1.7.0:
|
||||
dependencies:
|
||||
type: 2.7.3
|
||||
|
||||
extend-shallow@2.0.1:
|
||||
dependencies:
|
||||
is-extendable: 0.1.1
|
||||
@@ -28010,8 +27783,6 @@ snapshots:
|
||||
locate-path: 6.0.0
|
||||
path-exists: 4.0.0
|
||||
|
||||
find-value@1.0.13: {}
|
||||
|
||||
firefox-profile@4.7.0:
|
||||
dependencies:
|
||||
adm-zip: 0.5.16
|
||||
@@ -29030,8 +28801,6 @@ snapshots:
|
||||
|
||||
ip-address@10.1.0: {}
|
||||
|
||||
ip-regex@4.3.0: {}
|
||||
|
||||
ipaddr.js@1.9.1: {}
|
||||
|
||||
ipaddr.js@2.2.0: {}
|
||||
@@ -29175,8 +28944,6 @@ snapshots:
|
||||
|
||||
is-number@7.0.0: {}
|
||||
|
||||
is-obj@2.0.0: {}
|
||||
|
||||
is-path-inside@3.0.3: {}
|
||||
|
||||
is-path-inside@4.0.0: {}
|
||||
@@ -29251,14 +29018,10 @@ snapshots:
|
||||
dependencies:
|
||||
which-typed-array: 1.1.19
|
||||
|
||||
is-typedarray@1.0.0: {}
|
||||
|
||||
is-unicode-supported@0.1.0: {}
|
||||
|
||||
is-unicode-supported@2.1.0: {}
|
||||
|
||||
is-url@1.2.4: {}
|
||||
|
||||
is-weakmap@2.0.2: {}
|
||||
|
||||
is-weakref@1.1.1:
|
||||
@@ -29281,12 +29044,6 @@ snapshots:
|
||||
dependencies:
|
||||
is-inside-container: 1.0.0
|
||||
|
||||
is2@2.0.9:
|
||||
dependencies:
|
||||
deep-is: 0.1.4
|
||||
ip-regex: 4.3.0
|
||||
is-url: 1.2.4
|
||||
|
||||
isarray@0.0.1: {}
|
||||
|
||||
isarray@1.0.0: {}
|
||||
@@ -29320,8 +29077,6 @@ snapshots:
|
||||
html-escaper: 2.0.2
|
||||
istanbul-lib-report: 3.0.1
|
||||
|
||||
iterate-object@1.3.5: {}
|
||||
|
||||
iterator.prototype@1.1.5:
|
||||
dependencies:
|
||||
define-data-property: 1.1.4
|
||||
@@ -29407,6 +29162,8 @@ snapshots:
|
||||
|
||||
js-levenshtein@1.1.6: {}
|
||||
|
||||
js-md5@0.8.3: {}
|
||||
|
||||
js-sha1@0.7.0: {}
|
||||
|
||||
js-sha256@0.11.1: {}
|
||||
@@ -29425,7 +29182,7 @@ snapshots:
|
||||
|
||||
jsdoc-type-pratt-parser@4.1.0: {}
|
||||
|
||||
jsdom@16.7.0(bufferutil@4.0.9)(utf-8-validate@5.0.10):
|
||||
jsdom@16.7.0(bufferutil@4.0.9)(utf-8-validate@6.0.5):
|
||||
dependencies:
|
||||
abab: 2.0.6
|
||||
acorn: 8.15.0
|
||||
@@ -29452,7 +29209,7 @@ snapshots:
|
||||
whatwg-encoding: 1.0.5
|
||||
whatwg-mimetype: 2.3.0
|
||||
whatwg-url: 8.7.0
|
||||
ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)
|
||||
ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||
xml-name-validator: 3.0.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
@@ -30003,10 +29760,6 @@ snapshots:
|
||||
semver: 5.7.2
|
||||
optional: true
|
||||
|
||||
make-dir@3.1.0:
|
||||
dependencies:
|
||||
semver: 6.3.1
|
||||
|
||||
make-dir@4.0.0:
|
||||
dependencies:
|
||||
semver: 7.7.4
|
||||
@@ -30785,8 +30538,6 @@ snapshots:
|
||||
|
||||
ms@2.0.0: {}
|
||||
|
||||
ms@2.1.2: {}
|
||||
|
||||
ms@2.1.3: {}
|
||||
|
||||
msw@2.7.5(@types/node@24.12.0)(typescript@5.9.3):
|
||||
@@ -30898,8 +30649,6 @@ snapshots:
|
||||
|
||||
netmask@2.0.2: {}
|
||||
|
||||
next-tick@1.1.0: {}
|
||||
|
||||
ngraph.events@1.2.2: {}
|
||||
|
||||
nice-try@1.0.5: {}
|
||||
@@ -30939,7 +30688,8 @@ snapshots:
|
||||
|
||||
node-forge@1.3.3: {}
|
||||
|
||||
node-gyp-build@4.8.4: {}
|
||||
node-gyp-build@4.8.4:
|
||||
optional: true
|
||||
|
||||
node-gyp@11.4.2:
|
||||
dependencies:
|
||||
@@ -31680,8 +31430,6 @@ snapshots:
|
||||
dependencies:
|
||||
crc-32: 0.3.0
|
||||
|
||||
png2icons@2.0.1: {}
|
||||
|
||||
pngjs@6.0.0: {}
|
||||
|
||||
pngjs@7.0.0: {}
|
||||
@@ -32151,10 +31899,6 @@ snapshots:
|
||||
|
||||
quickselect@3.0.0: {}
|
||||
|
||||
r-json@1.3.1:
|
||||
dependencies:
|
||||
w-json: 1.3.10
|
||||
|
||||
rand-token@1.0.1: {}
|
||||
|
||||
random-bytes@1.0.0: {}
|
||||
@@ -32387,10 +32131,6 @@ snapshots:
|
||||
dependencies:
|
||||
resolve: 1.22.10
|
||||
|
||||
recursive-readdir@2.2.3:
|
||||
dependencies:
|
||||
minimatch: 3.1.5
|
||||
|
||||
redoc@2.5.1(core-js@3.46.0)(encoding@0.1.13)(mobx@6.15.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(styled-components@6.3.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4)):
|
||||
dependencies:
|
||||
'@redocly/openapi-core': 1.34.5
|
||||
@@ -33238,13 +32978,13 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
simple-websocket@9.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10):
|
||||
simple-websocket@9.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5):
|
||||
dependencies:
|
||||
debug: 4.4.3(supports-color@8.1.1)
|
||||
queue-microtask: 1.2.3
|
||||
randombytes: 2.1.0
|
||||
readable-stream: 3.6.2
|
||||
ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)
|
||||
ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- supports-color
|
||||
@@ -33390,8 +33130,6 @@ snapshots:
|
||||
|
||||
spacetrim@0.11.59: {}
|
||||
|
||||
spawn-command@1.0.0: {}
|
||||
|
||||
spawn-sync@1.0.15:
|
||||
dependencies:
|
||||
concat-stream: 1.6.2
|
||||
@@ -33958,13 +33696,6 @@ snapshots:
|
||||
minizlib: 3.1.0
|
||||
yallist: 5.0.0
|
||||
|
||||
tcp-port-used@1.0.2:
|
||||
dependencies:
|
||||
debug: 4.3.1
|
||||
is2: 2.0.9
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
temp@0.9.4:
|
||||
dependencies:
|
||||
mkdirp: 0.5.6
|
||||
@@ -34232,9 +33963,9 @@ snapshots:
|
||||
- immer
|
||||
- react
|
||||
|
||||
turndown-attendant@0.0.3(bufferutil@4.0.9)(utf-8-validate@5.0.10):
|
||||
turndown-attendant@0.0.3(bufferutil@4.0.9)(utf-8-validate@6.0.5):
|
||||
dependencies:
|
||||
jsdom: 16.7.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)
|
||||
jsdom: 16.7.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||
tape: 4.17.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
@@ -34279,8 +34010,6 @@ snapshots:
|
||||
media-typer: 1.1.0
|
||||
mime-types: 3.0.2
|
||||
|
||||
type@2.7.3: {}
|
||||
|
||||
typed-array-buffer@1.0.3:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
@@ -34314,10 +34043,6 @@ snapshots:
|
||||
possible-typed-array-names: 1.1.0
|
||||
reflect.getprototypeof: 1.0.10
|
||||
|
||||
typedarray-to-buffer@3.1.5:
|
||||
dependencies:
|
||||
is-typedarray: 1.0.0
|
||||
|
||||
typedarray@0.0.6: {}
|
||||
|
||||
typedoc-plugin-missing-exports@4.1.2(typedoc@0.28.18(typescript@5.9.3)):
|
||||
@@ -34475,10 +34200,6 @@ snapshots:
|
||||
dependencies:
|
||||
imurmurhash: 0.1.4
|
||||
|
||||
unique-string@2.0.0:
|
||||
dependencies:
|
||||
crypto-random-string: 2.0.0
|
||||
|
||||
unist-util-find-after@5.0.0:
|
||||
dependencies:
|
||||
'@types/unist': 3.0.3
|
||||
@@ -34620,10 +34341,6 @@ snapshots:
|
||||
execa: 1.0.0
|
||||
mem: 4.3.0
|
||||
|
||||
utf-8-validate@5.0.10:
|
||||
dependencies:
|
||||
node-gyp-build: 4.8.4
|
||||
|
||||
utf-8-validate@6.0.5:
|
||||
dependencies:
|
||||
node-gyp-build: 4.8.4
|
||||
@@ -34844,10 +34561,6 @@ snapshots:
|
||||
'@mapbox/vector-tile': 1.3.1
|
||||
pbf: 3.3.0
|
||||
|
||||
w-json@1.3.10: {}
|
||||
|
||||
w-json@1.3.11: {}
|
||||
|
||||
w3c-hr-time@1.0.2:
|
||||
dependencies:
|
||||
browser-process-hrtime: 1.0.0
|
||||
@@ -35108,17 +34821,6 @@ snapshots:
|
||||
|
||||
websocket-extensions@0.1.4: {}
|
||||
|
||||
websocket@1.0.35:
|
||||
dependencies:
|
||||
bufferutil: 4.0.9
|
||||
debug: 2.6.9
|
||||
es5-ext: 0.10.64
|
||||
typedarray-to-buffer: 3.1.5
|
||||
utf-8-validate: 5.0.10
|
||||
yaeti: 0.0.6
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
webworkify@1.5.0: {}
|
||||
|
||||
whatwg-encoding@1.0.5:
|
||||
@@ -35275,21 +34977,14 @@ snapshots:
|
||||
|
||||
wrappy@1.0.2: {}
|
||||
|
||||
write-file-atomic@3.0.3:
|
||||
dependencies:
|
||||
imurmurhash: 0.1.4
|
||||
is-typedarray: 1.0.0
|
||||
signal-exit: 3.0.7
|
||||
typedarray-to-buffer: 3.1.5
|
||||
|
||||
write-file-atomic@7.0.1:
|
||||
dependencies:
|
||||
signal-exit: 4.1.0
|
||||
|
||||
ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10):
|
||||
ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@6.0.5):
|
||||
optionalDependencies:
|
||||
bufferutil: 4.0.9
|
||||
utf-8-validate: 5.0.10
|
||||
utf-8-validate: 6.0.5
|
||||
|
||||
ws@8.17.1(bufferutil@4.0.9)(utf-8-validate@6.0.5):
|
||||
optionalDependencies:
|
||||
@@ -35375,8 +35070,6 @@ snapshots:
|
||||
- tsx
|
||||
- yaml
|
||||
|
||||
xdg-basedir@4.0.0: {}
|
||||
|
||||
xdg-basedir@5.1.0: {}
|
||||
|
||||
xml-name-validator@3.0.0: {}
|
||||
@@ -35409,8 +35102,6 @@ snapshots:
|
||||
|
||||
y18n@5.0.8: {}
|
||||
|
||||
yaeti@0.0.6: {}
|
||||
|
||||
yallist@3.1.1: {}
|
||||
|
||||
yallist@4.0.0: {}
|
||||
@@ -35487,10 +35178,6 @@ snapshots:
|
||||
buffer-crc32: 0.2.13
|
||||
pend: 1.2.0
|
||||
|
||||
yazl@3.3.1:
|
||||
dependencies:
|
||||
buffer-crc32: 1.0.0
|
||||
|
||||
yn@3.1.1: {}
|
||||
|
||||
yocto-queue@0.1.0: {}
|
||||
@@ -35514,11 +35201,6 @@ snapshots:
|
||||
async: 3.2.6
|
||||
jszip: 3.10.1
|
||||
|
||||
zip-lib@1.3.1:
|
||||
dependencies:
|
||||
yauzl: 3.2.1
|
||||
yazl: 3.3.1
|
||||
|
||||
zip-stream@6.0.1:
|
||||
dependencies:
|
||||
archiver-utils: 5.0.2
|
||||
|
||||
@@ -26,14 +26,24 @@ const filtered = lines.filter(
|
||||
|
||||
let errorIndex = 0;
|
||||
const numbered: string[] = [];
|
||||
const seen = new Set<string>();
|
||||
let skipContinuation = false;
|
||||
|
||||
for (const line of filtered) {
|
||||
if (ERROR_LINE_PATTERN.test(line)) {
|
||||
if (seen.has(line)) {
|
||||
skipContinuation = true;
|
||||
continue;
|
||||
}
|
||||
seen.add(line);
|
||||
skipContinuation = false;
|
||||
errorIndex++;
|
||||
numbered.push(`[${errorIndex}] ${line}`);
|
||||
} else if (line.trim()) {
|
||||
// Continuation line (indented context for multi-line errors)
|
||||
numbered.push(line);
|
||||
if (!skipContinuation) {
|
||||
numbered.push(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user