Drop existing offline search index to fix broken state

See #9295

Close #9314

Co-authored-by: ivk <ivk@tutao.de>
This commit is contained in:
hrb-hub 2025-07-17 17:57:30 +02:00 committed by ivk
parent 8c3bb93113
commit dad5a892c2
9 changed files with 93 additions and 4 deletions

View file

@ -16,6 +16,7 @@ import { domainConfigs } from "./DomainConfigs.js"
import commonjs from "@rollup/plugin-commonjs"
import { nodeGypPlugin } from "./nodeGypPlugin.js"
import { napiPlugin } from "./napiPlugin.js"
import replace from "@rollup/plugin-replace"
const exec = util.promisify(cp.exec)
const buildSrc = dirname(fileURLToPath(import.meta.url))
@ -142,6 +143,11 @@ async function rollupDesktop(dirname, outDir, version, platform, architecture, d
},
preserveEntrySignatures: false,
plugins: [
replace({
// AppType.Integrated
// see src/common/misc/ClientConstants.ts
APP_TYPE: JSON.stringify("0"),
}),
nodeGypPlugin({
rootDir: projectRoot,
platform: platform,

View file

@ -18,6 +18,16 @@ import { napiPlugin } from "./napiPlugin.js"
const buildSrc = dirname(fileURLToPath(import.meta.url))
const projectRoot = path.resolve(path.join(buildSrc, ".."))
/**
* @param stage
* @param host
* @param desktop
* @param clean
* @param ignoreMigrations
* @param networkDebugging
* @param app {"mail"|"calendar"}
* @returns {Promise<void>}
*/
export async function runDevBuild({ stage, host, desktop, clean, ignoreMigrations, networkDebugging, app }) {
const isCalendarBuild = app === "calendar"
const tsConfig = isCalendarBuild ? "tsconfig-calendar-app.json" : "tsconfig.json"
@ -93,7 +103,7 @@ export async function runDevBuild({ stage, host, desktop, clean, ignoreMigration
* @param p.version {string}
* @param p.domainConfigs {DomainConfigMap}
* @param p.networkDebugging {boolean}
* @param p.app {string}
* @param p.app {"mail"|"calendar"}
* @return {Promise<void>}
*/
async function buildWebPart({ stage, host, version, domainConfigs, networkDebugging, app }) {
@ -110,6 +120,8 @@ async function buildWebPart({ stage, host, version, domainConfigs, networkDebugg
define: {
// Need it at least until inlining enums is supported
LOAD_ASSERTIONS: "false",
// see AppType in src/common/misc/ClientConstants.ts
APP_TYPE: JSON.stringify(app === "calendar" ? "2" : "1"),
},
external: "fs", // qrcode-svg tries to import it on save()
plugins: [

View file

@ -15,6 +15,7 @@ import { createHtml } from "./createHtml.js"
import { domainConfigs } from "./DomainConfigs.js"
import { visualizer } from "rollup-plugin-visualizer"
import { rollupWasmLoader } from "@tutao/tuta-wasm-loader"
import replace from "@rollup/plugin-replace"
/**
* Builds the web app for production.
@ -89,6 +90,10 @@ export async function buildWebapp({ version, stage, host, measure, minify, proje
analyzer(projectDir, buildDir),
visualizer({ filename: `${buildDir}/stats.html`, gzipSize: true }),
bundleDependencyCheckPlugin(),
replace({
// see AppType in src/common/misc/ClientConstants.ts
APP_TYPE: JSON.stringify(app === "calendar" ? "2" : "1"),
}),
nodeResolve({
preferBuiltins: true,
resolveOnly: [/^@tutao\/.*$/],

23
package-lock.json generated
View file

@ -51,6 +51,7 @@
"@rollup/plugin-commonjs": "26.0.1",
"@rollup/plugin-json": "6.1.0",
"@rollup/plugin-node-resolve": "15.2.3",
"@rollup/plugin-replace": "^6.0.2",
"@rollup/plugin-terser": "0.4.4",
"@rollup/plugin-typescript": "12.1.2",
"@tutao/licc": "299.250715.0",
@ -3420,6 +3421,28 @@
}
}
},
"node_modules/@rollup/plugin-replace": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-6.0.2.tgz",
"integrity": "sha512-7QaYCf8bqF04dOy7w/eHmJeNExxTYwvKAmlSAH/EaWWUzbT0h5sbF6bktFoX/0F/0qwng5/dWFMyf3gzaM8DsQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@rollup/pluginutils": "^5.0.1",
"magic-string": "^0.30.3"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
},
"peerDependenciesMeta": {
"rollup": {
"optional": true
}
}
},
"node_modules/@rollup/plugin-node-resolve/node_modules/builtin-modules": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",

View file

@ -75,6 +75,7 @@
"@rollup/plugin-commonjs": "26.0.1",
"@rollup/plugin-json": "6.1.0",
"@rollup/plugin-node-resolve": "15.2.3",
"@rollup/plugin-replace": "^6.0.2",
"@rollup/plugin-terser": "0.4.4",
"@rollup/plugin-typescript": "12.1.2",
"@tutao/licc": "299.250715.0",

View file

@ -4,6 +4,7 @@ import { SqlCipherFacade } from "../../../native/common/generatedipc/SqlCipherFa
import { OutOfSyncError } from "../../common/error/OutOfSyncError.js"
import { offline5 } from "./migrations/offline-v5.js"
import { offline6 } from "./migrations/offline-v6.js"
import { offline7 } from "./migrations/offline-v7"
export interface OfflineMigration {
readonly version: number
@ -17,11 +18,11 @@ export interface OfflineMigration {
* Normally you should only add them to the end of the list but with offline ones it can be a bit tricky since they change the db structure itself so sometimes
* they should rather be in the beginning.
*/
export const OFFLINE_STORAGE_MIGRATIONS: ReadonlyArray<OfflineMigration> = [offline5, offline6]
export const OFFLINE_STORAGE_MIGRATIONS: ReadonlyArray<OfflineMigration> = [offline5, offline6, offline7]
// in cases where the actual migration is not there anymore (we clean up old migrations no client would apply anymore)
// and we create a new offline database, we still need to set the offline version to the current value.
export const CURRENT_OFFLINE_VERSION = 6
export const CURRENT_OFFLINE_VERSION = 7
/**
* Migrator for the offline storage between different versions of model. It is tightly couples to the versions of API entities: every time we make an

View file

@ -0,0 +1,38 @@
import { OfflineStorage } from "../OfflineStorage.js"
import { SqlCipherFacade } from "../../../../native/common/generatedipc/SqlCipherFacade.js"
import { OfflineMigration } from "../OfflineStorageMigrator.js"
import { AppType } from "../../../../misc/ClientConstants"
import { NOTHING_INDEXED_TIMESTAMP } from "../../../common/TutanotaConstants"
import { sql } from "../Sql"
/**
* Empties search index since it could have been inconsistent.
*/
export const offline7: OfflineMigration = {
version: 7,
async migrate(_: OfflineStorage, sqlCipherFacade: SqlCipherFacade): Promise<void> {
if (APP_TYPE === AppType.Mail || APP_TYPE === AppType.Integrated) {
console.log("Droping search indices...")
{
const { query, params } = sql`DELETE
FROM content_mail_index`
await sqlCipherFacade.run(query, params)
}
{
const { query, params } = sql`DELETE
FROM mail_index`
await sqlCipherFacade.run(query, params)
}
{
const { query, params } = sql`DELETE
FROM contact_index`
await sqlCipherFacade.run(query, params)
}
{
const { query, params } = sql`UPDATE search_group_data
SET indexedTimestamp = ${NOTHING_INDEXED_TIMESTAMP}`
await sqlCipherFacade.run(query, params)
}
}
},
}

View file

@ -48,7 +48,7 @@ export type BrowserData = {
export const companyTeamLabel = "Tuta Team"
export enum AppType {
export const enum AppType {
/**
* Desktop app / Web app
*/

3
src/global.d.ts vendored
View file

@ -11,6 +11,7 @@ import { ICommonLocator } from "./api/main/CommonLocator"
import { WhitelabelCustomizations } from "./misc/WhitelabelCustomizations"
import { WorkerLocatorType } from "./api/worker/WorkerLocator"
import { TopLevelView } from "./TopLevelView.js"
import { AppType } from "./common/misc/ClientConstants"
interface NativeApp {
// In desktop, we can pass whole objects
@ -55,4 +56,6 @@ declare global {
interface WorkerGlobalScope {
locator: WorkerLocatorType
}
const APP_TYPE: AppType
}