mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-16 19:57:52 +01:00
desktop: use better-sqlite3 on desktop for SQLite
This commit is contained in:
@@ -23,11 +23,13 @@ import { type RendererGlobalElectronTRPC } from "electron-trpc/src/types";
|
||||
import type { NNCrypto } from "@notesnook/crypto";
|
||||
import { ipcRenderer } from "electron";
|
||||
import { platform } from "os";
|
||||
import sqlite3, { Database } from "better-sqlite3-multiple-ciphers";
|
||||
|
||||
declare global {
|
||||
var os: () => "mas" | ReturnType<typeof platform>;
|
||||
var electronTRPC: RendererGlobalElectronTRPC;
|
||||
var NativeNNCrypto: (new () => NNCrypto) | undefined;
|
||||
var createSQLite3Database: (filename: string) => Database;
|
||||
}
|
||||
|
||||
process.once("loaded", async () => {
|
||||
@@ -41,4 +43,5 @@ process.once("loaded", async () => {
|
||||
});
|
||||
|
||||
globalThis.NativeNNCrypto = require("@notesnook/crypto").NNCrypto;
|
||||
globalThis.createSQLite3Database = (filename) => sqlite3(filename);
|
||||
globalThis.os = () => (MAC_APP_STORE ? "mas" : platform());
|
||||
|
||||
133
apps/web/package-lock.json
generated
133
apps/web/package-lock.json
generated
@@ -59,6 +59,7 @@
|
||||
"immer": "^10.0.3",
|
||||
"katex": "0.16.2",
|
||||
"kysely": "^0.26.3",
|
||||
"libsodium-wrappers": "^0.7.13",
|
||||
"mac-scrollbar": "^0.13.5",
|
||||
"marked": "^4.1.0",
|
||||
"pdfjs-dist": "3.6.172",
|
||||
@@ -70,6 +71,7 @@
|
||||
"react-day-picker": "^8.9.1",
|
||||
"react-dom": "18.2.0",
|
||||
"react-dropzone": "^14.2.3",
|
||||
"react-error-boundary": "^4.0.12",
|
||||
"react-hot-toast": "^2.4.1",
|
||||
"react-loading-skeleton": "^3.3.1",
|
||||
"react-modal": "3.16.1",
|
||||
@@ -101,6 +103,7 @@
|
||||
"@types/wicg-file-system-access": "^2020.9.6",
|
||||
"@vitejs/plugin-react-swc": "3.3.2",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"better-sqlite3-multiple-ciphers": "^9.4.0",
|
||||
"buffer": "^6.0.3",
|
||||
"chalk": "^4.1.0",
|
||||
"cross-env": "^7.0.3",
|
||||
@@ -31951,9 +31954,11 @@
|
||||
"@notesnook/crypto": "file:../../packages/crypto",
|
||||
"@trpc/client": "10.38.3",
|
||||
"@trpc/server": "10.38.3",
|
||||
"better-sqlite3-multiple-ciphers": "^9.4.0",
|
||||
"electron-trpc": "0.5.2",
|
||||
"electron-updater": "6.1.4",
|
||||
"icojs": "^0.17.1",
|
||||
"sodium-native": "^4.0.6",
|
||||
"typed-emitter": "^2.1.0",
|
||||
"yargs": "^17.6.2",
|
||||
"zod": "^3.21.4"
|
||||
@@ -31962,11 +31967,11 @@
|
||||
"@types/node": "18.16.1",
|
||||
"@types/yargs": "^17.0.24",
|
||||
"chokidar": "^3.5.3",
|
||||
"electron": "25.9.8",
|
||||
"electron": "^28.2.1",
|
||||
"electron-builder": "^24.9.1",
|
||||
"esbuild": "^0.17.19",
|
||||
"esbuild": "^0.20.0",
|
||||
"tree-kill": "^1.2.2",
|
||||
"undici": "^5.23.0"
|
||||
"undici": "^6.6.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"dmg-license": "^1.0.11"
|
||||
@@ -38713,6 +38718,17 @@
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/better-sqlite3-multiple-ciphers": {
|
||||
"version": "9.4.1",
|
||||
"resolved": "https://registry.npmjs.org/better-sqlite3-multiple-ciphers/-/better-sqlite3-multiple-ciphers-9.4.1.tgz",
|
||||
"integrity": "sha512-9WIeXiGodJ0bJLLMdxicmGpJHe0ahpiaNC3VLv3QQj8/h4RLOcs4yskecSkSF3Pj/u8f7juYADpdMBvx71HlLQ==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"bindings": "^1.5.0",
|
||||
"prebuild-install": "^7.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/big.js": {
|
||||
"version": "5.2.2",
|
||||
"dev": true,
|
||||
@@ -38721,10 +38737,19 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/bindings": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"file-uri-to-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bl": {
|
||||
"version": "4.1.0",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"buffer": "^5.5.0",
|
||||
"inherits": "^2.0.4",
|
||||
@@ -38733,6 +38758,7 @@
|
||||
},
|
||||
"node_modules/bl/node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"devOptional": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -38748,7 +38774,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
@@ -39343,8 +39368,8 @@
|
||||
},
|
||||
"node_modules/deep-extend": {
|
||||
"version": "0.6.0",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
@@ -39414,8 +39439,8 @@
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "2.0.2",
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -40033,8 +40058,8 @@
|
||||
},
|
||||
"node_modules/expand-template": {
|
||||
"version": "2.0.3",
|
||||
"devOptional": true,
|
||||
"license": "(MIT OR WTFPL)",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
@@ -40150,6 +40175,12 @@
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/file-uri-to-path": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/filelist": {
|
||||
"version": "1.0.4",
|
||||
"dev": true,
|
||||
@@ -40279,8 +40310,8 @@
|
||||
},
|
||||
"node_modules/fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fs-minipass": {
|
||||
"version": "2.1.0",
|
||||
@@ -40439,8 +40470,8 @@
|
||||
},
|
||||
"node_modules/github-from-package": {
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "7.2.3",
|
||||
@@ -40899,8 +40930,8 @@
|
||||
},
|
||||
"node_modules/ini": {
|
||||
"version": "1.3.8",
|
||||
"license": "ISC",
|
||||
"optional": true
|
||||
"devOptional": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/internal-slot": {
|
||||
"version": "1.0.6",
|
||||
@@ -41482,6 +41513,19 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/libsodium": {
|
||||
"version": "0.7.13",
|
||||
"resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.13.tgz",
|
||||
"integrity": "sha512-mK8ju0fnrKXXfleL53vtp9xiPq5hKM0zbDQtcxQIsSmxNgSxqCj6R7Hl9PkrNe2j29T4yoDaF7DJLK9/i5iWUw=="
|
||||
},
|
||||
"node_modules/libsodium-wrappers": {
|
||||
"version": "0.7.13",
|
||||
"resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.13.tgz",
|
||||
"integrity": "sha512-kasvDsEi/r1fMzKouIDv7B8I6vNmknXwGiYodErGuESoFTohGSKZplFtVxZqHaoQ217AynyIFgnOVRitpHs0Qw==",
|
||||
"dependencies": {
|
||||
"libsodium": "^0.7.13"
|
||||
}
|
||||
},
|
||||
"node_modules/lines-and-columns": {
|
||||
"version": "1.2.4",
|
||||
"license": "MIT"
|
||||
@@ -42540,8 +42584,8 @@
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.8",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
@@ -42595,8 +42639,8 @@
|
||||
},
|
||||
"node_modules/mkdirp-classic": {
|
||||
"version": "0.5.3",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/mlly": {
|
||||
"version": "1.4.2",
|
||||
@@ -42644,8 +42688,8 @@
|
||||
},
|
||||
"node_modules/napi-build-utils": {
|
||||
"version": "1.0.2",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/neo-async": {
|
||||
"version": "2.6.2",
|
||||
@@ -42664,8 +42708,8 @@
|
||||
},
|
||||
"node_modules/node-abi": {
|
||||
"version": "3.54.0",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"semver": "^7.3.5"
|
||||
},
|
||||
@@ -42675,8 +42719,8 @@
|
||||
},
|
||||
"node_modules/node-abi/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"devOptional": true,
|
||||
"license": "ISC",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
@@ -42686,8 +42730,8 @@
|
||||
},
|
||||
"node_modules/node-abi/node_modules/semver": {
|
||||
"version": "7.5.4",
|
||||
"devOptional": true,
|
||||
"license": "ISC",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
@@ -42700,8 +42744,8 @@
|
||||
},
|
||||
"node_modules/node-abi/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"license": "ISC",
|
||||
"optional": true
|
||||
"devOptional": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/node-addon-api": {
|
||||
"version": "4.3.0",
|
||||
@@ -43085,8 +43129,8 @@
|
||||
},
|
||||
"node_modules/prebuild-install": {
|
||||
"version": "7.1.1",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.0",
|
||||
"expand-template": "^2.0.3",
|
||||
@@ -43110,6 +43154,7 @@
|
||||
},
|
||||
"node_modules/prebuild-install/node_modules/simple-get": {
|
||||
"version": "4.0.1",
|
||||
"devOptional": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -43125,7 +43170,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"decompress-response": "^6.0.0",
|
||||
"once": "^1.3.1",
|
||||
@@ -43265,8 +43309,8 @@
|
||||
},
|
||||
"node_modules/rc": {
|
||||
"version": "1.2.8",
|
||||
"devOptional": true,
|
||||
"license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"deep-extend": "^0.6.0",
|
||||
"ini": "~1.3.0",
|
||||
@@ -43333,6 +43377,17 @@
|
||||
"react": ">= 16.8 || 18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-error-boundary": {
|
||||
"version": "4.0.13",
|
||||
"resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.13.tgz",
|
||||
"integrity": "sha512-b6PwbdSv8XeOSYvjt8LpgpKrZ0yGdtZokYwkwV2wlcZbxgopHX/hgPl5VgpnoVOWd868n1hktM8Qm4b+02MiLQ==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.13.1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-hot-toast": {
|
||||
"version": "2.4.1",
|
||||
"license": "MIT",
|
||||
@@ -43415,8 +43470,8 @@
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
@@ -43985,6 +44040,7 @@
|
||||
},
|
||||
"node_modules/simple-concat": {
|
||||
"version": "1.0.1",
|
||||
"devOptional": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -43999,8 +44055,7 @@
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/simple-get": {
|
||||
"version": "3.1.1",
|
||||
@@ -44108,8 +44163,8 @@
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
@@ -44241,8 +44296,8 @@
|
||||
},
|
||||
"node_modules/strip-json-comments": {
|
||||
"version": "2.0.1",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -44339,8 +44394,8 @@
|
||||
},
|
||||
"node_modules/tar-fs": {
|
||||
"version": "2.1.1",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"chownr": "^1.1.1",
|
||||
"mkdirp-classic": "^0.5.2",
|
||||
@@ -44350,13 +44405,13 @@
|
||||
},
|
||||
"node_modules/tar-fs/node_modules/chownr": {
|
||||
"version": "1.1.4",
|
||||
"license": "ISC",
|
||||
"optional": true
|
||||
"devOptional": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/tar-stream": {
|
||||
"version": "2.2.0",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"bl": "^4.0.3",
|
||||
"end-of-stream": "^1.4.1",
|
||||
@@ -44574,8 +44629,8 @@
|
||||
},
|
||||
"node_modules/tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
},
|
||||
@@ -44918,8 +44973,8 @@
|
||||
},
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
"immer": "^10.0.3",
|
||||
"katex": "0.16.2",
|
||||
"kysely": "^0.26.3",
|
||||
"libsodium-wrappers": "^0.7.13",
|
||||
"mac-scrollbar": "^0.13.5",
|
||||
"marked": "^4.1.0",
|
||||
"pdfjs-dist": "3.6.172",
|
||||
@@ -68,6 +69,7 @@
|
||||
"react-day-picker": "^8.9.1",
|
||||
"react-dom": "18.2.0",
|
||||
"react-dropzone": "^14.2.3",
|
||||
"react-error-boundary": "^4.0.12",
|
||||
"react-hot-toast": "^2.4.1",
|
||||
"react-loading-skeleton": "^3.3.1",
|
||||
"react-modal": "3.16.1",
|
||||
@@ -99,6 +101,7 @@
|
||||
"@types/wicg-file-system-access": "^2020.9.6",
|
||||
"@vitejs/plugin-react-swc": "3.3.2",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"better-sqlite3-multiple-ciphers": "^9.4.0",
|
||||
"buffer": "^6.0.3",
|
||||
"chalk": "^4.1.0",
|
||||
"cross-env": "^7.0.3",
|
||||
|
||||
@@ -21,17 +21,12 @@ import { EventSourcePolyfill as EventSource } from "event-source-polyfill";
|
||||
import { DatabasePersistence, NNStorage } from "../interfaces/storage";
|
||||
import { logger } from "../utils/logger";
|
||||
import { showMigrationDialog } from "./dialog-controller";
|
||||
// import { SQLocalKysely } from "sqlocal/kysely";
|
||||
import { WaSqliteWorkerDriver } from "./sqlite/sqlite.kysely";
|
||||
import { SqliteAdapter, SqliteQueryCompiler, SqliteIntrospector } from "kysely";
|
||||
import { database } from "@notesnook/common";
|
||||
// import SQLiteESMFactory from "./sqlite/wa-sqlite-async";
|
||||
// import * as SQLite from "./sqlite/sqlite-api";
|
||||
// import { IDBBatchAtomicVFS } from "./sqlite/IDBBatchAtomicVFS";
|
||||
import { createDialect } from "./sqlite";
|
||||
import { isFeatureSupported } from "../utils/feature-check";
|
||||
|
||||
const db = database;
|
||||
async function initializeDatabase(persistence: DatabasePersistence) {
|
||||
console.log("initi");
|
||||
logger.measure("Database initialization");
|
||||
|
||||
const { FileStorage } = await import("../interfaces/fs");
|
||||
@@ -49,21 +44,21 @@ async function initializeDatabase(persistence: DatabasePersistence) {
|
||||
});
|
||||
|
||||
const storage = new NNStorage("Notesnook", KeyChain, persistence);
|
||||
await storage.migrate();
|
||||
|
||||
database.setup({
|
||||
sqliteOptions: {
|
||||
dialect: (name) => ({
|
||||
createDriver: () =>
|
||||
new WaSqliteWorkerDriver({ async: true, dbName: name }),
|
||||
createAdapter: () => new SqliteAdapter(),
|
||||
createIntrospector: (db) => new SqliteIntrospector(db),
|
||||
createQueryCompiler: () => new SqliteQueryCompiler()
|
||||
}),
|
||||
journalMode: "MEMORY",
|
||||
dialect: createDialect,
|
||||
...(isFeatureSupported("opfs")
|
||||
? { journalMode: "WAL" }
|
||||
: {
|
||||
journalMode: "MEMORY",
|
||||
lockingMode: "exclusive"
|
||||
}),
|
||||
tempStore: "memory",
|
||||
synchronous: "normal",
|
||||
pageSize: 8192,
|
||||
cacheSize: -16000,
|
||||
lockingMode: "exclusive",
|
||||
password: databaseKey
|
||||
},
|
||||
storage: storage,
|
||||
|
||||
@@ -61,6 +61,9 @@ export class AccessHandlePoolVFS extends VFS.Base {
|
||||
// The OPFS files all have randomly-generated names that do not match
|
||||
// the SQLite files whose data they contain. This map links those names
|
||||
// with their respective OPFS access handles.
|
||||
/**
|
||||
* @type {Map<FileSystemSyncAccessHandle, string>}
|
||||
*/
|
||||
#mapAccessHandleToName = new Map();
|
||||
|
||||
// When a SQLite file is associated with an OPFS file, that association
|
||||
@@ -209,6 +212,16 @@ export class AccessHandlePoolVFS extends VFS.Base {
|
||||
await this.#releaseAccessHandles();
|
||||
}
|
||||
|
||||
async delete() {
|
||||
console.log("CLSOGING");
|
||||
await this.close();
|
||||
console.log("CLSOGING", this.#directoryHandle);
|
||||
for await (const [name] of this.#directoryHandle) {
|
||||
console.log("DELETING", name);
|
||||
await this.#directoryHandle.removeEntry(name, { recursive: true });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Release and reacquire all OPFS access handles. This must be called
|
||||
* and awaited before any SQLite call that uses the VFS and also before
|
||||
|
||||
@@ -1,22 +1,4 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* eslint-disable header/header */
|
||||
// Copyright 2022 Roy T. Hashimoto. All Rights Reserved.
|
||||
import * as VFS from "./VFS.js";
|
||||
import { WebLocksExclusive as WebLocks } from "./WebLocks.js";
|
||||
@@ -77,6 +59,12 @@ export class IDBBatchAtomicVFS extends VFS.Base {
|
||||
#taskTimestamp = performance.now();
|
||||
#pendingAsync = new Set();
|
||||
|
||||
// Asyncify can grow WebAssembly memory during an asynchronous call.
|
||||
// If this happens, then any array buffer arguments will be detached.
|
||||
// The workaround is when finding a detached buffer, set this handler
|
||||
// function to process the new buffer outside handlerAsync().
|
||||
#growthHandler = null;
|
||||
|
||||
constructor(idbDatabaseName = "wa-sqlite", options = DEFAULT_OPTIONS) {
|
||||
super();
|
||||
this.name = idbDatabaseName;
|
||||
@@ -86,6 +74,11 @@ export class IDBBatchAtomicVFS extends VFS.Base {
|
||||
});
|
||||
}
|
||||
|
||||
async delete() {
|
||||
await this.close();
|
||||
await deleteDatabase(this.name);
|
||||
}
|
||||
|
||||
async close() {
|
||||
for (const fileId of this.#mapIdToFile.keys()) {
|
||||
await this.xClose(fileId);
|
||||
@@ -103,7 +96,7 @@ export class IDBBatchAtomicVFS extends VFS.Base {
|
||||
* @returns {number}
|
||||
*/
|
||||
xOpen(name, fileId, flags, pOutFlags) {
|
||||
return this.handleAsync(async () => {
|
||||
const result = this.handleAsync(async () => {
|
||||
if (name === null) name = `null_${fileId}`;
|
||||
log(`xOpen ${name} 0x${fileId.toString(16)} 0x${flags.toString(16)}`);
|
||||
|
||||
@@ -137,6 +130,14 @@ export class IDBBatchAtomicVFS extends VFS.Base {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
if (pOutFlags.buffer.detached || !pOutFlags.buffer.byteLength) {
|
||||
pOutFlags = new DataView(new ArrayBuffer(4));
|
||||
this.#growthHandler = (pOutFlagsNew) => {
|
||||
pOutFlagsNew.setInt32(0, pOutFlags.getInt32(0, true), true);
|
||||
};
|
||||
}
|
||||
pOutFlags.setInt32(0, flags & VFS.SQLITE_OPEN_READONLY, true);
|
||||
return VFS.SQLITE_OK;
|
||||
} catch (e) {
|
||||
@@ -144,6 +145,10 @@ export class IDBBatchAtomicVFS extends VFS.Base {
|
||||
return VFS.SQLITE_CANTOPEN;
|
||||
}
|
||||
});
|
||||
|
||||
this.#growthHandler?.(pOutFlags);
|
||||
this.#growthHandler = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,7 +184,8 @@ export class IDBBatchAtomicVFS extends VFS.Base {
|
||||
* @returns {number}
|
||||
*/
|
||||
xRead(fileId, pData, iOffset) {
|
||||
return this.handleAsync(async () => {
|
||||
const byteLength = pData.byteLength;
|
||||
const result = this.handleAsync(async () => {
|
||||
const file = this.#mapIdToFile.get(fileId);
|
||||
log(`xRead ${file.path} ${pData.byteLength} ${iOffset}`);
|
||||
|
||||
@@ -189,6 +195,15 @@ export class IDBBatchAtomicVFS extends VFS.Base {
|
||||
// one case - rollback after journal spill - where reads cross
|
||||
// write boundaries so we have to allow for that.
|
||||
const result = await this.#idb.run("readonly", async ({ blocks }) => {
|
||||
// @ts-ignore
|
||||
if (pData.buffer.detached || !pData.buffer.byteLength) {
|
||||
// WebAssembly memory has grown, invalidating our buffer. Use
|
||||
// a temporary buffer and copy after this asynchronous call
|
||||
// completes.
|
||||
pData = new Uint8Array(byteLength);
|
||||
this.#growthHandler = (pDataNew) => pDataNew.set(pData);
|
||||
}
|
||||
|
||||
let pDataOffset = 0;
|
||||
while (pDataOffset < pData.byteLength) {
|
||||
// Fetch the IndexedDB block for this file location.
|
||||
@@ -223,6 +238,10 @@ export class IDBBatchAtomicVFS extends VFS.Base {
|
||||
return VFS.SQLITE_IOERR;
|
||||
}
|
||||
});
|
||||
|
||||
this.#growthHandler?.(pData);
|
||||
this.#growthHandler = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -244,7 +263,7 @@ export class IDBBatchAtomicVFS extends VFS.Base {
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve));
|
||||
|
||||
const result = this.#xWriteHelper(fileId, pData, iOffset);
|
||||
const result = this.#xWriteHelper(fileId, pData.slice(), iOffset);
|
||||
this.#taskTimestamp = performance.now();
|
||||
return result;
|
||||
});
|
||||
@@ -452,6 +471,7 @@ export class IDBBatchAtomicVFS extends VFS.Base {
|
||||
return this.handleAsync(async () => {
|
||||
const file = this.#mapIdToFile.get(fileId);
|
||||
log(`xUnlock ${file.path} ${flags}`);
|
||||
|
||||
try {
|
||||
return file.locks.unlock(flags);
|
||||
} catch (e) {
|
||||
@@ -467,14 +487,26 @@ export class IDBBatchAtomicVFS extends VFS.Base {
|
||||
* @returns {number}
|
||||
*/
|
||||
xCheckReservedLock(fileId, pResOut) {
|
||||
return this.handleAsync(async () => {
|
||||
const result = this.handleAsync(async () => {
|
||||
const file = this.#mapIdToFile.get(fileId);
|
||||
log(`xCheckReservedLock ${file.path}`);
|
||||
|
||||
const isReserved = await file.locks.isSomewhereReserved();
|
||||
|
||||
// @ts-ignore
|
||||
if (pResOut.buffer.detached || !pResOut.buffer.byteLength) {
|
||||
pResOut = new DataView(new ArrayBuffer(4));
|
||||
this.#growthHandler = (pResOutNew) => {
|
||||
pResOutNew.setInt32(0, pResOut.getInt32(0, true), true);
|
||||
};
|
||||
}
|
||||
pResOut.setInt32(0, isReserved ? 1 : 0, true);
|
||||
return VFS.SQLITE_OK;
|
||||
});
|
||||
|
||||
this.#growthHandler?.(pResOut);
|
||||
this.#growthHandler = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -649,7 +681,7 @@ export class IDBBatchAtomicVFS extends VFS.Base {
|
||||
* @returns {number}
|
||||
*/
|
||||
xAccess(name, flags, pResOut) {
|
||||
return this.handleAsync(async () => {
|
||||
const result = this.handleAsync(async () => {
|
||||
try {
|
||||
if (name.includes("-journal") || name.includes("-wal")) {
|
||||
pResOut.setInt32(0, 0, true);
|
||||
@@ -663,6 +695,14 @@ export class IDBBatchAtomicVFS extends VFS.Base {
|
||||
const key = await this.#idb.run("readonly", ({ blocks }) => {
|
||||
return blocks.getKey(this.#bound({ path }, 0));
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
if (pResOut.buffer.detached || !pResOut.buffer.byteLength) {
|
||||
pResOut = new DataView(new ArrayBuffer(4));
|
||||
this.#growthHandler = (pResOutNew) => {
|
||||
pResOutNew.setInt32(0, pResOut.getInt32(0, true), true);
|
||||
};
|
||||
}
|
||||
pResOut.setInt32(0, key ? 1 : 0, true);
|
||||
return VFS.SQLITE_OK;
|
||||
} catch (e) {
|
||||
@@ -670,6 +710,10 @@ export class IDBBatchAtomicVFS extends VFS.Base {
|
||||
return VFS.SQLITE_IOERR;
|
||||
}
|
||||
});
|
||||
|
||||
this.#growthHandler?.(pResOut);
|
||||
this.#growthHandler = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -867,6 +911,18 @@ export class IDBBatchAtomicVFS extends VFS.Base {
|
||||
}
|
||||
}
|
||||
|
||||
function deleteDatabase(idbDatabaseName) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = globalThis.indexedDB.deleteDatabase(idbDatabaseName);
|
||||
request.addEventListener("success", () => {
|
||||
resolve();
|
||||
});
|
||||
request.addEventListener("error", () => {
|
||||
reject(request.error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function openDatabase(idbDatabaseName) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = globalThis.indexedDB.open(idbDatabaseName, 5);
|
||||
|
||||
58
apps/web/src/common/sqlite/index.desktop.ts
Normal file
58
apps/web/src/common/sqlite/index.desktop.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
SqliteDriver as KSqliteDriver,
|
||||
SqliteDialectConfig,
|
||||
Dialect,
|
||||
SqliteAdapter,
|
||||
SqliteIntrospector,
|
||||
SqliteQueryCompiler
|
||||
} from "kysely";
|
||||
import { desktop } from "../desktop-bridge";
|
||||
|
||||
class SqliteDriver extends KSqliteDriver {
|
||||
constructor(private readonly config: SqliteDialectConfig & { name: string }) {
|
||||
super(config);
|
||||
}
|
||||
async delete() {
|
||||
const path = await desktop!.integration.resolvePath.query({
|
||||
filePath: `userData/${this.config.name}.sql`
|
||||
});
|
||||
await desktop?.integration.deleteFile.query(path);
|
||||
}
|
||||
}
|
||||
|
||||
export const createDialect = (name: string): Dialect => {
|
||||
return {
|
||||
createDriver: () =>
|
||||
new SqliteDriver({
|
||||
name,
|
||||
database: async () => {
|
||||
const path = await desktop!.integration.resolvePath.query({
|
||||
filePath: `userData/${name}.sql`
|
||||
});
|
||||
return window.createSQLite3Database(path).unsafeMode(true);
|
||||
}
|
||||
}),
|
||||
createAdapter: () => new SqliteAdapter(),
|
||||
createIntrospector: (db) => new SqliteIntrospector(db),
|
||||
createQueryCompiler: () => new SqliteQueryCompiler()
|
||||
};
|
||||
};
|
||||
46
apps/web/src/common/sqlite/index.ts
Normal file
46
apps/web/src/common/sqlite/index.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
SqliteAdapter,
|
||||
SqliteQueryCompiler,
|
||||
SqliteIntrospector,
|
||||
Dialect
|
||||
} from "kysely";
|
||||
import { WaSqliteWorkerDriver } from "./wa-sqlite-kysely-driver";
|
||||
import { isFeatureSupported } from "../../utils/feature-check";
|
||||
|
||||
declare module "kysely" {
|
||||
interface Driver {
|
||||
delete(): Promise<void>;
|
||||
}
|
||||
}
|
||||
|
||||
export const createDialect = (name: string): Dialect => {
|
||||
return {
|
||||
createDriver: () =>
|
||||
new WaSqliteWorkerDriver({
|
||||
async: isFeatureSupported("opfs") ? false : true,
|
||||
dbName: name
|
||||
}),
|
||||
createAdapter: () => new SqliteAdapter(),
|
||||
createIntrospector: (db) => new SqliteIntrospector(db),
|
||||
createQueryCompiler: () => new SqliteQueryCompiler()
|
||||
};
|
||||
};
|
||||
@@ -34,7 +34,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* each element converted to a byte); SQLite always returns blob data as
|
||||
* `Uint8Array`
|
||||
*/
|
||||
type SQLiteCompatibleType =
|
||||
export type SQLiteCompatibleType =
|
||||
| number
|
||||
| string
|
||||
| Uint8Array
|
||||
@@ -58,7 +58,7 @@ type SQLiteCompatibleType =
|
||||
* @see https://sqlite.org/vfs.html
|
||||
* @see https://sqlite.org/c3ref/io_methods.html
|
||||
*/
|
||||
declare interface SQLiteVFS {
|
||||
export interface SQLiteVFS {
|
||||
/** Maximum length of a file path in UTF-8 bytes (default 64) */
|
||||
mxPathName?: number;
|
||||
|
||||
@@ -115,7 +115,7 @@ declare interface SQLiteVFS {
|
||||
* {@link SQLiteModule.xBestIndex}
|
||||
* @see https://sqlite.org/c3ref/index_info.html
|
||||
*/
|
||||
declare interface SQLiteModuleIndexInfo {
|
||||
export interface SQLiteModuleIndexInfo {
|
||||
nConstraint: number;
|
||||
aConstraint: Array<{
|
||||
iColumn: number;
|
||||
@@ -152,13 +152,13 @@ declare interface SQLiteModuleIndexInfo {
|
||||
*
|
||||
* @see https://sqlite.org/vtab.html
|
||||
*/
|
||||
declare interface SQLiteModule {
|
||||
export interface SQLiteModule {
|
||||
/**
|
||||
* @see https://sqlite.org/vtab.html#the_xcreate_method
|
||||
*/
|
||||
xCreate?(
|
||||
db: number,
|
||||
appData,
|
||||
appData: any,
|
||||
argv: string[],
|
||||
pVTab: number,
|
||||
pzErr: DataView
|
||||
@@ -169,7 +169,7 @@ declare interface SQLiteModule {
|
||||
*/
|
||||
xConnect(
|
||||
db: number,
|
||||
appData,
|
||||
appData: any,
|
||||
argv: string[],
|
||||
pVTab: number,
|
||||
pzErr: DataView
|
||||
@@ -304,7 +304,7 @@ declare interface SQLiteModule {
|
||||
*
|
||||
* @see https://sqlite.org/c3ref/funclist.html
|
||||
*/
|
||||
declare interface SQLiteAPI {
|
||||
export interface SQLiteAPI {
|
||||
/**
|
||||
* Bind a collection of values to a statement
|
||||
*
|
||||
@@ -466,7 +466,7 @@ declare interface SQLiteAPI {
|
||||
* @param db database pointer
|
||||
* @returns number of rows modified
|
||||
*/
|
||||
changes(db): number;
|
||||
changes(db: number): number;
|
||||
|
||||
/**
|
||||
* Close database connection
|
||||
@@ -474,7 +474,7 @@ declare interface SQLiteAPI {
|
||||
* @param db database pointer
|
||||
* @returns `SQLITE_OK` (throws exception on error)
|
||||
*/
|
||||
close(db): Promise<number>;
|
||||
close(db: number): Promise<number>;
|
||||
|
||||
/**
|
||||
* Call the appropriate `column_*` function based on the column type
|
||||
@@ -625,7 +625,7 @@ declare interface SQLiteAPI {
|
||||
db: number,
|
||||
zName: string,
|
||||
module: SQLiteModule,
|
||||
appData?
|
||||
appData?: any
|
||||
): number;
|
||||
|
||||
/**
|
||||
@@ -783,8 +783,8 @@ declare interface SQLiteAPI {
|
||||
db: number,
|
||||
nProgressOps: number,
|
||||
handler: (userData: any) => number,
|
||||
userData
|
||||
);
|
||||
userData: any
|
||||
): any;
|
||||
|
||||
/**
|
||||
* Reset a prepared statement object
|
||||
@@ -1082,645 +1082,3 @@ declare interface SQLiteAPI {
|
||||
*/
|
||||
vfs_register(vfs: SQLiteVFS, makeDefault?: boolean): number;
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
declare module "wa-sqlite/src/sqlite-constants.js" {
|
||||
export const SQLITE_OK: 0;
|
||||
export const SQLITE_ERROR: 1;
|
||||
export const SQLITE_INTERNAL: 2;
|
||||
export const SQLITE_PERM: 3;
|
||||
export const SQLITE_ABORT: 4;
|
||||
export const SQLITE_BUSY: 5;
|
||||
export const SQLITE_LOCKED: 6;
|
||||
export const SQLITE_NOMEM: 7;
|
||||
export const SQLITE_READONLY: 8;
|
||||
export const SQLITE_INTERRUPT: 9;
|
||||
export const SQLITE_IOERR: 10;
|
||||
export const SQLITE_CORRUPT: 11;
|
||||
export const SQLITE_NOTFOUND: 12;
|
||||
export const SQLITE_FULL: 13;
|
||||
export const SQLITE_CANTOPEN: 14;
|
||||
export const SQLITE_PROTOCOL: 15;
|
||||
export const SQLITE_EMPTY: 16;
|
||||
export const SQLITE_SCHEMA: 17;
|
||||
export const SQLITE_TOOBIG: 18;
|
||||
export const SQLITE_CONSTRAINT: 19;
|
||||
export const SQLITE_MISMATCH: 20;
|
||||
export const SQLITE_MISUSE: 21;
|
||||
export const SQLITE_NOLFS: 22;
|
||||
export const SQLITE_AUTH: 23;
|
||||
export const SQLITE_FORMAT: 24;
|
||||
export const SQLITE_RANGE: 25;
|
||||
export const SQLITE_NOTADB: 26;
|
||||
export const SQLITE_NOTICE: 27;
|
||||
export const SQLITE_WARNING: 28;
|
||||
export const SQLITE_ROW: 100;
|
||||
export const SQLITE_DONE: 101;
|
||||
export const SQLITE_IOERR_ACCESS: 3338;
|
||||
export const SQLITE_IOERR_CHECKRESERVEDLOCK: 3594;
|
||||
export const SQLITE_IOERR_CLOSE: 4106;
|
||||
export const SQLITE_IOERR_DATA: 8202;
|
||||
export const SQLITE_IOERR_DELETE: 2570;
|
||||
export const SQLITE_IOERR_DELETE_NOENT: 5898;
|
||||
export const SQLITE_IOERR_DIR_FSYNC: 1290;
|
||||
export const SQLITE_IOERR_FSTAT: 1802;
|
||||
export const SQLITE_IOERR_FSYNC: 1034;
|
||||
export const SQLITE_IOERR_GETTEMPPATH: 6410;
|
||||
export const SQLITE_IOERR_LOCK: 3850;
|
||||
export const SQLITE_IOERR_NOMEM: 3082;
|
||||
export const SQLITE_IOERR_READ: 266;
|
||||
export const SQLITE_IOERR_RDLOCK: 2314;
|
||||
export const SQLITE_IOERR_SEEK: 5642;
|
||||
export const SQLITE_IOERR_SHORT_READ: 522;
|
||||
export const SQLITE_IOERR_TRUNCATE: 1546;
|
||||
export const SQLITE_IOERR_UNLOCK: 2058;
|
||||
export const SQLITE_IOERR_VNODE: 6922;
|
||||
export const SQLITE_IOERR_WRITE: 778;
|
||||
export const SQLITE_IOERR_BEGIN_ATOMIC: 7434;
|
||||
export const SQLITE_IOERR_COMMIT_ATOMIC: 7690;
|
||||
export const SQLITE_IOERR_ROLLBACK_ATOMIC: 7946;
|
||||
export const SQLITE_CONSTRAINT_CHECK: 275;
|
||||
export const SQLITE_CONSTRAINT_COMMITHOOK: 531;
|
||||
export const SQLITE_CONSTRAINT_FOREIGNKEY: 787;
|
||||
export const SQLITE_CONSTRAINT_FUNCTION: 1043;
|
||||
export const SQLITE_CONSTRAINT_NOTNULL: 1299;
|
||||
export const SQLITE_CONSTRAINT_PINNED: 2835;
|
||||
export const SQLITE_CONSTRAINT_PRIMARYKEY: 1555;
|
||||
export const SQLITE_CONSTRAINT_ROWID: 2579;
|
||||
export const SQLITE_CONSTRAINT_TRIGGER: 1811;
|
||||
export const SQLITE_CONSTRAINT_UNIQUE: 2067;
|
||||
export const SQLITE_CONSTRAINT_VTAB: 2323;
|
||||
export const SQLITE_OPEN_READONLY: 1;
|
||||
export const SQLITE_OPEN_READWRITE: 2;
|
||||
export const SQLITE_OPEN_CREATE: 4;
|
||||
export const SQLITE_OPEN_DELETEONCLOSE: 8;
|
||||
export const SQLITE_OPEN_EXCLUSIVE: 16;
|
||||
export const SQLITE_OPEN_AUTOPROXY: 32;
|
||||
export const SQLITE_OPEN_URI: 64;
|
||||
export const SQLITE_OPEN_MEMORY: 128;
|
||||
export const SQLITE_OPEN_MAIN_DB: 256;
|
||||
export const SQLITE_OPEN_TEMP_DB: 512;
|
||||
export const SQLITE_OPEN_TRANSIENT_DB: 1024;
|
||||
export const SQLITE_OPEN_MAIN_JOURNAL: 2048;
|
||||
export const SQLITE_OPEN_TEMP_JOURNAL: 4096;
|
||||
export const SQLITE_OPEN_SUBJOURNAL: 8192;
|
||||
export const SQLITE_OPEN_SUPER_JOURNAL: 16384;
|
||||
export const SQLITE_OPEN_NOMUTEX: 32768;
|
||||
export const SQLITE_OPEN_FULLMUTEX: 65536;
|
||||
export const SQLITE_OPEN_SHAREDCACHE: 131072;
|
||||
export const SQLITE_OPEN_PRIVATECACHE: 262144;
|
||||
export const SQLITE_OPEN_WAL: 524288;
|
||||
export const SQLITE_OPEN_NOFOLLOW: 16777216;
|
||||
export const SQLITE_LOCK_NONE: 0;
|
||||
export const SQLITE_LOCK_SHARED: 1;
|
||||
export const SQLITE_LOCK_RESERVED: 2;
|
||||
export const SQLITE_LOCK_PENDING: 3;
|
||||
export const SQLITE_LOCK_EXCLUSIVE: 4;
|
||||
export const SQLITE_IOCAP_ATOMIC: 1;
|
||||
export const SQLITE_IOCAP_ATOMIC512: 2;
|
||||
export const SQLITE_IOCAP_ATOMIC1K: 4;
|
||||
export const SQLITE_IOCAP_ATOMIC2K: 8;
|
||||
export const SQLITE_IOCAP_ATOMIC4K: 16;
|
||||
export const SQLITE_IOCAP_ATOMIC8K: 32;
|
||||
export const SQLITE_IOCAP_ATOMIC16K: 64;
|
||||
export const SQLITE_IOCAP_ATOMIC32K: 128;
|
||||
export const SQLITE_IOCAP_ATOMIC64K: 256;
|
||||
export const SQLITE_IOCAP_SAFE_APPEND: 512;
|
||||
export const SQLITE_IOCAP_SEQUENTIAL: 1024;
|
||||
export const SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN: 2048;
|
||||
export const SQLITE_IOCAP_POWERSAFE_OVERWRITE: 4096;
|
||||
export const SQLITE_IOCAP_IMMUTABLE: 8192;
|
||||
export const SQLITE_IOCAP_BATCH_ATOMIC: 16384;
|
||||
export const SQLITE_ACCESS_EXISTS: 0;
|
||||
export const SQLITE_ACCESS_READWRITE: 1;
|
||||
export const SQLITE_ACCESS_READ: 2;
|
||||
export const SQLITE_FCNTL_LOCKSTATE: 1;
|
||||
export const SQLITE_FCNTL_GET_LOCKPROXYFILE: 2;
|
||||
export const SQLITE_FCNTL_SET_LOCKPROXYFILE: 3;
|
||||
export const SQLITE_FCNTL_LAST_ERRNO: 4;
|
||||
export const SQLITE_FCNTL_SIZE_HINT: 5;
|
||||
export const SQLITE_FCNTL_CHUNK_SIZE: 6;
|
||||
export const SQLITE_FCNTL_FILE_POINTER: 7;
|
||||
export const SQLITE_FCNTL_SYNC_OMITTED: 8;
|
||||
export const SQLITE_FCNTL_WIN32_AV_RETRY: 9;
|
||||
export const SQLITE_FCNTL_PERSIST_WAL: 10;
|
||||
export const SQLITE_FCNTL_OVERWRITE: 11;
|
||||
export const SQLITE_FCNTL_VFSNAME: 12;
|
||||
export const SQLITE_FCNTL_POWERSAFE_OVERWRITE: 13;
|
||||
export const SQLITE_FCNTL_PRAGMA: 14;
|
||||
export const SQLITE_FCNTL_BUSYHANDLER: 15;
|
||||
export const SQLITE_FCNTL_TEMPFILENAME: 16;
|
||||
export const SQLITE_FCNTL_MMAP_SIZE: 18;
|
||||
export const SQLITE_FCNTL_TRACE: 19;
|
||||
export const SQLITE_FCNTL_HAS_MOVED: 20;
|
||||
export const SQLITE_FCNTL_SYNC: 21;
|
||||
export const SQLITE_FCNTL_COMMIT_PHASETWO: 22;
|
||||
export const SQLITE_FCNTL_WIN32_SET_HANDLE: 23;
|
||||
export const SQLITE_FCNTL_WAL_BLOCK: 24;
|
||||
export const SQLITE_FCNTL_ZIPVFS: 25;
|
||||
export const SQLITE_FCNTL_RBU: 26;
|
||||
export const SQLITE_FCNTL_VFS_POINTER: 27;
|
||||
export const SQLITE_FCNTL_JOURNAL_POINTER: 28;
|
||||
export const SQLITE_FCNTL_WIN32_GET_HANDLE: 29;
|
||||
export const SQLITE_FCNTL_PDB: 30;
|
||||
export const SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: 31;
|
||||
export const SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: 32;
|
||||
export const SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: 33;
|
||||
export const SQLITE_FCNTL_LOCK_TIMEOUT: 34;
|
||||
export const SQLITE_FCNTL_DATA_VERSION: 35;
|
||||
export const SQLITE_FCNTL_SIZE_LIMIT: 36;
|
||||
export const SQLITE_FCNTL_CKPT_DONE: 37;
|
||||
export const SQLITE_FCNTL_RESERVE_BYTES: 38;
|
||||
export const SQLITE_FCNTL_CKPT_START: 39;
|
||||
export const SQLITE_INTEGER: 1;
|
||||
export const SQLITE_FLOAT: 2;
|
||||
export const SQLITE_TEXT: 3;
|
||||
export const SQLITE_BLOB: 4;
|
||||
export const SQLITE_NULL: 5;
|
||||
export const SQLITE_STATIC: 0;
|
||||
export const SQLITE_TRANSIENT: -1;
|
||||
export const SQLITE_UTF8: 1;
|
||||
export const SQLITE_UTF16LE: 2;
|
||||
export const SQLITE_UTF16BE: 3;
|
||||
export const SQLITE_UTF16: 4;
|
||||
export const SQLITE_INDEX_CONSTRAINT_EQ: 2;
|
||||
export const SQLITE_INDEX_CONSTRAINT_GT: 4;
|
||||
export const SQLITE_INDEX_CONSTRAINT_LE: 8;
|
||||
export const SQLITE_INDEX_CONSTRAINT_LT: 16;
|
||||
export const SQLITE_INDEX_CONSTRAINT_GE: 32;
|
||||
export const SQLITE_INDEX_CONSTRAINT_MATCH: 64;
|
||||
export const SQLITE_INDEX_CONSTRAINT_LIKE: 65;
|
||||
export const SQLITE_INDEX_CONSTRAINT_GLOB: 66;
|
||||
export const SQLITE_INDEX_CONSTRAINT_REGEXP: 67;
|
||||
export const SQLITE_INDEX_CONSTRAINT_NE: 68;
|
||||
export const SQLITE_INDEX_CONSTRAINT_ISNOT: 69;
|
||||
export const SQLITE_INDEX_CONSTRAINT_ISNOTNULL: 70;
|
||||
export const SQLITE_INDEX_CONSTRAINT_ISNULL: 71;
|
||||
export const SQLITE_INDEX_CONSTRAINT_IS: 72;
|
||||
export const SQLITE_INDEX_CONSTRAINT_FUNCTION: 150;
|
||||
export const SQLITE_INDEX_SCAN_UNIQUE: 1;
|
||||
export const SQLITE_DETERMINISTIC: 0x000000800;
|
||||
export const SQLITE_DIRECTONLY: 0x000080000;
|
||||
export const SQLITE_SUBTYPE: 0x000100000;
|
||||
export const SQLITE_INNOCUOUS: 0x000200000;
|
||||
export const SQLITE_SYNC_NORMAL: 0x00002;
|
||||
export const SQLITE_SYNC_FULL: 0x00003;
|
||||
export const SQLITE_SYNC_DATAONLY: 0x00010;
|
||||
export const SQLITE_CREATE_INDEX: 1;
|
||||
export const SQLITE_CREATE_TABLE: 2;
|
||||
export const SQLITE_CREATE_TEMP_INDEX: 3;
|
||||
export const SQLITE_CREATE_TEMP_TABLE: 4;
|
||||
export const SQLITE_CREATE_TEMP_TRIGGER: 5;
|
||||
export const SQLITE_CREATE_TEMP_VIEW: 6;
|
||||
export const SQLITE_CREATE_TRIGGER: 7;
|
||||
export const SQLITE_CREATE_VIEW: 8;
|
||||
export const SQLITE_DELETE: 9;
|
||||
export const SQLITE_DROP_INDEX: 10;
|
||||
export const SQLITE_DROP_TABLE: 11;
|
||||
export const SQLITE_DROP_TEMP_INDEX: 12;
|
||||
export const SQLITE_DROP_TEMP_TABLE: 13;
|
||||
export const SQLITE_DROP_TEMP_TRIGGER: 14;
|
||||
export const SQLITE_DROP_TEMP_VIEW: 15;
|
||||
export const SQLITE_DROP_TRIGGER: 16;
|
||||
export const SQLITE_DROP_VIEW: 17;
|
||||
export const SQLITE_INSERT: 18;
|
||||
export const SQLITE_PRAGMA: 19;
|
||||
export const SQLITE_READ: 20;
|
||||
export const SQLITE_SELECT: 21;
|
||||
export const SQLITE_TRANSACTION: 22;
|
||||
export const SQLITE_UPDATE: 23;
|
||||
export const SQLITE_ATTACH: 24;
|
||||
export const SQLITE_DETACH: 25;
|
||||
export const SQLITE_ALTER_TABLE: 26;
|
||||
export const SQLITE_REINDEX: 27;
|
||||
export const SQLITE_ANALYZE: 28;
|
||||
export const SQLITE_CREATE_VTABLE: 29;
|
||||
export const SQLITE_DROP_VTABLE: 30;
|
||||
export const SQLITE_FUNCTION: 31;
|
||||
export const SQLITE_SAVEPOINT: 32;
|
||||
export const SQLITE_COPY: 0;
|
||||
export const SQLITE_RECURSIVE: 33;
|
||||
export const SQLITE_DENY: 1;
|
||||
export const SQLITE_IGNORE: 2;
|
||||
export const SQLITE_LIMIT_LENGTH: 0;
|
||||
export const SQLITE_LIMIT_SQL_LENGTH: 1;
|
||||
export const SQLITE_LIMIT_COLUMN: 2;
|
||||
export const SQLITE_LIMIT_EXPR_DEPTH: 3;
|
||||
export const SQLITE_LIMIT_COMPOUND_SELECT: 4;
|
||||
export const SQLITE_LIMIT_VDBE_OP: 5;
|
||||
export const SQLITE_LIMIT_FUNCTION_ARG: 6;
|
||||
export const SQLITE_LIMIT_ATTACHED: 7;
|
||||
export const SQLITE_LIMIT_LIKE_PATTERN_LENGTH: 8;
|
||||
export const SQLITE_LIMIT_VARIABLE_NUMBER: 9;
|
||||
export const SQLITE_LIMIT_TRIGGER_DEPTH: 10;
|
||||
export const SQLITE_LIMIT_WORKER_THREADS: 11;
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
declare module "wa-sqlite" {
|
||||
export * from "wa-sqlite/src/sqlite-constants.js";
|
||||
|
||||
/**
|
||||
* Builds a Javascript API from the Emscripten module. This API is still
|
||||
* low-level and closely corresponds to the C API exported by the module,
|
||||
* but differs in some specifics like throwing exceptions on errors.
|
||||
* @param {*} Module SQLite module
|
||||
* @returns {SQLiteAPI}
|
||||
*/
|
||||
export function Factory(Module: any): SQLiteAPI;
|
||||
|
||||
export class SQLiteError extends Error {
|
||||
constructor(message: any, code: any);
|
||||
code: any;
|
||||
}
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
declare module "wa-sqlite/dist/wa-sqlite.mjs" {
|
||||
function ModuleFactory(config?: object): Promise<any>;
|
||||
export = ModuleFactory;
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
declare module "wa-sqlite/dist/wa-sqlite-async.mjs" {
|
||||
function ModuleFactory(config?: object): Promise<any>;
|
||||
export = ModuleFactory;
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
declare module "wa-sqlite/src/VFS.js" {
|
||||
export * from "wa-sqlite/src/sqlite-constants.js";
|
||||
|
||||
export class Base {
|
||||
mxPathName: number;
|
||||
/**
|
||||
* @param {number} fileId
|
||||
* @returns {number|Promise<number>}
|
||||
*/
|
||||
xClose(fileId: number): number;
|
||||
/**
|
||||
* @param {number} fileId
|
||||
* @param {Uint8Array} pData
|
||||
* @param {number} iOffset
|
||||
* @returns {number}
|
||||
*/
|
||||
xRead(
|
||||
fileId: number,
|
||||
pData: {
|
||||
size: number;
|
||||
value: Uint8Array;
|
||||
},
|
||||
iOffset: number
|
||||
): number;
|
||||
/**
|
||||
* @param {number} fileId
|
||||
* @param {Uint8Array} pData
|
||||
* @param {number} iOffset
|
||||
* @returns {number}
|
||||
*/
|
||||
xWrite(
|
||||
fileId: number,
|
||||
pData: {
|
||||
size: number;
|
||||
value: Uint8Array;
|
||||
},
|
||||
iOffset: number
|
||||
): number;
|
||||
/**
|
||||
* @param {number} fileId
|
||||
* @param {number} iSize
|
||||
* @returns {number}
|
||||
*/
|
||||
xTruncate(fileId: number, iSize: number): number;
|
||||
/**
|
||||
* @param {number} fileId
|
||||
* @param {*} flags
|
||||
* @returns {number}
|
||||
*/
|
||||
xSync(fileId: number, flags: any): number;
|
||||
/**
|
||||
* @param {number} fileId
|
||||
* @param {DataView} pSize64
|
||||
* @returns {number|Promise<number>}
|
||||
*/
|
||||
xFileSize(fileId: number, pSize64: DataView): number;
|
||||
/**
|
||||
* @param {number} fileId
|
||||
* @param {number} flags
|
||||
* @returns {number}
|
||||
*/
|
||||
xLock(fileId: number, flags: number): number;
|
||||
/**
|
||||
* @param {number} fileId
|
||||
* @param {number} flags
|
||||
* @returns {number}
|
||||
*/
|
||||
xUnlock(fileId: number, flags: number): number;
|
||||
/**
|
||||
* @param {number} fileId
|
||||
* @param {DataView} pResOut
|
||||
* @returns {number}
|
||||
*/
|
||||
xCheckReservedLock(fileId: number, pResOut: DataView): number;
|
||||
/**
|
||||
* @param {number} fileId
|
||||
* @param {number} flags
|
||||
* @param {DataView} pArg
|
||||
* @returns {number}
|
||||
*/
|
||||
xFileControl(fileId: number, flags: number, pArg: DataView): number;
|
||||
/**
|
||||
* @param {number} fileId
|
||||
* @returns {number}
|
||||
*/
|
||||
xSectorSize(fileId: number): number;
|
||||
/**
|
||||
* @param {number} fileId
|
||||
* @returns {number}
|
||||
*/
|
||||
xDeviceCharacteristics(fileId: number): number;
|
||||
/**
|
||||
* @param {string?} name
|
||||
* @param {number} fileId
|
||||
* @param {number} flags
|
||||
* @param {DataView} pOutFlags
|
||||
* @returns {number}
|
||||
*/
|
||||
xOpen(
|
||||
name: string | null,
|
||||
fileId: number,
|
||||
flags: number,
|
||||
pOutFlags: DataView
|
||||
): number;
|
||||
/**
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {number} syncDir
|
||||
* @returns {number}
|
||||
*/
|
||||
xDelete(name: string, syncDir: number): number;
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {number} flags
|
||||
* @param {DataView} pResOut
|
||||
* @returns {number}
|
||||
*/
|
||||
xAccess(name: string, flags: number, pResOut: DataView): number;
|
||||
/**
|
||||
* Handle asynchronous operation. This implementation will be overriden on
|
||||
* registration by an Asyncify build.
|
||||
* @param {function(): Promise<number>} f
|
||||
* @returns {number}
|
||||
*/
|
||||
handleAsync(f: () => Promise<number>): number;
|
||||
}
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
declare module "wa-sqlite/src/examples/ArrayModule.js" {
|
||||
export class ArrayModule {
|
||||
/**
|
||||
* @param {SQLiteAPI} sqlite3
|
||||
* @param {number} db
|
||||
* @param {Array<Array>} rows Table data.
|
||||
* @param {Array<string>} columns Column names.
|
||||
*/
|
||||
constructor(
|
||||
sqlite3: any,
|
||||
db: number,
|
||||
rows: Array<any[]>,
|
||||
columns: Array<string>
|
||||
);
|
||||
mapCursorToState: Map<any, any>;
|
||||
sqlite3: any;
|
||||
db: number;
|
||||
rows: any[][];
|
||||
columns: string[];
|
||||
/**
|
||||
* @param {number} db
|
||||
* @param {*} appData Application data passed to `SQLiteAPI.create_module`.
|
||||
* @param {Array<string>} argv
|
||||
* @param {number} pVTab
|
||||
* @param {{ set: function(string): void}} pzErr
|
||||
* @returns {number|Promise<number>}
|
||||
*/
|
||||
xCreate(
|
||||
db: number,
|
||||
appData: any,
|
||||
argv: Array<string>,
|
||||
pVTab: number,
|
||||
pzErr: {
|
||||
set: (arg0: string) => void;
|
||||
}
|
||||
): number | Promise<number>;
|
||||
/**
|
||||
* @param {number} db
|
||||
* @param {*} appData Application data passed to `SQLiteAPI.create_module`.
|
||||
* @param {Array<string>} argv
|
||||
* @param {number} pVTab
|
||||
* @param {{ set: function(string): void}} pzErr
|
||||
* @returns {number|Promise<number>}
|
||||
*/
|
||||
xConnect(
|
||||
db: number,
|
||||
appData: any,
|
||||
argv: Array<string>,
|
||||
pVTab: number,
|
||||
pzErr: {
|
||||
set: (arg0: string) => void;
|
||||
}
|
||||
): number | Promise<number>;
|
||||
/**
|
||||
* @param {number} pVTab
|
||||
* @param {SQLiteModuleIndexInfo} indexInfo
|
||||
* @returns {number|Promise<number>}
|
||||
*/
|
||||
xBestIndex(pVTab: number, indexInfo: any): number | Promise<number>;
|
||||
/**
|
||||
* @param {number} pVTab
|
||||
* @returns {number|Promise<number>}
|
||||
*/
|
||||
xDisconnect(pVTab: number): number | Promise<number>;
|
||||
/**
|
||||
* @param {number} pVTab
|
||||
* @returns {number|Promise<number>}
|
||||
*/
|
||||
xDestroy(pVTab: number): number | Promise<number>;
|
||||
/**
|
||||
* @param {number} pVTab
|
||||
* @param {number} pCursor
|
||||
* @returns {number|Promise<number>}
|
||||
*/
|
||||
xOpen(pVTab: number, pCursor: number): number | Promise<number>;
|
||||
/**
|
||||
* @param {number} pCursor
|
||||
* @returns {number|Promise<number>}
|
||||
*/
|
||||
xClose(pCursor: number): number | Promise<number>;
|
||||
/**
|
||||
* @param {number} pCursor
|
||||
* @param {number} idxNum
|
||||
* @param {string?} idxStr
|
||||
* @param {Array<number>} values
|
||||
* @returns {number|Promise<number>}
|
||||
*/
|
||||
xFilter(
|
||||
pCursor: number,
|
||||
idxNum: number,
|
||||
idxStr: string | null,
|
||||
values: Array<number>
|
||||
): number | Promise<number>;
|
||||
/**
|
||||
* @param {number} pCursor
|
||||
* @returns {number|Promise<number>}
|
||||
*/
|
||||
xNext(pCursor: number): number | Promise<number>;
|
||||
/**
|
||||
* @param {number} pCursor
|
||||
* @returns {number|Promise<number>}
|
||||
*/
|
||||
xEof(pCursor: number): number | Promise<number>;
|
||||
/**
|
||||
* @param {number} pCursor
|
||||
* @param {number} pContext
|
||||
* @param {number} iCol
|
||||
* @returns {number|Promise<number>}
|
||||
*/
|
||||
xColumn(
|
||||
pCursor: number,
|
||||
pContext: number,
|
||||
iCol: number
|
||||
): number | Promise<number>;
|
||||
/**
|
||||
* @param {number} pCursor
|
||||
* @param {{ set: function(number): void}} pRowid
|
||||
* @returns {number|Promise<number>}
|
||||
*/
|
||||
xRowid(
|
||||
pCursor: number,
|
||||
pRowid: {
|
||||
set: (arg0: number) => void;
|
||||
}
|
||||
): number | Promise<number>;
|
||||
/**
|
||||
* @param {number} pVTab
|
||||
* @param {Array<number>} values sqlite3_value pointers
|
||||
* @param {{ set: function(number): void}} pRowid
|
||||
* @returns {number|Promise<number>}
|
||||
*/
|
||||
xUpdate(
|
||||
pVTab: number,
|
||||
values: Array<number>,
|
||||
pRowid: {
|
||||
set: (arg0: number) => void;
|
||||
}
|
||||
): number | Promise<number>;
|
||||
}
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
declare module "wa-sqlite/src/examples/ArrayAsyncModule.js" {
|
||||
import { ArrayModule } from "wa-sqlite/src/examples/ArrayModule.js";
|
||||
export class ArrayAsyncModule extends ArrayModule {
|
||||
/**
|
||||
* @param {function} f
|
||||
* @returns {Promise<number>}
|
||||
*/
|
||||
handleAsync(f: Function): Promise<number>;
|
||||
}
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
declare module "wa-sqlite/src/examples/IndexedDbVFS.js" {
|
||||
import * as VFS from "wa-sqlite/src/VFS.js";
|
||||
export class IndexedDbVFS extends VFS.Base {
|
||||
/**
|
||||
* @param {string} idbName Name of IndexedDB database.
|
||||
*/
|
||||
constructor(idbName?: string);
|
||||
name: string;
|
||||
mapIdToFile: Map<any, any>;
|
||||
cacheSize: number;
|
||||
db: any;
|
||||
close(): Promise<void>;
|
||||
/**
|
||||
* Delete a file from IndexedDB.
|
||||
* @param {string} name
|
||||
*/
|
||||
deleteFile(name: string): Promise<void>;
|
||||
/**
|
||||
* Forcibly clear an orphaned file lock.
|
||||
* @param {string} name
|
||||
*/
|
||||
forceClearLock(name: string): Promise<void>;
|
||||
_getStore(mode?: string): any;
|
||||
/**
|
||||
* Returns the key for file metadata.
|
||||
* @param {string} name
|
||||
* @returns
|
||||
*/
|
||||
_metaKey(name: string): string;
|
||||
/**
|
||||
* Returns the key for file block data.
|
||||
* @param {string} name
|
||||
* @param {number} index
|
||||
* @returns
|
||||
*/
|
||||
_blockKey(name: string, index: number): string;
|
||||
_getBlock(store: any, file: any, index: any): Promise<any>;
|
||||
_putBlock(store: any, file: any, index: any, blockData: any): void;
|
||||
_purgeCache(store: any, file: any, size?: number): void;
|
||||
_flushCache(store: any, file: any): Promise<void>;
|
||||
_sync(file: any): Promise<void>;
|
||||
/**
|
||||
* Helper function that deletes all keys greater or equal to `key`
|
||||
* provided they start with `prefix`.
|
||||
* @param {string} key
|
||||
* @param {string} [prefix]
|
||||
* @returns
|
||||
*/
|
||||
_delete(key: string, prefix?: string): Promise<any>;
|
||||
}
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
declare module "wa-sqlite/src/examples/MemoryVFS.js" {
|
||||
import * as VFS from "wa-sqlite/src/VFS.js";
|
||||
export class MemoryVFS extends VFS.Base {
|
||||
name: string;
|
||||
mapNameToFile: Map<any, any>;
|
||||
mapIdToFile: Map<any, any>;
|
||||
}
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
declare module "wa-sqlite/src/examples/MemoryAsyncVFS.js" {
|
||||
import { MemoryVFS } from "wa-sqlite/src/examples/MemoryVFS.js";
|
||||
export class MemoryAsyncVFS extends MemoryVFS {}
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
declare module "wa-sqlite/src/examples/tag.js" {
|
||||
/**
|
||||
* Template tag builder. This function creates a tag with an API and
|
||||
* database from the same module, then the tag can be used like this:
|
||||
* ```
|
||||
* const sql = tag(sqlite3, db);
|
||||
* const results = await sql`
|
||||
* SELECT 1 + 1;
|
||||
* SELECT 6 * 7;
|
||||
* `;
|
||||
* ```
|
||||
* The returned Promise value contains an array of results for each
|
||||
* SQL statement that produces output. Each result is an object with
|
||||
* properties `columns` (array of names) and `rows` (array of array
|
||||
* of values).
|
||||
* @param {SQLiteAPI} sqlite3
|
||||
* @param {number} db
|
||||
* @returns {function(TemplateStringsArray, ...any): Promise<object[]>}
|
||||
*/
|
||||
export function tag(
|
||||
sqlite3: any,
|
||||
db: number
|
||||
): (arg0: TemplateStringsArray, ...args: any[]) => Promise<object[]>;
|
||||
}
|
||||
@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// import type { SQLiteAPI, SQLiteCompatibleType } from "./index.d.ts";
|
||||
import type { SQLiteAPI, SQLiteCompatibleType } from "./sqlite-types";
|
||||
import { Factory, SQLITE_ROW } from "./sqlite-api";
|
||||
import SQLiteAsyncESMFactory from "./wa-sqlite-async";
|
||||
import SQLiteSyncESMFactory from "./wa-sqlite";
|
||||
@@ -48,7 +48,7 @@ async function init(dbName: string, async: boolean, url?: string) {
|
||||
? new IDBBatchAtomicVFS(dbName, { durability: "strict" })
|
||||
: new AccessHandlePoolVFS(dbName);
|
||||
if ("isReady" in vfs) await vfs.isReady;
|
||||
|
||||
console.log(vfs, SQLiteAsyncModule);
|
||||
sqlite.vfs_register(vfs, false);
|
||||
db = await sqlite.open_v2(dbName, undefined, `multipleciphers-${vfs.name}`);
|
||||
}
|
||||
@@ -138,11 +138,16 @@ async function exportDatabase(dbName: string, async: boolean) {
|
||||
return transfer(stream, [stream]);
|
||||
}
|
||||
|
||||
async function deleteDatabase() {
|
||||
await vfs?.delete();
|
||||
}
|
||||
|
||||
const worker = {
|
||||
close,
|
||||
init,
|
||||
run: exec,
|
||||
export: exportDatabase
|
||||
export: exportDatabase,
|
||||
delete: deleteDatabase
|
||||
};
|
||||
|
||||
export type SQLiteWorker = typeof worker;
|
||||
|
||||
@@ -78,6 +78,11 @@ export class WaSqliteWorkerDriver implements Driver {
|
||||
return await this.worker.close();
|
||||
}
|
||||
|
||||
async delete() {
|
||||
console.log("DELETING");
|
||||
return this.worker.delete();
|
||||
}
|
||||
|
||||
async export() {
|
||||
return this.worker.export(this.config.dbName, this.config.async);
|
||||
}
|
||||
164
apps/web/src/components/error-boundary/index.tsx
Normal file
164
apps/web/src/components/error-boundary/index.tsx
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { PropsWithChildren } from "react";
|
||||
import { ErrorText } from "../error-text";
|
||||
import { BaseThemeProvider } from "../theme-provider";
|
||||
import { Button, Flex, Image, Text } from "@theme-ui/components";
|
||||
import {
|
||||
ErrorBoundary as RErrorBoundary,
|
||||
FallbackProps
|
||||
} from "react-error-boundary";
|
||||
import Logo from "../../assets/logo.svg";
|
||||
import LogoDark from "../../assets/logo-dark.svg";
|
||||
import { useStore as useThemeStore } from "../../stores/theme-store";
|
||||
import { createDialect } from "../../common/sqlite";
|
||||
import { getDeviceInfo } from "../../dialogs/issue-dialog";
|
||||
|
||||
export function ErrorBoundary(props: PropsWithChildren) {
|
||||
return (
|
||||
<RErrorBoundary FallbackComponent={ErrorComponent}>
|
||||
{props.children}
|
||||
</RErrorBoundary>
|
||||
);
|
||||
}
|
||||
|
||||
export function ErrorComponent({ error, resetErrorBoundary }: FallbackProps) {
|
||||
const help = getErrorHelp({ error, resetErrorBoundary });
|
||||
const colorScheme = useThemeStore((store) => store.colorScheme);
|
||||
|
||||
return (
|
||||
<BaseThemeProvider
|
||||
onRender={() => document.getElementById("splash")?.remove()}
|
||||
addGlobalStyles
|
||||
sx={{
|
||||
height: "100%",
|
||||
bg: "background",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
overflowY: "auto"
|
||||
}}
|
||||
>
|
||||
<Flex
|
||||
sx={{
|
||||
width: ["95%", "50%"],
|
||||
flexDirection: "column"
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
src={colorScheme === "dark" ? LogoDark : Logo}
|
||||
sx={{ borderRadius: "default", width: 60, alignSelf: "start" }}
|
||||
mb={4}
|
||||
/>
|
||||
<Text
|
||||
variant="heading"
|
||||
sx={{ borderBottom: "1px solid var(--border)", pb: 1 }}
|
||||
>
|
||||
Something went wrong
|
||||
</Text>
|
||||
<ErrorText error={error} />
|
||||
{help ? (
|
||||
<>
|
||||
<Text variant="subtitle" sx={{ mt: 2 }}>
|
||||
What went wrong?
|
||||
</Text>
|
||||
<Text variant="body">{help.explanation}</Text>
|
||||
<Text variant="subtitle" sx={{ mt: 1 }}>
|
||||
How to fix it?
|
||||
</Text>
|
||||
<Text variant="body">{help.action}</Text>
|
||||
<Flex sx={{ gap: 1 }}>
|
||||
<Button
|
||||
variant="error"
|
||||
sx={{ alignSelf: "start", px: 30, mt: 1 }}
|
||||
onClick={() => help.fix().catch((e) => alert(e))}
|
||||
>
|
||||
Fix it
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
sx={{ alignSelf: "start", px: 30, mt: 1 }}
|
||||
onClick={() => {
|
||||
const mailto = new URL("mailto:support@streetwriters.co");
|
||||
mailto.searchParams.set(
|
||||
"body",
|
||||
`${
|
||||
error instanceof Error
|
||||
? error.stack
|
||||
: -typeof error
|
||||
? error
|
||||
: JSON.stringify(error)
|
||||
}
|
||||
|
||||
---
|
||||
Device information:
|
||||
|
||||
${getDeviceInfo()}`
|
||||
);
|
||||
window.open(mailto.toString(), "_blank");
|
||||
}}
|
||||
>
|
||||
Contact support
|
||||
</Button>
|
||||
</Flex>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Button
|
||||
variant="secondary"
|
||||
sx={{ alignSelf: "start", px: 30, mt: 1 }}
|
||||
onClick={() =>
|
||||
window.open("mailto:support@streetwriters.co", "_blank")
|
||||
}
|
||||
>
|
||||
Contact support
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
</BaseThemeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
function getErrorHelp(props: FallbackProps) {
|
||||
const { error, resetErrorBoundary } = props;
|
||||
const errorText =
|
||||
typeof error === "string"
|
||||
? error
|
||||
: error instanceof Error
|
||||
? error.toString()
|
||||
: JSON.stringify(error);
|
||||
if (errorText.includes("file is not a database")) {
|
||||
return {
|
||||
explanation: `This error usually means the database file is either corrupt or it could not be decrypted.`,
|
||||
action:
|
||||
"This error can only be fixed by wiping & reseting the database. Beware that this will wipe all your data inside the database with no way to recover it later on.",
|
||||
fix: async () => {
|
||||
const dialect = createDialect("notesnook");
|
||||
const driver = dialect.createDriver();
|
||||
if (!IS_DESKTOP_APP) await driver.init();
|
||||
await driver.delete();
|
||||
await driver.destroy();
|
||||
resetErrorBoundary();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -19,9 +19,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { Flex, FlexProps, Text } from "@theme-ui/components";
|
||||
|
||||
import { Error } from "../icons";
|
||||
import { Error as ErrorIcon } from "../icons";
|
||||
|
||||
type ErrorTextProps = { error?: string | null | false } & FlexProps;
|
||||
type ErrorTextProps = { error?: string | Error | null | false } & FlexProps;
|
||||
export function ErrorText(props: ErrorTextProps) {
|
||||
const { error, sx, ...restProps } = props;
|
||||
|
||||
@@ -34,9 +34,14 @@ export function ErrorText(props: ErrorTextProps) {
|
||||
sx={{ borderRadius: "default", ...sx }}
|
||||
{...restProps}
|
||||
>
|
||||
<Error size={15} color="var(--icon-error)" />
|
||||
<Text variant={"error"} ml={1}>
|
||||
{error}
|
||||
<ErrorIcon size={15} color="var(--icon-error)" />
|
||||
<Text
|
||||
className="selectable"
|
||||
variant={"error"}
|
||||
ml={1}
|
||||
sx={{ whiteSpace: "pre-wrap" }}
|
||||
>
|
||||
{error instanceof Error ? <>{error.stack}</> : error}
|
||||
</Text>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
6
apps/web/src/global.d.ts
vendored
6
apps/web/src/global.d.ts
vendored
@@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import "vite/client";
|
||||
import "vite-plugin-svgr/client";
|
||||
import "@notesnook/desktop/dist/preload";
|
||||
|
||||
declare global {
|
||||
var PUBLIC_URL: string;
|
||||
@@ -32,11 +33,6 @@ declare global {
|
||||
var APP_TITLE: string;
|
||||
var IS_THEME_BUILDER: boolean;
|
||||
|
||||
interface Window {
|
||||
os?: () => NodeJS.Platform | "mas";
|
||||
NativeNNCrypto?: new () => import("@notesnook/crypto").NNCrypto;
|
||||
}
|
||||
|
||||
interface AuthenticationExtensionsClientInputs {
|
||||
prf?: {
|
||||
eval: {
|
||||
|
||||
@@ -24,35 +24,41 @@ import { AppEventManager, AppEvents } from "./common/app-events";
|
||||
import { BaseThemeProvider } from "./components/theme-provider";
|
||||
import { register } from "./utils/stream-saver/mitm";
|
||||
import { getServiceWorkerVersion } from "./utils/version";
|
||||
import { ErrorBoundary, ErrorComponent } from "./components/error-boundary";
|
||||
|
||||
renderApp();
|
||||
|
||||
async function renderApp() {
|
||||
const { component, props, path } = await init();
|
||||
|
||||
if (serviceWorkerWhitelist.includes(path)) await initializeServiceWorker();
|
||||
if (IS_DESKTOP_APP) {
|
||||
const { loadDatabase } = await import("./hooks/use-database");
|
||||
await loadDatabase("db");
|
||||
}
|
||||
|
||||
const { default: Component } = await component();
|
||||
const rootElement = document.getElementById("root");
|
||||
if (!rootElement) return;
|
||||
|
||||
const { default: AppLock } = await import("./views/app-lock");
|
||||
const root = createRoot(rootElement);
|
||||
root.render(
|
||||
<BaseThemeProvider
|
||||
onRender={() => document.getElementById("splash")?.remove()}
|
||||
addGlobalStyles
|
||||
sx={{ height: "100%" }}
|
||||
>
|
||||
<AppLock>
|
||||
<Component route={props?.route || "login:email"} />
|
||||
</AppLock>
|
||||
</BaseThemeProvider>
|
||||
);
|
||||
|
||||
try {
|
||||
const { component, props, path } = await init();
|
||||
|
||||
if (serviceWorkerWhitelist.includes(path)) await initializeServiceWorker();
|
||||
|
||||
const { default: Component } = await component();
|
||||
|
||||
const { default: AppLock } = await import("./views/app-lock");
|
||||
root.render(
|
||||
<ErrorBoundary>
|
||||
<BaseThemeProvider
|
||||
onRender={() => document.getElementById("splash")?.remove()}
|
||||
addGlobalStyles
|
||||
sx={{ height: "100%", bg: "background" }}
|
||||
>
|
||||
<AppLock>
|
||||
<Component route={props?.route || "login:email"} />
|
||||
</AppLock>
|
||||
</BaseThemeProvider>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
} catch (e) {
|
||||
root.render(
|
||||
<ErrorComponent error={e} resetErrorBoundary={() => renderApp()} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const serviceWorkerWhitelist: Routes[] = ["default"];
|
||||
|
||||
@@ -88,10 +88,14 @@ export default defineConfig({
|
||||
|
||||
alias: [
|
||||
{
|
||||
find: /desktop-bridge/gm,
|
||||
find: /\/desktop-bridge$/gm,
|
||||
replacement: isDesktop
|
||||
? "desktop-bridge/index.desktop"
|
||||
: "desktop-bridge/index"
|
||||
? "/desktop-bridge/index.desktop"
|
||||
: "/desktop-bridge/index"
|
||||
},
|
||||
{
|
||||
find: /\/sqlite$/gm,
|
||||
replacement: isDesktop ? "/sqlite/index.desktop" : "/sqlite/index"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user