exports.id=5788,exports.ids=[5788],exports.modules={5242:(a,b,c)=>{"use strict";c.d(b,{$K:()=>R,NW:()=>m,PF:()=>M,a_:()=>k,bX:()=>n,db:()=>U,gs:()=>j,h:()=>q,hp:()=>u,iM:()=>t});var d=c(79868),e=c(33873),f=c.n(e),g=c(55511),h=c(29021),i=c.n(h);function j(){let a=(process.env.DATABASE_URL??"file:./gws-backup.db").replace(/^file:/,"").replace(/^["']|["']$/g,"");return f().isAbsolute(a)?a:f().join(process.cwd(),a)}function k(){let a=process.env.ARCHIVE_DATABASE_URL;if(a){let b=a.replace(/^file:/,"").replace(/^["']|["']$/g,"");return f().isAbsolute(b)?b:f().join(process.cwd(),b)}let b=j();return f().join(f().dirname(b),f().basename(b).replace(/\.db$/,"")+"-archive.db")}let l='"archive"."BackupFileIndex"';function m(){return f().join(f().dirname(j()),"clients")}function n(a){let b=a.replace(/[^A-Za-z0-9_-]/g,"_");return f().join(m(),`${b}.db`)}let o=`
CREATE TABLE IF NOT EXISTS "BackupFileIndex" (
    "id"           INTEGER PRIMARY KEY,
    "clientId"     TEXT NOT NULL,
    "userEmail"    TEXT NOT NULL,
    "driveFileId"  TEXT NOT NULL,
    "fileName"     TEXT NOT NULL DEFAULT '',
    "mimeType"     TEXT NOT NULL DEFAULT '',
    "modifiedTime" TEXT NOT NULL DEFAULT '',
    "backupJobId"  TEXT NOT NULL,
    "backupPath"   TEXT NOT NULL DEFAULT '',
    "destination"  TEXT NOT NULL DEFAULT 'remote',
    "createdAt"    TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    "payloadPurged" INTEGER NOT NULL DEFAULT 0,
    "preserve"      INTEGER NOT NULL DEFAULT 0,
    "deletedAt"      TEXT,
    "deletedAtJobId" TEXT,
    "originalPath"   TEXT,
    "subject"        TEXT,
    "sender"         TEXT,
    "recipient"      TEXT,
    "emailDate"      TEXT,
    "labelIds"       TEXT,
    "size"           INTEGER,
    "destinationProfileId" TEXT,
    UNIQUE ("clientId", "userEmail", "driveFileId", "backupJobId")
);
CREATE INDEX IF NOT EXISTS "idx_bfi_client_user_created"
    ON "BackupFileIndex" ("clientId", "userEmail", "driveFileId", "createdAt" DESC);
-- Object-key lookups. Without this, "which rows point at this key" degrades to
-- scanning every row the client owns: measured at 993 ms per call on an
-- 826k-row index, and retention preview made one call PER SUPERSEDED VERSION.
CREATE INDEX IF NOT EXISTS "idx_bfi_client_path"
    ON "BackupFileIndex" ("clientId", "backupPath");
CREATE INDEX IF NOT EXISTS "idx_bfi_drive_file" ON "BackupFileIndex" ("driveFileId");
CREATE INDEX IF NOT EXISTS "idx_bfi_profile"    ON "BackupFileIndex" ("destinationProfileId");
CREATE INDEX IF NOT EXISTS "idx_bfi_job"        ON "BackupFileIndex" ("backupJobId");
CREATE INDEX IF NOT EXISTS "idx_bfi_deleted"    ON "BackupFileIndex" ("deletedAt");
`,p=null;function q(){if(null===p)try{let a=z().prepare('SELECT "indexSplitVersion" AS v FROM "AppSettings" WHERE id = \'singleton\'').get();p=Number(a?.v??0)>0}catch{p=!1}return p}let r=new Map;function s(a){if(!q())return z();let b=r.get(a);if(b)return b;let c=m();i().mkdirSync(c,{recursive:!0});let e=new d.DatabaseSync(n(a));try{e.exec("PRAGMA journal_mode=WAL"),e.exec("PRAGMA busy_timeout=5000")}catch{}return e.exec(o),r.set(a,e),e}function t(a){q()&&s(a)}function u(){if(!q())return z().prepare('SELECT DISTINCT clientId FROM "BackupFileIndex"').all().map(a=>a.clientId);try{return i().readdirSync(m()).filter(a=>a.endsWith(".db")).map(a=>a.slice(0,-3))}catch{return[]}}let v=new Map;function w(a,b){if(!q())return C(b);let c=`${a}\u0000${b}`,d=v.get(c);return d||(d=s(a).prepare(b),v.set(c,d)),d}function x(a){return q()?'"BackupFileIndex"':l}let y=null;function z(){if(y)return y;let a=j(),b=f().dirname(a);i().existsSync(b)||i().mkdirSync(b,{recursive:!0}),y=new d.DatabaseSync(a);try{y.exec("PRAGMA journal_mode=WAL"),y.exec("PRAGMA busy_timeout=5000")}catch{console.warn("[db] WAL mode unavailable, falling back to default journal mode")}y.exec("PRAGMA foreign_keys=ON");try{let a=k();i().mkdirSync(f().dirname(a),{recursive:!0}),y.exec(`ATTACH DATABASE '${a.replace(/'/g,"''")}' AS "archive"`),y.exec(`
CREATE TABLE IF NOT EXISTS "archive"."BackupFileIndex" (
    "id"           INTEGER PRIMARY KEY,
    "clientId"     TEXT NOT NULL,
    "userEmail"    TEXT NOT NULL,
    "driveFileId"  TEXT NOT NULL,
    "fileName"     TEXT NOT NULL DEFAULT '',
    "mimeType"     TEXT NOT NULL DEFAULT '',
    "modifiedTime" TEXT NOT NULL DEFAULT '',
    "backupJobId"  TEXT NOT NULL,
    "backupPath"   TEXT NOT NULL DEFAULT '',
    "destination"  TEXT NOT NULL DEFAULT 'remote',
    "createdAt"    TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    "payloadPurged" INTEGER NOT NULL DEFAULT 0,
    "preserve"      INTEGER NOT NULL DEFAULT 0,
    "deletedAt"     TEXT,
    "deletedAtJobId" TEXT,
    "originalPath"  TEXT,
    "subject"       TEXT,
    "sender"        TEXT,
    "recipient"     TEXT,
    "emailDate"     TEXT,
    "labelIds"      TEXT,
    "size"          INTEGER,
    "destinationProfileId" TEXT
);
CREATE INDEX IF NOT EXISTS "archive"."idx_arc_client_user"
    ON "BackupFileIndex" ("clientId", "userEmail", "driveFileId");
CREATE INDEX IF NOT EXISTS "archive"."idx_arc_profile"
    ON "BackupFileIndex" ("destinationProfileId");
CREATE INDEX IF NOT EXISTS "archive"."idx_arc_job"
    ON "BackupFileIndex" ("backupJobId");
        `)}catch(a){console.error("[db] Could not attach the frozen index archive:",a)}try{let a=process.cwd(),b=f().join(a,"update.php"),c=f().join(a,"update.zip");i().existsSync(b)&&i().unlinkSync(b),i().existsSync(c)&&i().unlinkSync(c)}catch(a){console.warn("[db] Failed to cleanup deployment payloads:",a)}y.exec(`
CREATE TABLE IF NOT EXISTS "AppSettings" (
    "id" TEXT NOT NULL PRIMARY KEY DEFAULT 'singleton',
    "businessName" TEXT NOT NULL DEFAULT '',
    "businessAddress" TEXT NOT NULL DEFAULT '',
    "companyNumber" TEXT NOT NULL DEFAULT '',
    "vatNumber" TEXT NOT NULL DEFAULT '',
    "businessEmail" TEXT NOT NULL DEFAULT '',
    "logoUrl" TEXT,
    "reportLogoAlign" TEXT NOT NULL DEFAULT 'left',
    "reportDetailsAlign" TEXT NOT NULL DEFAULT 'footer_left',
    "adminPasswordHash" TEXT NOT NULL DEFAULT '',
    "adminEmail" TEXT NOT NULL DEFAULT 'admin@localhost',
    "recoveryKeyHash" TEXT NOT NULL DEFAULT '',
    "defaultDriveFolderId" TEXT NOT NULL DEFAULT '',
    "backupDestinationEmail" TEXT NOT NULL DEFAULT '',
    "serviceAccountJson" TEXT NOT NULL DEFAULT '',
    "serviceAccountEmail" TEXT NOT NULL DEFAULT '',
    "driveOAuthClientId" TEXT NOT NULL DEFAULT '',
    "driveOAuthClientSecret" TEXT NOT NULL DEFAULT '',
    "driveOAuthRefreshToken" TEXT NOT NULL DEFAULT '',
    "driveOAuthEmail" TEXT NOT NULL DEFAULT '',
    "backupDestMode" TEXT NOT NULL DEFAULT 'remote',
    "localBackupPath" TEXT NOT NULL DEFAULT '',
    "s3Endpoint" TEXT NOT NULL DEFAULT '',
    "s3Region" TEXT NOT NULL DEFAULT '',
    "s3AccessKeyId" TEXT NOT NULL DEFAULT '',
    "s3SecretAccessKey" TEXT NOT NULL DEFAULT '',
    "s3Bucket" TEXT NOT NULL DEFAULT '',
    "azureAccountName" TEXT NOT NULL DEFAULT '',
    "azureAccountKey" TEXT NOT NULL DEFAULT '',
    "azureContainer" TEXT NOT NULL DEFAULT '',
    "themePrimary" TEXT NOT NULL DEFAULT '',
    "licenseKey" TEXT NOT NULL DEFAULT '',
    "heartbeatApiKey" TEXT NOT NULL DEFAULT '',
    "appPort" TEXT NOT NULL DEFAULT '3001',
    "backgroundImage" TEXT NOT NULL DEFAULT '',
    "schemaVersion" INTEGER NOT NULL DEFAULT 1,
    -- \xa77 R1. A NEW install starts with one index database per client; there is
    -- nothing to migrate, so it should never grow the monolith the migration
    -- exists to rescue. Installs that predate this get the column from the ALTER
    -- further down, which defaults to 0 until they run the split themselves.
    "indexSplitVersion" INTEGER NOT NULL DEFAULT 1,
    "createdAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    "updatedAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
);

CREATE TABLE IF NOT EXISTS "Client" (
    "id" TEXT NOT NULL PRIMARY KEY,
    "name" TEXT NOT NULL,
    "primaryDomain" TEXT NOT NULL,
    "status" TEXT NOT NULL DEFAULT 'pending',
    "errorMessage" TEXT,
    "suspendedAt" TEXT,
    "statusChangedAt" TEXT,
    "serviceAccountJson" TEXT NOT NULL DEFAULT '',
    "serviceAccountEmail" TEXT NOT NULL DEFAULT '',
    "backupDriveFolderId" TEXT NOT NULL DEFAULT '',
    "scopesTier" TEXT NOT NULL DEFAULT 'backup',
    "retentionMonths" INTEGER,
    "retentionDate" TEXT,
    "retentionAction" TEXT,
    "retentionLabel" TEXT,
    "previousRetentionLabel" TEXT,
    "pruneMonths" INTEGER,
    "shieldDriveFolders" TEXT DEFAULT '["GWS_PERMANENT_VAULT"]',
    "shieldGmailLabels" TEXT DEFAULT '["GWS_PERMANENT_VAULT"]',
    "contactName" TEXT,
    "contactEmail" TEXT,
    "contactPhone" TEXT,
    "invoicingEmail" TEXT,
    "notes" TEXT,
    "createdAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    "updatedAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
);
CREATE UNIQUE INDEX IF NOT EXISTS "Client_primaryDomain_key" ON "Client"("primaryDomain");

CREATE TABLE IF NOT EXISTS "ClientDomain" (
    "id" TEXT NOT NULL PRIMARY KEY,
    "clientId" TEXT NOT NULL,
    "domain" TEXT NOT NULL,
    "type" TEXT NOT NULL,
    "createdAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    FOREIGN KEY ("clientId") REFERENCES "Client"("id") ON DELETE CASCADE
);
CREATE UNIQUE INDEX IF NOT EXISTS "ClientDomain_clientId_domain_key" ON "ClientDomain"("clientId","domain");

CREATE TABLE IF NOT EXISTS "ClientAccount" (
    "id" TEXT NOT NULL PRIMARY KEY,
    "clientId" TEXT NOT NULL,
    "email" TEXT NOT NULL,
    "displayName" TEXT NOT NULL DEFAULT '',
    "accountType" TEXT NOT NULL DEFAULT 'user',
    "suspended" INTEGER NOT NULL DEFAULT 0,
    "aliases" TEXT NOT NULL DEFAULT '[]',
    "lastBackedAt" TEXT,
    "createdAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    FOREIGN KEY ("clientId") REFERENCES "Client"("id") ON DELETE CASCADE
);
CREATE UNIQUE INDEX IF NOT EXISTS "ClientAccount_clientId_email_key" ON "ClientAccount"("clientId","email");

CREATE TABLE IF NOT EXISTS "ClientGroup" (
    "id" TEXT NOT NULL PRIMARY KEY,
    "clientId" TEXT NOT NULL,
    "groupEmail" TEXT NOT NULL,
    "name" TEXT NOT NULL DEFAULT '',
    "memberCount" INTEGER NOT NULL DEFAULT 0,
    "archiveEmail" TEXT,
    "createdAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    FOREIGN KEY ("clientId") REFERENCES "Client"("id") ON DELETE CASCADE
);
CREATE UNIQUE INDEX IF NOT EXISTS "ClientGroup_clientId_groupEmail_key" ON "ClientGroup"("clientId","groupEmail");

CREATE TABLE IF NOT EXISTS "ClientSharedDrive" (
    "id" TEXT NOT NULL PRIMARY KEY,
    "clientId" TEXT NOT NULL,
    "driveId" TEXT NOT NULL,
    "name" TEXT NOT NULL,
    "createdAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    FOREIGN KEY ("clientId") REFERENCES "Client"("id") ON DELETE CASCADE
);
CREATE UNIQUE INDEX IF NOT EXISTS "ClientSharedDrive_clientId_driveId_key" ON "ClientSharedDrive"("clientId","driveId");

CREATE TABLE IF NOT EXISTS "LicenceLedger" (
    "id" TEXT NOT NULL PRIMARY KEY,
    "clientId" TEXT NOT NULL,
    "periodStart" TEXT NOT NULL,
    "userCount" INTEGER NOT NULL DEFAULT 0,
    "aliasCount" INTEGER NOT NULL DEFAULT 0,
    "domainCount" INTEGER NOT NULL DEFAULT 0,
    "groupCount" INTEGER NOT NULL DEFAULT 0,
    "sharedDrives" INTEGER NOT NULL DEFAULT 0,
    "createdAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    FOREIGN KEY ("clientId") REFERENCES "Client"("id") ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS "BackupSchedule" (
    "id" TEXT NOT NULL PRIMARY KEY,
    "clientId" TEXT NOT NULL UNIQUE,
    "frequencyHours" INTEGER NOT NULL DEFAULT 4,
    "windowStart" TEXT NOT NULL DEFAULT '00:00',
    "windowEnd" TEXT NOT NULL DEFAULT '23:59',
    "enabled" INTEGER NOT NULL DEFAULT 1,
    "backupGmail" INTEGER NOT NULL DEFAULT 1,
    "backupDrive" INTEGER NOT NULL DEFAULT 1,
    "backupCalendar" INTEGER NOT NULL DEFAULT 1,
    "backupContacts" INTEGER NOT NULL DEFAULT 1,
    "backupGroups" INTEGER NOT NULL DEFAULT 1,
    "encryptFiles" INTEGER NOT NULL DEFAULT 0,
    "createdAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    "updatedAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    FOREIGN KEY ("clientId") REFERENCES "Client"("id") ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS "BackupJob" (
    "id" TEXT NOT NULL PRIMARY KEY,
    "clientId" TEXT NOT NULL,
    "startedAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    "completedAt" TEXT,
    "status" TEXT NOT NULL DEFAULT 'running',
    "stats" TEXT NOT NULL DEFAULT '{}',
    "errorDetail" TEXT,
    FOREIGN KEY ("clientId") REFERENCES "Client"("id") ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS "RestoreJob" (
    "id" TEXT NOT NULL PRIMARY KEY,
    "clientId" TEXT NOT NULL,
    "requestedAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    "completedAt" TEXT,
    "status" TEXT NOT NULL DEFAULT 'pending',
    "scope" TEXT NOT NULL,
    "params" TEXT NOT NULL DEFAULT '{}',
    "stats" TEXT NOT NULL DEFAULT '{}',
    "errorDetail" TEXT,
    FOREIGN KEY ("clientId") REFERENCES "Client"("id") ON DELETE CASCADE
);

-- One row per item successfully written back into Workspace, so an interrupted
-- restore can be resumed instead of redone. Keyed by the ROOT job of the chain
-- (the original restore), which every resume of it also writes under — without
-- that, a resume would only know about its own progress and would replay
-- everything the first attempt already restored.
CREATE TABLE IF NOT EXISTS "RestoreItemLog" (
    "rootJobId"  TEXT NOT NULL,
    "indexRowId" TEXT NOT NULL,
    "restoredAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    PRIMARY KEY ("rootJobId", "indexRowId")
) WITHOUT ROWID;

-- The mirror of RestoreItemLog: one row per item that FAILED, so repeated
-- attempts are visible across resumes. Without this a permanently broken item
-- (a deleted source object, a revoked permission) is retried on every future run
-- for ever, burning five attempts and ~30s each time and never being reported as
-- hopeless. Rows are deleted the moment an item finally succeeds.
CREATE TABLE IF NOT EXISTS "RestoreItemFailure" (
    "rootJobId"     TEXT NOT NULL,
    "indexRowId"    TEXT NOT NULL,
    "attempts"      INTEGER NOT NULL DEFAULT 0,
    "permanent"     INTEGER NOT NULL DEFAULT 0,
    "lastError"     TEXT NOT NULL DEFAULT '',
    "fileName"      TEXT NOT NULL DEFAULT '',
    "lastAttemptAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    PRIMARY KEY ("rootJobId", "indexRowId")
) WITHOUT ROWID;

CREATE TABLE IF NOT EXISTS "AuditLog" (
    "id" TEXT NOT NULL PRIMARY KEY,
    "clientId" TEXT,
    "clientName" TEXT,
    "clientDomain" TEXT,
    "actor" TEXT NOT NULL,
    "action" TEXT NOT NULL,
    "detail" TEXT NOT NULL DEFAULT '',
    "createdAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
    -- Deliberately NO foreign key to Client (ROADMAP \xa77 R6). The audit trail has to
    -- outlive the thing it describes: deleting a client must leave a readable record
    -- of who deleted what, and ON DELETE SET NULL erased exactly that. clientId is
    -- a plain reference; clientName and clientDomain are denormalised beside it so a
    -- row still names its subject after the Client row is gone.
);
CREATE INDEX IF NOT EXISTS "idx_audit_created" ON "AuditLog" ("createdAt");
CREATE INDEX IF NOT EXISTS "idx_audit_client"  ON "AuditLog" ("clientId");
`);try{y.prepare('ALTER TABLE "RestoreJob" ADD COLUMN "stats" TEXT DEFAULT \'{}\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "installId" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "newsCache" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "newsLastSeenAt" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "versionPruneEnabled" INTEGER DEFAULT 0').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "versionRetentionLadder" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "s3Endpoint" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "s3Region" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "s3AccessKeyId" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "s3SecretAccessKey" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "s3Bucket" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "azureAccountName" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "azureAccountKey" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "azureContainer" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "heartbeatApiKey" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "appPort" TEXT DEFAULT \'3001\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "themePrimary" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "backgroundImage" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "licenseKey" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "businessAddress" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "companyNumber" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "vatNumber" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "reportLogoAlign" TEXT DEFAULT \'left\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "reportDetailsAlign" TEXT DEFAULT \'footer_left\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "vacuumTargetHour" INTEGER DEFAULT 3').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "lastVacuumAt" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "masterScheduleEnabled" INTEGER DEFAULT 1').run()}catch{}try{y.prepare('ALTER TABLE "RestoreJob" ADD COLUMN "parkedUntil" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "RestoreJob" ADD COLUMN "autoResumeCount" INTEGER DEFAULT 0').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "autoResumeRestores" INTEGER DEFAULT 1').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "recoveryKeyCreatedAt" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "onboardingCompletedAt" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "licenceAcceptedVersion" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "licenceAcceptedAt" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "licenceAcceptedBy" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "dbBackupEnabled" INTEGER DEFAULT 0').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "dbBackupFrequencyHours" INTEGER DEFAULT 24').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "dbBackupHour" INTEGER DEFAULT 3').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "dbBackupKeep" INTEGER DEFAULT 7').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "deletedItemPruneEnabled" INTEGER DEFAULT 0').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "indexSplitVersion" INTEGER DEFAULT 0').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "lastDbBackupAt" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "lastDbBackupDetail" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "encryptionKeyFingerprint" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "encryptionKeySavedAt" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "Client" ADD COLUMN "versionPruneEnabled" INTEGER').run()}catch{}try{y.prepare('ALTER TABLE "Client" ADD COLUMN "retentionMonths" INTEGER').run()}catch{}try{y.prepare('ALTER TABLE "Client" ADD COLUMN "retentionDate" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "Client" ADD COLUMN "retentionAction" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "Client" ADD COLUMN "retentionLabel" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "Client" ADD COLUMN "previousRetentionLabel" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "Client" ADD COLUMN "scopesTier" TEXT DEFAULT \'backup\'').run()}catch{}try{y.prepare('ALTER TABLE "Client" ADD COLUMN "archivePurgeAt" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "Client" ADD COLUMN "archivedAt" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "Client" ADD COLUMN "archivedBy" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "Client" ADD COLUMN "archiveReason" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "Client" ADD COLUMN "deletionStartedAt" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "AuditLog" ADD COLUMN "clientName" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "AuditLog" ADD COLUMN "clientDomain" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "AuditLog" ADD COLUMN "totalEmails" INTEGER DEFAULT 0').run()}catch{}try{y.prepare('ALTER TABLE "AuditLog" ADD COLUMN "totalFiles" INTEGER DEFAULT 0').run()}catch{}try{y.prepare('ALTER TABLE "AuditLog" ADD COLUMN "totalBytes" INTEGER DEFAULT 0').run()}catch{}try{y.prepare('ALTER TABLE "Client" ADD COLUMN "contactName" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "Client" ADD COLUMN "contactEmail" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "Client" ADD COLUMN "contactPhone" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "Client" ADD COLUMN "invoicingEmail" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "Client" ADD COLUMN "notes" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "Client" ADD COLUMN "pruneMonths" INTEGER').run()}catch{}try{y.prepare('ALTER TABLE "Client" ADD COLUMN "shieldDriveFolders" TEXT DEFAULT \'["GWS_PERMANENT_VAULT"]\'').run()}catch{}try{y.prepare('ALTER TABLE "Client" ADD COLUMN "shieldGmailLabels" TEXT DEFAULT \'["GWS_PERMANENT_VAULT"]\'').run()}catch{}try{y.prepare('ALTER TABLE "ClientAccount" ADD COLUMN "isDeleted" INTEGER NOT NULL DEFAULT 0').run()}catch{}try{y.prepare('ALTER TABLE "ClientGroup" ADD COLUMN "archiveEmail" TEXT').run()}catch{}try{y.prepare('DROP INDEX IF EXISTS "idx_bfi_client_user"').run()}catch{}y.exec(`
CREATE TABLE IF NOT EXISTS "ReportTemplate" (
    "id" TEXT NOT NULL PRIMARY KEY,
    "name" TEXT NOT NULL,
    "targetType" TEXT NOT NULL DEFAULT 'all_clients',
    "targetClientId" TEXT,
    "entities" TEXT NOT NULL DEFAULT '[]',
    "metrics" TEXT NOT NULL DEFAULT '[]',
    "periodMonths" INTEGER NOT NULL DEFAULT 3,
    "globalStrategy" TEXT NOT NULL DEFAULT 'aggregate',
    "customText" TEXT NOT NULL DEFAULT '',
    "createdAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    "updatedAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    FOREIGN KEY ("targetClientId") REFERENCES "Client"("id") ON DELETE CASCADE
);
`);try{y.prepare('ALTER TABLE "ReportTemplate" ADD COLUMN "globalStrategy" TEXT DEFAULT \'aggregate\'').run()}catch{}try{y.prepare('ALTER TABLE "ReportTemplate" ADD COLUMN "customText" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "ReportTemplate" ADD COLUMN "layoutFormat" TEXT DEFAULT \'A4\'').run()}catch{}try{y.prepare('ALTER TABLE "ReportTemplate" ADD COLUMN "layoutOrientation" TEXT DEFAULT \'portrait\'').run()}catch{}try{y.prepare('ALTER TABLE "ReportTemplate" ADD COLUMN "layoutColumns" INTEGER DEFAULT 1').run()}catch{}y.exec(`
CREATE TABLE IF NOT EXISTS "DestinationProfile" (
    "id"        TEXT NOT NULL PRIMARY KEY,
    "label"     TEXT NOT NULL DEFAULT '',
    "mode"      TEXT NOT NULL,
    "status"    TEXT NOT NULL DEFAULT 'active',
    "config"    TEXT NOT NULL DEFAULT '{}',
    "createdAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    "frozenAt"  TEXT
);
`),y.exec(`
CREATE TABLE IF NOT EXISTS "BackupFileIndex" (
    -- INTEGER PRIMARY KEY is the rowid itself: no second B-tree, and a few bytes
    -- per row instead of a 36-character UUID stored twice (ROADMAP #(B)).
    -- Installs created before this keep a TEXT id until
    -- scripts/migrate-index-integer-ids.mjs is run; indexIdIsText() below tells
    -- the writer which shape it is on, so both work.
    "id"           INTEGER PRIMARY KEY,
    "clientId"     TEXT NOT NULL,
    "userEmail"    TEXT NOT NULL,
    "driveFileId"  TEXT NOT NULL,
    "fileName"     TEXT NOT NULL DEFAULT '',
    "mimeType"     TEXT NOT NULL DEFAULT '',
    "modifiedTime" TEXT NOT NULL DEFAULT '',
    "backupJobId"  TEXT NOT NULL,
    "backupPath"   TEXT NOT NULL DEFAULT '',
    "destination"  TEXT NOT NULL DEFAULT 'remote',
    "createdAt"    TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    "payloadPurged" INTEGER NOT NULL DEFAULT 0,
    "preserve"      INTEGER NOT NULL DEFAULT 0,
    -- These three were only ever added by ALTER statements that run EARLIER in this
    -- function than this CREATE, so on a brand-new database they threw "no such
    -- table", were swallowed, and the column never appeared. The first backup on a
    -- fresh install then failed on "no column named originalPath". Declared here so
    -- a new install is born complete; the ALTERs still upgrade older ones.
    "deletedAt"      TEXT,
    "deletedAtJobId" TEXT,
    "originalPath"   TEXT,
    UNIQUE ("clientId", "userEmail", "driveFileId", "backupJobId")
);
CREATE INDEX IF NOT EXISTS "idx_bfi_client_user_created"
    ON "BackupFileIndex" ("clientId", "userEmail", "driveFileId", "createdAt" DESC);
-- (idx_bfi_client_user removed: a strict prefix of idx_bfi_client_user_created)
CREATE INDEX IF NOT EXISTS "idx_bfi_client_path"
    ON "BackupFileIndex" ("clientId", "backupPath");
CREATE INDEX IF NOT EXISTS "idx_bfi_drive_file"
    ON "BackupFileIndex" ("driveFileId");
`);try{y.prepare('ALTER TABLE "BackupFileIndex" ADD COLUMN "deletedAt" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "BackupFileIndex" ADD COLUMN "deletedAtJobId" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "BackupFileIndex" ADD COLUMN "originalPath" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "BackupFileIndex" ADD COLUMN "payloadPurged" INTEGER DEFAULT 0').run()}catch{}try{y.prepare('ALTER TABLE "BackupFileIndex" ADD COLUMN "preserve" INTEGER DEFAULT 0').run()}catch{}try{y.prepare('ALTER TABLE "BackupFileIndex" ADD COLUMN "destination" TEXT DEFAULT \'remote\'').run()}catch{}try{y.prepare('ALTER TABLE "BackupFileIndex" ADD COLUMN "subject" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "BackupFileIndex" ADD COLUMN "sender" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "BackupFileIndex" ADD COLUMN "recipient" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "BackupFileIndex" ADD COLUMN "emailDate" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "BackupFileIndex" ADD COLUMN "labelIds" TEXT').run()}catch{}try{y.prepare('ALTER TABLE "BackupFileIndex" ADD COLUMN "size" INTEGER').run()}catch{}try{y.prepare('ALTER TABLE "BackupFileIndex" ADD COLUMN "destinationProfileId" TEXT').run()}catch{}y.exec(`
CREATE TABLE IF NOT EXISTS "LinuxServer" (
    "id" TEXT NOT NULL PRIMARY KEY,
    "clientId" TEXT NOT NULL,
    "host" TEXT NOT NULL,
    "port" INTEGER NOT NULL DEFAULT 22,
    "username" TEXT NOT NULL,
    "authMethod" TEXT NOT NULL DEFAULT 'password',
    "passwordHash" TEXT,
    "sshKeyHash" TEXT,
    "status" TEXT NOT NULL DEFAULT 'pending',
    "lastScanAt" TEXT,
    "discoveredData" TEXT NOT NULL DEFAULT '{}',
    "createdAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    "updatedAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    FOREIGN KEY ("clientId") REFERENCES "Client"("id") ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS "LinuxBackupJob" (
    "id" TEXT NOT NULL PRIMARY KEY,
    "serverId" TEXT NOT NULL,
    "clientId" TEXT NOT NULL,
    "startedAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    "completedAt" TEXT,
    "status" TEXT NOT NULL DEFAULT 'running',
    "stats" TEXT NOT NULL DEFAULT '{}',
    "errorDetail" TEXT,
    FOREIGN KEY ("serverId") REFERENCES "LinuxServer"("id") ON DELETE CASCADE,
    FOREIGN KEY ("clientId") REFERENCES "Client"("id") ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS "LinuxFileIndex" (
    "id" TEXT NOT NULL PRIMARY KEY,
    "serverId" TEXT NOT NULL,
    "backupJobId" TEXT NOT NULL,
    "filePath" TEXT NOT NULL,
    "fileType" TEXT NOT NULL,
    "size" INTEGER NOT NULL DEFAULT 0,
    "destination" TEXT NOT NULL DEFAULT 'remote',
    "createdAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    UNIQUE ("serverId", "backupJobId", "filePath"),
    FOREIGN KEY ("serverId") REFERENCES "LinuxServer"("id") ON DELETE CASCADE,
    FOREIGN KEY ("backupJobId") REFERENCES "LinuxBackupJob"("id") ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS "LinuxRestoreJob" (
    "id" TEXT NOT NULL PRIMARY KEY,
    "serverId" TEXT NOT NULL,
    "clientId" TEXT NOT NULL,
    "backupJobId" TEXT NOT NULL,
    "startedAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    "completedAt" TEXT,
    "status" TEXT NOT NULL DEFAULT 'running',
    "params" TEXT NOT NULL DEFAULT '{}',
    "stats" TEXT NOT NULL DEFAULT '{}',
    "errorDetail" TEXT,
    FOREIGN KEY ("serverId") REFERENCES "LinuxServer"("id") ON DELETE CASCADE,
    FOREIGN KEY ("clientId") REFERENCES "Client"("id") ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS "AppUser" (
    "id" TEXT NOT NULL PRIMARY KEY,
    "email" TEXT NOT NULL UNIQUE,
    "name" TEXT NOT NULL DEFAULT '',
    "passwordHash" TEXT NOT NULL,
    "role" TEXT NOT NULL DEFAULT 'REPORTER',
    "twoFactorSecret" TEXT DEFAULT '',
    "twoFactorEnabled" INTEGER NOT NULL DEFAULT 0,
    -- Bumped whenever every existing session for this user must stop working
    -- (password reset, account disabled). The JWT carries the value it was
    -- issued with; lib/auth.ts rejects a token that no longer matches.
    "tokenVersion" INTEGER NOT NULL DEFAULT 0,
    "createdAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
    "updatedAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
);
    `);try{let a=y.prepare('SELECT COUNT(*) as c FROM "AppUser"').get();if(0===a.c){let a=y.prepare('SELECT * FROM "AppSettings" WHERE "id" = ?').get("singleton");a&&a.adminEmail&&a.adminPasswordHash&&y.prepare('INSERT INTO "AppUser" ("id", "email", "name", "passwordHash", "role") VALUES (?, ?, ?, ?, ?)').run((0,g.randomUUID)(),a.adminEmail,a.businessName||"Master Admin",a.adminPasswordHash,"SUPER_ADMIN")}}catch(a){}try{y.prepare('ALTER TABLE "AppUser" ADD COLUMN "twoFactorSecret" TEXT DEFAULT \'\'').run()}catch{}try{y.prepare('ALTER TABLE "AppUser" ADD COLUMN "twoFactorEnabled" INTEGER DEFAULT 0').run()}catch{}try{y.prepare('ALTER TABLE "AppUser" ADD COLUMN "tokenVersion" INTEGER DEFAULT 0').run()}catch{}try{y.prepare('ALTER TABLE "AppSettings" ADD COLUMN "schemaVersion" INTEGER DEFAULT 1').run()}catch{}try{let a=y.prepare('SELECT "indexSplitVersion" AS v FROM "AppSettings" WHERE id = \'singleton\'').get();if(a&&0===Number(a.v??0)){let a=y.prepare('SELECT COUNT(*) AS n FROM "BackupFileIndex"').get().n,b=0;try{b=y.prepare('SELECT COUNT(*) AS n FROM "archive"."BackupFileIndex"').get().n}catch{}0===a&&0===b&&(y.prepare('UPDATE "AppSettings" SET "indexSplitVersion" = 1 WHERE id = \'singleton\'').run(),p=null,console.log("[db] No index rows to migrate — using one database per client (\xa77 R1)."))}}catch{}try{if(y.prepare('PRAGMA foreign_key_list("AuditLog")').all().length>0){y.exec("PRAGMA foreign_keys=OFF");try{y.exec("BEGIN IMMEDIATE"),y.exec(`
CREATE TABLE "AuditLog_r6" (
    "id" TEXT NOT NULL PRIMARY KEY,
    "clientId" TEXT,
    "clientName" TEXT,
    "clientDomain" TEXT,
    "actor" TEXT NOT NULL,
    "action" TEXT NOT NULL,
    "detail" TEXT NOT NULL DEFAULT '',
    "totalEmails" INTEGER DEFAULT 0,
    "totalFiles" INTEGER DEFAULT 0,
    "totalBytes" INTEGER DEFAULT 0,
    "createdAt" TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
);
INSERT INTO "AuditLog_r6"
    ("id","clientId","clientName","clientDomain","actor","action","detail",
     "totalEmails","totalFiles","totalBytes","createdAt")
SELECT "id","clientId","clientName","clientDomain","actor","action","detail",
       COALESCE("totalEmails",0), COALESCE("totalFiles",0), COALESCE("totalBytes",0),
       "createdAt"
FROM "AuditLog";
DROP TABLE "AuditLog";
ALTER TABLE "AuditLog_r6" RENAME TO "AuditLog";
CREATE INDEX IF NOT EXISTS "idx_audit_created" ON "AuditLog" ("createdAt");
CREATE INDEX IF NOT EXISTS "idx_audit_client"  ON "AuditLog" ("clientId");
                `),y.exec(`
UPDATE "AuditLog" SET
    "clientName"   = COALESCE(NULLIF("clientName",''),   (SELECT "name"          FROM "Client" WHERE "id" = "AuditLog"."clientId")),
    "clientDomain" = COALESCE(NULLIF("clientDomain",''), (SELECT "primaryDomain" FROM "Client" WHERE "id" = "AuditLog"."clientId"))
WHERE "clientId" IS NOT NULL
  AND (NULLIF("clientName",'') IS NULL OR NULLIF("clientDomain",'') IS NULL);
                `),y.exec("COMMIT"),console.log("[db] AuditLog rebuilt without its Client foreign key (R6)")}catch(a){try{y.exec("ROLLBACK")}catch{}throw a}finally{y.exec("PRAGMA foreign_keys=ON")}}}catch(a){console.error("[db] AuditLog R6 rebuild failed, leaving the table as it was:",a)}return y}let A=()=>new Date().toISOString(),B=new Map;function C(a){let b=B.get(a);return b||(b=z().prepare(a),B.set(a,b)),b}function D(a,b){let c={...a};for(let a of b)a in c&&null!==c[a]&&(c[a]=0!==c[a]);return c}let E=["enabled","backupGmail","backupDrive","backupCalendar","backupContacts","backupGroups","encryptFiles"],F=["suspended","isDeleted"];function G(a){let b=[],c=[];for(let[d,e]of Object.entries(a))if("object"==typeof e&&null!==e&&"in"in e){let a=e.in;b.push(`"${d}" IN (${a.map(()=>"?").join(",")})`),c.push(...a.map(a=>"boolean"==typeof a?+!!a:a))}else if("object"==typeof e&&null!==e&&"not"in e){let a=e.not;b.push(`"${d}" != ?`),c.push("boolean"==typeof a?+!!a:a)}else if("object"==typeof e&&null!==e&&"gte"in e){let a=e.gte;b.push(`"${d}" >= ?`),c.push("boolean"==typeof a?+!!a:a)}else b.push(`"${d}" = ?`),c.push("boolean"==typeof e?+!!e:e);return{clause:b.join(" AND "),params:c}}let H=new Map;function I(a){if(H.has(a))return H.get(a);let b=new Set(C(`PRAGMA table_info("${a}")`).all().map(a=>a.name));return H.set(a,b),b}function J(a,b){let c=I(a),d=Object.keys(b).filter(a=>void 0!==b[a]&&c.has(a)),e=d.map(a=>`"${a}"`).join(", "),f=d.map(()=>"?").join(", "),g=d.map(a=>{let c=b[a];return void 0===c?null:c instanceof Date?c.toISOString():c});return C(`INSERT INTO "${a}" (${e}) VALUES (${f})`).run(...g),C(`SELECT * FROM "${a}" WHERE "id" = ?`).get(b.id)}function K(a,b,c){let d=I(a),e={};for(let[a,b]of Object.entries(c))d.has(a)&&(e[a]=void 0===b?null:b instanceof Date?b.toISOString():b);let f=Object.keys(e).map(a=>`"${a}" = ?`).join(", ");return f.length>0&&C(`UPDATE "${a}" SET ${f} WHERE "id" = ?`).run(...Object.values(e),b),C(`SELECT * FROM "${a}" WHERE "id" = ?`).get(b)}function L(a,b,c,d=[]){let e=I(a),f={};for(let[a,b]of Object.entries(c))e.has(a)&&(f[a]=b);for(let a of d)a in f&&(f[a]=+!!f[a]);if(C(`SELECT id FROM "${a}" WHERE "id" = ?`).get(b)){if(Object.keys(f).length){let c=Object.keys(f).map(a=>`"${a}" = ?`).join(", ");c.length>0&&C(`UPDATE "${a}" SET ${c} WHERE "id" = ?`).run(...Object.values(f),b)}}else J(a,{id:b,...f,createdAt:A()});return C(`SELECT * FROM "${a}" WHERE "id" = ?`).get(b)}let M={findUnique:a=>Promise.resolve(C('SELECT * FROM "AppSettings" WHERE "id" = ?').get("singleton")??null),findUniqueOrThrow(a){let b=C('SELECT * FROM "AppSettings" WHERE "id" = ?').get("singleton");if(!b)throw Error("AppSettings record not found");return Promise.resolve(b)},update:a=>Promise.resolve(K("AppSettings",a.where.id,{...a.data,updatedAt:A()})),upsert(a){if(C('SELECT id FROM "AppSettings" WHERE "id" = ?').get(a.where.id)){let b={...a.update,updatedAt:A()};if(Object.keys(b).length>1){let c=Object.keys(b).map(a=>`"${a}" = ?`).join(", ");C(`UPDATE "AppSettings" SET ${c} WHERE "id" = ?`).run(...Object.values(b),a.where.id)}}else J("AppSettings",{id:a.where.id,...a.create,createdAt:A(),updatedAt:A()});return Promise.resolve(C('SELECT * FROM "AppSettings" WHERE "id" = ?').get(a.where.id))}};function N(a,b){let c=a.id;if(b.domains&&(a.domains=C('SELECT * FROM "ClientDomain" WHERE "clientId" = ? ORDER BY "createdAt" ASC').all(c)),b.accounts&&(a.accounts=C('SELECT * FROM "ClientAccount" WHERE "clientId" = ? ORDER BY "createdAt" ASC').all(c).map(a=>D(a,F))),b.groups&&(a.groups=C('SELECT * FROM "ClientGroup" WHERE "clientId" = ? ORDER BY "createdAt" ASC').all(c)),b.sharedDrives&&(a.sharedDrives=C('SELECT * FROM "ClientSharedDrive" WHERE "clientId" = ? ORDER BY "createdAt" ASC').all(c)),b.backupSchedule){let b=C('SELECT * FROM "BackupSchedule" WHERE "clientId" = ?').get(c);a.backupSchedule=b?D(b,E):null}if(b.licenceLedger){let d=b.licenceLedger.take??10;a.licenceLedger=C('SELECT * FROM "LicenceLedger" WHERE "clientId" = ? ORDER BY "createdAt" DESC LIMIT ?').all(c,d)}if(b.backupJobs){let d=b.backupJobs,e=d.take??10,f=d.where,g=f?.status&&"object"==typeof f.status?f.status.not:void 0;g?a.backupJobs=C('SELECT * FROM "BackupJob" WHERE "clientId" = ? AND "status" != ? ORDER BY "startedAt" DESC LIMIT ?').all(c,g,e):a.backupJobs=C('SELECT * FROM "BackupJob" WHERE "clientId" = ? ORDER BY "startedAt" DESC LIMIT ?').all(c,e)}if(b._count){let d=b._count.select,e={};d?.accounts&&(e.accounts=C('SELECT COUNT(*) as c FROM "ClientAccount" WHERE "clientId" = ?').get(c).c),d?.domains&&(e.domains=C('SELECT COUNT(*) as c FROM "ClientDomain" WHERE "clientId" = ?').get(c).c),d?.sharedDrives&&(e.sharedDrives=C('SELECT COUNT(*) as c FROM "ClientSharedDrive" WHERE "clientId" = ?').get(c).c),a._count=e}return a}let O={count:()=>Promise.resolve(C('SELECT COUNT(*) as c FROM "Client"').get().c),findUnique(a){let b=C('SELECT * FROM "Client" WHERE "id" = ?').get(a.where.id);if(!b)return Promise.resolve(null);return a.include&&N(b,a.include),Promise.resolve(b)},findUniqueOrThrow(a){let b=C('SELECT * FROM "Client" WHERE "id" = ?').get(a.where.id);if(!b)throw Error(`Client ${a.where.id} not found`);return a.include&&N(b,a.include),Promise.resolve(b)},findMany(a){let b='SELECT * FROM "Client"',c=[];if(a?.where&&Object.keys(a.where).length){let{clause:d,params:e}=G(a.where);b+=` WHERE ${d}`,c.push(...e)}let d=C(b+=' ORDER BY "createdAt" DESC').all(...c);return a?.include&&d.forEach(b=>N(b,a.include)),Promise.resolve(d)},create(a){let b=A(),c=a.data.backupSchedule?.create,d={...a.data};delete d.backupSchedule;let e=d.id??(0,g.randomUUID)();return delete d.id,J("Client",{id:e,contactName:d.contactName||null,contactEmail:d.contactEmail||null,contactPhone:d.contactPhone||null,invoicingEmail:d.invoicingEmail||null,notes:d.notes||null,...d,createdAt:b,updatedAt:b}),c&&J("BackupSchedule",{id:(0,g.randomUUID)(),clientId:e,...c,createdAt:b,updatedAt:b}),Promise.resolve(C('SELECT * FROM "Client" WHERE "id" = ?').get(e))},upsert(a){let b=a.where.id?C('SELECT id FROM "Client" WHERE "id" = ?').get(a.where.id):a.where.primaryDomain?C('SELECT id FROM "Client" WHERE "primaryDomain" = ?').get(a.where.primaryDomain):null;return b?Promise.resolve(K("Client",b.id,{...a.update,updatedAt:A()})):O.create({data:a.create})},update:a=>Promise.resolve(K("Client",a.where.id,{...a.data,updatedAt:A()})),delete:a=>(C('DELETE FROM "Client" WHERE "id" = ?').run(a.where.id),Promise.resolve({success:!0}))};function P(a,b,c,d){let e=`SELECT * FROM "${a}"`,f=[];if(b&&Object.keys(b).length){let{clause:a,params:c}=G(b);e+=` WHERE ${a}`,f.push(...c)}if(c){let[a,b]=Object.entries(c)[0];e+=` ORDER BY "${a}" ${"desc"===b?"DESC":"ASC"}`}return d&&(e+=` LIMIT ${d}`),{query:e,params:f}}let Q={gmail:"(mimeType = 'application/json' AND fileName LIKE '%.eml.json')",calendar:"(mimeType = 'application/x-gws-calendar' OR fileName LIKE '%.ics')",contacts:"(mimeType = 'application/x-gws-contacts' OR fileName LIKE '%.vcf')"};function R(a){return"drive"===a?`NOT ${Q.gmail} AND NOT ${Q.calendar} AND NOT ${Q.contacts}`:Q[a]}let S=null,T={upsert(a){let b=w(a.clientId,`
            SELECT id, modifiedTime FROM "BackupFileIndex"
            WHERE clientId = ? AND userEmail = ? AND driveFileId = ? AND destination = ? AND destinationProfileId IS NULL
            ORDER BY modifiedTime DESC
            LIMIT 1
        `).get(a.clientId,a.userEmail,a.driveFileId,a.destination);if(b&&b.modifiedTime===a.modifiedTime)return Promise.resolve();let c=function(){if(null===S)try{let a=z().prepare("SELECT type FROM pragma_table_info('BackupFileIndex') WHERE name = 'id'").get();S="INTEGER"!==(a?.type||"TEXT").toUpperCase()}catch{S=!0}return S}();return w(a.clientId,`
            INSERT OR REPLACE INTO "BackupFileIndex"
                (${c?"id, ":""}clientId, userEmail, driveFileId, fileName, mimeType, modifiedTime, backupJobId, backupPath, destination, preserve, subject, sender, recipient, emailDate, labelIds, size, originalPath, createdAt)
            VALUES (${c?"?, ":""}?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
                COALESCE((SELECT createdAt FROM "BackupFileIndex"
                          WHERE clientId=? AND userEmail=? AND driveFileId=? AND backupJobId=?),
                         strftime('%Y-%m-%dT%H:%M:%fZ','now')))
        `).run(...c?[(0,g.randomUUID)()]:[],a.clientId,a.userEmail,a.driveFileId,a.fileName,a.mimeType,a.modifiedTime,a.backupJobId,a.backupPath,a.destination,a.preserve??0,a.subject??null,a.sender??null,a.recipient??null,a.emailDate??null,a.labelIds??null,a.size??null,a.originalPath??null,a.clientId,a.userEmail,a.driveFileId,a.backupJobId),Promise.resolve()},count(a){let b='SELECT COUNT(*) as c FROM "BackupFileIndex" WHERE "clientId" = ?',c=[a.where.clientId];return a.where.mimeType&&("string"==typeof a.where.mimeType?(b+=' AND "mimeType" = ?',c.push(a.where.mimeType)):a.where.mimeType.not&&(b+=' AND "mimeType" != ?',c.push(a.where.mimeType.not))),Promise.resolve(w(a.where.clientId,b).get(...c).c)},aggregate:a=>Promise.resolve({_sum:{size:w(a.where.clientId,'SELECT SUM(size) as s FROM "BackupFileIndex" WHERE "clientId" = ?').get(a.where.clientId).s||0}}),pruneUnshielded(a){let b=w(a.clientId,`
            SELECT backupPath FROM "BackupFileIndex"
            WHERE clientId = ? AND preserve = 0 AND createdAt < ?
        `).all(a.clientId,a.thresholdIso);return w(a.clientId,`
            DELETE FROM "BackupFileIndex"
            WHERE clientId = ? AND preserve = 0 AND createdAt < ?
        `).run(a.clientId,a.thresholdIso),b},dueForPrune(a){if(q()&&!a.clientId){let b=[];for(let c of u()){if(b.length>=a.limit)break;b.push(...T.dueForPrune({...a,clientId:c,limit:a.limit-b.length}))}return b}let b=a.clientId?"AND clientId = ?":"",c=[a.cutoffIso];return a.clientId&&c.push(a.clientId),c.push(a.limit),w(a.clientId??"",`
            SELECT id, clientId, userEmail, fileName, backupPath, size, deletedAt
            FROM "BackupFileIndex"
            WHERE deletedAt IS NOT NULL AND deletedAt < ?
              AND preserve = 0 AND destinationProfileId IS NULL ${b}
            ORDER BY deletedAt ASC
            LIMIT ?
        `).all(...c)},pruneForecast(a){if(q()){let b=[];for(let c of u()){let d=w(c,`
                    SELECT clientId, COUNT(*) AS items, SUM(COALESCE(size,0)) AS bytes, MIN(deletedAt) AS oldest
                    FROM "BackupFileIndex"
                    WHERE deletedAt IS NOT NULL AND deletedAt < ?
                      AND preserve = 0 AND destinationProfileId IS NULL
                    GROUP BY clientId
                `).all(a);b.push(...d)}return b}return C(`
            SELECT clientId, COUNT(*) AS items, SUM(COALESCE(size,0)) AS bytes, MIN(deletedAt) AS oldest
            FROM "BackupFileIndex"
            WHERE deletedAt IS NOT NULL AND deletedAt < ?
              AND preserve = 0 AND destinationProfileId IS NULL
            GROUP BY clientId
        `).all(a)},freezeActiveIntoProfile(a){if(q()){let b=0;for(let c of u())b+=Number(w(c,`UPDATE "BackupFileIndex" SET destinationProfileId = ?
                                     WHERE destinationProfileId IS NULL`).run(a).changes??0);return b}let b=z();b.exec("BEGIN IMMEDIATE");try{let c=C(`
                INSERT INTO ${l}
                    ("clientId", "userEmail", "driveFileId", "fileName", "mimeType",
                     "modifiedTime", "backupJobId", "backupPath", "destination", "createdAt",
                     "payloadPurged", "preserve", "deletedAt", "deletedAtJobId", "originalPath",
                     "subject", "sender", "recipient", "emailDate", "labelIds", "size",
                     "destinationProfileId")
                SELECT "clientId", "userEmail", "driveFileId", "fileName", "mimeType",
                       "modifiedTime", "backupJobId", "backupPath", "destination", "createdAt",
                       "payloadPurged", "preserve", "deletedAt", "deletedAtJobId", "originalPath",
                       "subject", "sender", "recipient", "emailDate", "labelIds", "size", ?
                FROM "BackupFileIndex" WHERE destinationProfileId IS NULL
            `).run(a);return C('DELETE FROM "BackupFileIndex" WHERE destinationProfileId IS NULL').run(),b.exec("COMMIT"),Number(c.changes??0)}catch(a){throw b.exec("ROLLBACK"),a}},atRiskFromProfile(a){let b=x(a.clientId);return w(a.clientId,`
            SELECT f.id, f.userEmail, f.driveFileId, f.fileName, f.mimeType, f.modifiedTime,
                   f.backupPath, f.size, f.deletedAt, f.originalPath, f.destination
            FROM ${b} f
            WHERE f.clientId = ? AND f.destinationProfileId = ?
              AND f.id = (
                  SELECT f2.id FROM ${b} f2
                  WHERE f2.clientId = f.clientId AND f2.destinationProfileId = f.destinationProfileId
                    AND f2.userEmail = f.userEmail AND f2.driveFileId = f.driveFileId
                  ORDER BY f2.modifiedTime DESC, f2.id DESC LIMIT 1
              )
              AND NOT EXISTS (
                  SELECT 1 FROM "BackupFileIndex" a
                  WHERE a.clientId = f.clientId AND a.destinationProfileId IS NULL
                    AND a.userEmail = f.userEmail AND a.driveFileId = f.driveFileId
              )
            ORDER BY f.userEmail, f.fileName
            LIMIT ?
        `).all(a.clientId,a.profileId,a.limit??1e5)},countForProfile(a){let b=w(a.clientId,`
            SELECT COUNT(*) AS items, COALESCE(SUM(size),0) AS bytes
            FROM ${x(a.clientId)}
            WHERE clientId = ? AND destinationProfileId = ?
        `).get(a.clientId,a.profileId);return{items:Number(b?.items??0),bytes:Number(b?.bytes??0)}},deleteProfileRows:a=>Number(w(a.clientId,`
            DELETE FROM ${x(a.clientId)}
            WHERE clientId = ? AND destinationProfileId = ?
        `).run(a.clientId,a.profileId).changes??0),profileStillInUse(a){for(let b of u())if(w(b,`SELECT 1 FROM ${x(b)} WHERE destinationProfileId = ? LIMIT 1`).get(a))return!0;return!1},summariseByProfile:a=>w(a,`
            SELECT "destinationProfileId" AS profileId, COUNT(*) AS items,
                   COALESCE(SUM(size),0) AS bytes,
                   SUM(CASE WHEN size IS NULL THEN 1 ELSE 0 END) AS unsized
            FROM "BackupFileIndex" WHERE clientId = ?
            GROUP BY "destinationProfileId"
        `).all(a),deleteActiveForClient(a){w(a,`
            DELETE FROM "BackupFileIndex"
            WHERE clientId = ? AND destinationProfileId IS NULL AND preserve = 0
        `).run(a)},listLatestForRestore(a){let b=R(a.type),c=null===a.destinationProfileId?'"BackupFileIndex"':x(a.clientId),d=null===a.destinationProfileId?"destinationProfileId IS NULL":"destinationProfileId = ?",e=[a.clientId,a.userEmail];null!==a.destinationProfileId&&e.push(a.destinationProfileId);let f=a.asOf?"AND createdAt <= ? AND (deletedAt IS NULL OR deletedAt > ?)":"";return a.asOf&&e.push(a.asOf,a.asOf),w(a.clientId,`
            SELECT * FROM (
                SELECT *, ROW_NUMBER() OVER (PARTITION BY driveFileId ORDER BY createdAt DESC) AS rn
                FROM ${c}
                WHERE clientId = ? AND userEmail = ? AND (${b}) AND ${d}
                  ${f}
            ) WHERE rn = 1
        `).all(...e)},listSharedDriveAccounts(a){let b=null===a.destinationProfileId?'"BackupFileIndex"':x(a.clientId),c=null===a.destinationProfileId?"destinationProfileId IS NULL":"destinationProfileId = ?",d=[a.clientId];return null!==a.destinationProfileId&&d.push(a.destinationProfileId),w(a.clientId,`
            SELECT DISTINCT userEmail FROM ${b}
            WHERE clientId = ? AND userEmail LIKE 'shared-drive:%' AND ${c}
            ORDER BY userEmail
        `).all(...d).map(a=>a.userEmail)},changeProfileForJob(a){let b=w(a.clientId,`
            SELECT userEmail,
                   SUM(CASE WHEN isDrive = 1 AND priorMtime IS NOT NULL AND priorMtime <> modifiedTime THEN 1 ELSE 0 END) AS modified,
                   SUM(CASE WHEN priorMtime IS NULL THEN 1 ELSE 0 END) AS added,
                   SUM(CASE WHEN priorMtime IS NOT NULL
                             AND NOT (isDrive = 1 AND priorMtime <> modifiedTime) THEN 1 ELSE 0 END) AS restored
            FROM (
                SELECT f.userEmail, f.modifiedTime,
                       CASE WHEN (${R("drive")}) THEN 1 ELSE 0 END AS isDrive,
                       (SELECT p.modifiedTime FROM "BackupFileIndex" p
                         WHERE p.clientId = f.clientId AND p.userEmail = f.userEmail
                           AND p.driveFileId = f.driveFileId AND p.createdAt < f.createdAt
                         ORDER BY p.createdAt DESC LIMIT 1) AS priorMtime
                FROM "BackupFileIndex" f
                WHERE f.clientId = ? AND f.backupJobId = ? AND f.destinationProfileId IS NULL
            )
            GROUP BY userEmail
        `).all(a.clientId,a.jobId),c=new Map(w(a.clientId,`
            SELECT userEmail, COUNT(DISTINCT driveFileId) AS n
            FROM "BackupFileIndex"
            WHERE clientId = ? AND deletedAtJobId = ? AND destinationProfileId IS NULL
            GROUP BY userEmail
        `).all(a.clientId,a.jobId).map(a=>[a.userEmail,Number(a.n||0)])),d=new Map(w(a.clientId,`
            SELECT userEmail, COUNT(DISTINCT driveFileId) AS n
            FROM "BackupFileIndex"
            WHERE clientId = ? AND createdAt < ? AND destinationProfileId IS NULL
            GROUP BY userEmail
        `).all(a.clientId,a.startedAt).map(a=>[a.userEmail,Number(a.n||0)]));return[...new Set([...b.map(a=>a.userEmail),...c.keys()])].map(a=>{let e=b.find(b=>b.userEmail===a);return{userEmail:a,modified:Number(e?.modified||0),added:Number(e?.added||0),deleted:c.get(a)??0,restored:Number(e?.restored||0),knownBefore:d.get(a)??0}})},listAccountsForRestore(a){let b=null===a.destinationProfileId?'"BackupFileIndex"':x(a.clientId),c=null===a.destinationProfileId?"destinationProfileId IS NULL":"destinationProfileId = ?",d=[a.clientId];return null!==a.destinationProfileId&&d.push(a.destinationProfileId),w(a.clientId,`
            SELECT DISTINCT userEmail FROM ${b}
            WHERE clientId = ? AND ${c}
            ORDER BY userEmail
        `).all(...d).map(a=>a.userEmail)},currentHoldings(a){if(q()&&!a.clientId){let a={emails:0,files:0,calendars:0,contacts:0,bytes:0,unsizedItems:0,deletedAtSource:0};for(let b of u()){let c=T.currentHoldings({clientId:b});a.emails+=c.emails,a.files+=c.files,a.calendars+=c.calendars,a.contacts+=c.contacts,a.bytes+=c.bytes,a.unsizedItems+=c.unsizedItems,a.deletedAtSource+=c.deletedAtSource}return a}let b=a.clientId??"",c=a.clientId?"clientId = ? AND":"",d=a.clientId?[a.clientId]:[],e=`${c} destinationProfileId IS NULL AND payloadPurged = 0`,f=a=>w(b,`
            SELECT COUNT(*) AS c FROM (
                SELECT 1 FROM "BackupFileIndex"
                WHERE ${e} AND (${a})
                GROUP BY userEmail, driveFileId
            )
        `).get(...d)?.c??0,g=w(b,`
            SELECT COALESCE(SUM(size), 0) AS bytes,
                   SUM(CASE WHEN size IS NULL THEN 1 ELSE 0 END) AS unsized
            FROM "BackupFileIndex" WHERE ${e}
        `).get(...d);return{deletedAtSource:w(b,`
            SELECT COUNT(*) AS c FROM (
                SELECT 1 FROM "BackupFileIndex"
                WHERE ${e} AND deletedAt IS NOT NULL GROUP BY userEmail, driveFileId
            )
        `).get(...d)?.c??0,emails:f(R("gmail")),files:f(R("drive")),calendars:f(R("calendar")),contacts:f(R("contacts")),bytes:g?.bytes??0,unsizedItems:g?.unsized??0}},restoreTransferEstimate(a){let b=(a.scope&&"workspace"!==a.scope&&"account"!==a.scope?[a.scope]:["gmail","drive","calendar","contacts"]).map(a=>`(${R(a)})`).join(" OR "),c=[a.clientId],d=a.profileId?x(a.clientId):'"BackupFileIndex"',e="destinationProfileId IS NULL";a.profileId&&(e="destinationProfileId = ?",c.push(a.profileId));let f="";a.accountEmail&&(f=" AND userEmail = ?",c.push(a.accountEmail));let g=w(a.clientId,`
            SELECT userEmail,
                   COALESCE(SUM(size), 0) AS bytes,
                   COUNT(*) AS items,
                   SUM(CASE WHEN size IS NULL THEN 1 ELSE 0 END) AS unsized
            FROM ${d}
            WHERE clientId = ? AND ${e} AND payloadPurged = 0${f}
              AND (${b})
            GROUP BY userEmail
            ORDER BY bytes DESC
        `).all(...c);return{perAccount:g,bytes:g.reduce((a,b)=>a+(b.bytes||0),0),items:g.reduce((a,b)=>a+(b.items||0),0),unsized:g.reduce((a,b)=>a+(b.unsized||0),0)}},heldBytesOverTime(a){if(q()&&!a.clientId){let a=new Map;for(let b of u())for(let c of w(b,`
                    SELECT substr(createdAt, 1, 10) AS day, COALESCE(SUM(size), 0) AS bytes
                    FROM "BackupFileIndex"
                    WHERE destinationProfileId IS NULL AND payloadPurged = 0
                    GROUP BY day
                `).all())a.set(c.day,(a.get(c.day)??0)+Number(c.bytes||0));let b=0;return[...a.entries()].sort((a,b)=>a[0].localeCompare(b[0])).map(([a,c])=>({date:a,bytes:b+=c}))}let b=a.clientId??"",c=a.clientId?"clientId = ? AND":"",d=a.clientId?[a.clientId]:[],e=w(b,`
            SELECT substr(createdAt, 1, 10) AS day, COALESCE(SUM(size), 0) AS bytes
            FROM "BackupFileIndex"
            WHERE ${c} destinationProfileId IS NULL AND payloadPurged = 0
            GROUP BY day ORDER BY day ASC
        `).all(...d),f=0;return e.map(a=>(f+=a.bytes,{date:a.day,bytes:f}))},markMissingAsDeleted(a){let b=w(a.clientId,`
            SELECT DISTINCT driveFileId FROM "BackupFileIndex"
            WHERE clientId = ? AND userEmail = ? AND destinationProfileId IS NULL
              AND deletedAt IS NULL AND (${R(a.type)})
        `).all(a.clientId,a.userEmail).map(a=>a.driveFileId).filter(b=>!a.seenDriveFileIds.has(b));if(0===b.length)return 0;let c=new Date().toISOString(),d=w(a.clientId,`
            UPDATE "BackupFileIndex" SET deletedAt = ?, deletedAtJobId = ?
            WHERE clientId = ? AND userEmail = ? AND driveFileId = ?
              AND destinationProfileId IS NULL AND deletedAt IS NULL
        `);for(let e of b)d.run(c,a.jobId,a.clientId,a.userEmail,e);return b.length},profileIdForJob(a){if(q()){let b=C('SELECT clientId FROM "BackupJob" WHERE id = ?').get(a);if(!b?.clientId)return null;let c=w(b.clientId,'SELECT destinationProfileId FROM "BackupFileIndex" WHERE backupJobId = ? LIMIT 1').get(a);return c?.destinationProfileId??null}let b=C('SELECT destinationProfileId FROM "BackupFileIndex" WHERE backupJobId = ? LIMIT 1').get(a);if(b)return b.destinationProfileId??null;try{let b=C(`SELECT destinationProfileId FROM ${l} WHERE backupJobId = ? LIMIT 1`).get(a);return b?.destinationProfileId??null}catch{return null}},hasAnyActive(){if(q()){for(let a of u())if(w(a,'SELECT 1 FROM "BackupFileIndex" WHERE destinationProfileId IS NULL LIMIT 1').get())return!0;return!1}return!!C('SELECT 1 FROM "BackupFileIndex" WHERE destinationProfileId IS NULL LIMIT 1').get()},listByProfile:a=>null===a.destinationProfileId?w(a.clientId,'SELECT * FROM "BackupFileIndex" WHERE clientId = ? AND destinationProfileId IS NULL').all(a.clientId):w(a.clientId,`SELECT * FROM ${x(a.clientId)} WHERE clientId = ? AND destinationProfileId = ?`).all(a.clientId,a.destinationProfileId),deleteAll(){if(q()){for(let a of u())w(a,'DELETE FROM "BackupFileIndex" WHERE destinationProfileId IS NULL').run();return}C('DELETE FROM "BackupFileIndex"').run()},deleteById(a,b){w(a,'DELETE FROM "BackupFileIndex" WHERE id = ?').run(b)},auditActiveDestination:a=>w(a.clientId,`
            SELECT id, userEmail, driveFileId, backupPath, fileName, mimeType 
            FROM "BackupFileIndex"
            WHERE clientId = ? AND destination = ? AND preserve = 0
            ORDER BY userEmail ASC
        `).all(a.clientId,a.activeDestination),getRetentionForecast(a){let b=w(a.clientId,`
            SELECT 
                SUM(CASE WHEN mimeType = 'application/json' AND fileName LIKE '%.eml.json' THEN 1 ELSE 0 END) as emails,
                SUM(CASE WHEN mimeType != 'application/json' OR fileName NOT LIKE '%.eml.json' THEN 1 ELSE 0 END) as files
            FROM "BackupFileIndex"
            WHERE clientId = ? AND payloadPurged = 0 AND modifiedTime < ?
        `).get(a.clientId,a.thresholdIso);return Promise.resolve({emails:b?.emails||0,files:b?.files||0})},refreshOriginalPath(a,b,c){w(a,'UPDATE "BackupFileIndex" SET originalPath = ? WHERE id = ?').run(c,b)},findLatest:a=>Promise.resolve(w(a.clientId,`
            SELECT * FROM "BackupFileIndex"
            WHERE clientId = ? AND userEmail = ? AND driveFileId = ? AND destination = ? AND destinationProfileId IS NULL
            ORDER BY createdAt DESC
            LIMIT 1
        `).get(a.clientId,a.userEmail,a.driveFileId,a.destination)??null),findByPath:a=>Promise.resolve(w(a.clientId,`
            SELECT * FROM "BackupFileIndex"
            WHERE clientId = ? AND backupPath = ?
            ORDER BY createdAt DESC
            LIMIT 1
        `).get(a.clientId,a.backupPath)??null),findById:a=>Promise.resolve(w(a.clientId,'SELECT * FROM "BackupFileIndex" WHERE id = ?').get(a.id)??null),setPreserve:a=>(w(a.clientId,`
            UPDATE "BackupFileIndex"
            SET preserve = ? 
            WHERE clientId = ? AND driveFileId = ?
        `).run(a.preserve,a.clientId,a.driveFileId),Promise.resolve()),getAggregateStats(a){let b=w(a,`
            SELECT
                SUM(CASE WHEN mimeType = 'application/json' AND fileName LIKE '%.eml.json' THEN 1 ELSE 0 END) as emails,
                SUM(CASE WHEN NOT (mimeType = 'application/json' AND fileName LIKE '%.eml.json') THEN 1 ELSE 0 END) as files
            FROM (
                SELECT driveFileId, fileName, mimeType
                FROM "BackupFileIndex"
                WHERE clientId = ?
                GROUP BY driveFileId
            )
        `).get(a);return Promise.resolve({emails:b?.emails||0,files:b?.files||0})},findVersions:a=>Promise.resolve(w(a.clientId,`
            SELECT * FROM "BackupFileIndex"
            WHERE clientId = ? AND userEmail = ? AND driveFileId = ?
            ORDER BY modifiedTime DESC
        `).all(a.clientId,a.userEmail,a.driveFileId)),search(a){let b=[`%${a.q}%`,a.clientId],c=a.userEmail?"AND userEmail = ?":"";return a.userEmail&&b.push(a.userEmail),Promise.resolve(w(a.clientId,`
            SELECT *, versionCount
            FROM (
                SELECT *, 
                    COUNT(*) OVER (PARTITION BY driveFileId, userEmail) AS versionCount,
                    ROW_NUMBER() OVER (PARTITION BY driveFileId, userEmail ORDER BY createdAt DESC) as rn
                FROM "BackupFileIndex"
                WHERE fileName LIKE ?
                  AND clientId = ?
                  ${c}
                  AND ${R("drive")}
            )
            WHERE rn = 1
            ORDER BY modifiedTime DESC
            LIMIT ?
        `).all(...b,a.limit??50))},browseFiles(a){let b=R(a.type),c=[a.clientId,a.userEmail],d=w(a.clientId,`
            SELECT COUNT(DISTINCT driveFileId) as c
            FROM "BackupFileIndex"
            WHERE clientId = ? AND userEmail = ? AND (${b})
        `).get(...c),e=d?d.c:0,f=[a.clientId,a.userEmail,0===a.limit?-1:a.limit,a.offset];return Promise.resolve({data:w(a.clientId,`
            SELECT *, versionCount
            FROM (
                SELECT *, 
                    COUNT(*) OVER (PARTITION BY driveFileId, userEmail) AS versionCount,
                    ROW_NUMBER() OVER (PARTITION BY driveFileId, userEmail ORDER BY createdAt DESC) as rn
                FROM "BackupFileIndex"
                WHERE clientId = ? AND userEmail = ? AND (${b})
            )
            WHERE rn = 1
            ORDER BY modifiedTime DESC
            LIMIT ? OFFSET ?
        `).all(...f),total:e})},getShieldedAssets(a){let b=a.page||1,c=a.limit||50,d=w(a.clientId,`
            SELECT COUNT(DISTINCT driveFileId) as c
            FROM "BackupFileIndex"
            WHERE clientId = ? AND preserve = 1
        `).get(a.clientId),e=d?d.c:0;return Promise.resolve({data:w(a.clientId,`
            SELECT driveFileId, clientId, userEmail, fileName, mimeType,
                   MAX(modifiedTime) AS modifiedTime, MAX(backupJobId) AS backupJobId,
                   MAX(backupPath) AS backupPath, MAX(createdAt) AS createdAt,
                   MAX(preserve) AS preserve, MIN(id) AS id
            FROM "BackupFileIndex"
            WHERE clientId = ? AND preserve = 1
            GROUP BY driveFileId, userEmail
            ORDER BY modifiedTime DESC
            LIMIT ? OFFSET ?
        `).all(a.clientId,c,(b-1)*c),total:e})},changeConcentration(a){let b=w(a.clientId,`
            SELECT COUNT(*) AS activeFiles, COALESCE(SUM(times),0) AS changes FROM (
                SELECT f.driveFileId, COUNT(*) AS times
                FROM "BackupFileIndex" f
                WHERE f.clientId = ? AND f.destinationProfileId IS NULL AND f.createdAt > ?
                  AND NOT (f.mimeType = 'application/json' AND f.fileName LIKE '%.eml.json')
                  AND NOT (f.fileName LIKE '%.ics') AND NOT (f.fileName LIKE '%.vcf')
                  AND EXISTS (
                      SELECT 1 FROM "BackupFileIndex" p
                      WHERE p.clientId = f.clientId AND p.userEmail = f.userEmail
                        AND p.driveFileId = f.driveFileId AND p.createdAt < f.createdAt
                        AND p.modifiedTime <> f.modifiedTime)
                GROUP BY f.driveFileId
            )
        `).get(a.clientId,a.sinceIso);return{activeFiles:Number(b?.activeFiles??0),changes:Number(b?.changes??0)}},supersededVersions:a=>w(a.clientId,`
            SELECT id, userEmail, driveFileId, fileName, backupPath, size, preserve, createdAt, nextAt
            FROM (
                SELECT id, userEmail, driveFileId, fileName, backupPath, size, preserve, createdAt,
                       LEAD(createdAt) OVER (PARTITION BY userEmail, driveFileId ORDER BY createdAt) AS nextAt
                FROM "BackupFileIndex"
                WHERE clientId = ? AND destinationProfileId IS NULL AND payloadPurged = 0
            )
            WHERE nextAt IS NOT NULL
            ORDER BY createdAt ASC
            LIMIT ?
        `).all(a.clientId,a.limit??1e5),rowsForBackupPath:a=>w(a.clientId,`
            SELECT id FROM "BackupFileIndex"
            WHERE clientId = ? AND backupPath = ? AND destinationProfileId IS NULL
        `).all(a.clientId,a.backupPath),holderCountsForPaths(a){let b=new Map,c=[...new Set(a.paths)];for(let d=0;d<c.length;d+=400){let e=c.slice(d,d+400),f=e.map(()=>"?").join(",");for(let c of w(a.clientId,`
                SELECT backupPath, COUNT(*) AS holders
                FROM "BackupFileIndex"
                WHERE clientId = ? AND destinationProfileId IS NULL
                  AND backupPath IN (${f})
                GROUP BY backupPath
            `).all(a.clientId,...e))b.set(c.backupPath,Number(c.holders))}return b},listVersions:a=>Promise.resolve(w(a.clientId,`
            SELECT * FROM "BackupFileIndex"
            WHERE clientId = ? AND userEmail = ? AND driveFileId = ?
              AND destinationProfileId IS NULL
            ORDER BY createdAt DESC
        `).all(a.clientId,a.userEmail,a.driveFileId)),deleteForClient:a=>(w(a,'DELETE FROM "BackupFileIndex" WHERE clientId = ?').run(a),Promise.resolve())},U={appSettings:M,destinationProfile:{list:()=>Promise.resolve(C('SELECT * FROM "DestinationProfile" ORDER BY ("status" = \'active\') DESC, "frozenAt" DESC, "createdAt" DESC').all()),listFrozen:()=>Promise.resolve(C('SELECT * FROM "DestinationProfile" WHERE "status" = \'frozen\' ORDER BY "frozenAt" DESC').all()),findActive:()=>Promise.resolve(C('SELECT * FROM "DestinationProfile" WHERE "status" = \'active\' ORDER BY "createdAt" DESC LIMIT 1').get()??null),findById:a=>Promise.resolve(C('SELECT * FROM "DestinationProfile" WHERE "id" = ?').get(a)??null),findFrozenByMode:a=>Promise.resolve(C('SELECT * FROM "DestinationProfile" WHERE "status" = \'frozen\' AND "mode" = ? ORDER BY "frozenAt" DESC LIMIT 1').get(a)??null),create:a=>Promise.resolve(J("DestinationProfile",{id:(0,g.randomUUID)(),label:a.label,mode:a.mode,status:a.status??"active",config:a.config,createdAt:A()})),setStatus(a,b){C('UPDATE "DestinationProfile" SET "status" = ?, "frozenAt" = ? WHERE "id" = ?').run(b,"frozen"===b?A():null,a)},deleteById(a){C('DELETE FROM "DestinationProfile" WHERE "id" = ?').run(a)}},client:O,clientAccount:{upsertById:a=>Promise.resolve(L("ClientAccount",a.id,a.data,F)),findMany(a){let{clause:b,params:c}=G(a.where);return Promise.resolve(C(b?`SELECT * FROM "ClientAccount" WHERE ${b} ORDER BY "createdAt" ASC`:'SELECT * FROM "ClientAccount" ORDER BY "createdAt" ASC').all(...c).map(a=>D(a,F)))},count:a=>Promise.resolve(C('SELECT COUNT(*) as c FROM "ClientAccount" WHERE "clientId" = ?').get(a.where.clientId).c),upsert(a){let{clientId:b,email:c}=a.where.clientId_email,d=C('SELECT id FROM "ClientAccount" WHERE "clientId" = ? AND "email" = ?').get(b,c);if(d){let b={...a.update};return"suspended"in b&&(b.suspended=+!!b.suspended),"isDeleted"in b&&(b.isDeleted=+!!b.isDeleted),Promise.resolve(D(K("ClientAccount",d.id,b),F))}let e={...a.create};return"suspended"in e&&(e.suspended=+!!e.suspended),"isDeleted"in e&&(e.isDeleted=+!!e.isDeleted),Promise.resolve(D(J("ClientAccount",{id:(0,g.randomUUID)(),...e,createdAt:A()}),F))},update(a){let b={...a.data};return"suspended"in b&&(b.suspended=+!!b.suspended),"isDeleted"in b&&(b.isDeleted=+!!b.isDeleted),Promise.resolve(D(K("ClientAccount",a.where.id,b),F))}},clientDomain:{upsertById:a=>Promise.resolve(L("ClientDomain",a.id,a.data)),count:a=>Promise.resolve(C('SELECT COUNT(*) as c FROM "ClientDomain" WHERE "clientId" = ?').get(a.where.clientId).c),upsert(a){let{clientId:b,domain:c}=a.where.clientId_domain,d=C('SELECT id FROM "ClientDomain" WHERE "clientId" = ? AND "domain" = ?').get(b,c);return d?Object.keys(a.update).length&&K("ClientDomain",d.id,a.update):J("ClientDomain",{id:(0,g.randomUUID)(),...a.create,createdAt:A()}),Promise.resolve(C('SELECT * FROM "ClientDomain" WHERE "clientId" = ? AND "domain" = ?').get(b,c))}},clientGroup:{upsertById:a=>Promise.resolve(L("ClientGroup",a.id,a.data)),count:a=>Promise.resolve(C('SELECT COUNT(*) as c FROM "ClientGroup" WHERE "clientId" = ?').get(a.where.clientId).c),upsert(a){let{clientId:b,groupEmail:c}=a.where.clientId_groupEmail,d=C('SELECT id FROM "ClientGroup" WHERE "clientId" = ? AND "groupEmail" = ?').get(b,c);return d?Object.keys(a.update).length&&K("ClientGroup",d.id,a.update):J("ClientGroup",{id:(0,g.randomUUID)(),...a.create,createdAt:A()}),Promise.resolve(C('SELECT * FROM "ClientGroup" WHERE "clientId" = ? AND "groupEmail" = ?').get(b,c))},findUnique:a=>Promise.resolve(C('SELECT * FROM "ClientGroup" WHERE "id" = ?').get(a.where.id)),update:a=>Promise.resolve(K("ClientGroup",a.where.id,a.data))},clientSharedDrive:{upsertById:a=>Promise.resolve(L("ClientSharedDrive",a.id,a.data)),count:a=>Promise.resolve(C('SELECT COUNT(*) as c FROM "ClientSharedDrive" WHERE "clientId" = ?').get(a.where.clientId).c),upsert(a){let{clientId:b,driveId:c}=a.where.clientId_driveId,d=C('SELECT id FROM "ClientSharedDrive" WHERE "clientId" = ? AND "driveId" = ?').get(b,c);return d?Object.keys(a.update).length&&K("ClientSharedDrive",d.id,a.update):J("ClientSharedDrive",{id:(0,g.randomUUID)(),...a.create,createdAt:A()}),Promise.resolve(C('SELECT * FROM "ClientSharedDrive" WHERE "clientId" = ? AND "driveId" = ?').get(b,c))}},licenceLedger:{create:a=>Promise.resolve(J("LicenceLedger",{id:(0,g.randomUUID)(),...a.data,createdAt:A()}))},backupSchedule:{findUnique(a){let[b,c]="clientId"in a.where?["clientId",a.where.clientId]:["id",a.where.id],d=C(`SELECT * FROM "BackupSchedule" WHERE "${b}" = ?`).get(c);return Promise.resolve(d?D(d,E):null)},findMany:a=>Promise.resolve(C('SELECT * FROM "BackupSchedule" WHERE "enabled" = ?').all(+!!a.where.enabled).map(a=>D(a,E))),upsert(a){let b=A(),c=C('SELECT id FROM "BackupSchedule" WHERE "clientId" = ?').get(a.where.clientId);if(c){let d={...a.update,updatedAt:b};for(let a of E)a in d&&(d[a]=+!!d[a]);K("BackupSchedule",c.id,d)}else{let c={...a.create};for(let a of E)a in c&&(c[a]=+!!c[a]);J("BackupSchedule",{id:(0,g.randomUUID)(),clientId:a.where.clientId,...c,createdAt:b,updatedAt:b})}return Promise.resolve(D(C('SELECT * FROM "BackupSchedule" WHERE "clientId" = ?').get(a.where.clientId),E))}},backupJob:{findUnique:a=>Promise.resolve(C('SELECT * FROM "BackupJob" WHERE "id" = ?').get(a.where.id)??null),count(a){let b=C('SELECT COUNT(*) as c FROM "BackupJob" WHERE "status" = ?').get(a.where.status);return Promise.resolve(b?b.c:0)},findFirst(a){let{query:b,params:c}=P("BackupJob",a.where,a.orderBy,1);return Promise.resolve(C(b).get(...c)??null)},findMany(a){let{query:b,params:c}=P("BackupJob",a.where,a.orderBy,a.take);return Promise.resolve(C(b).all(...c))},create:a=>Promise.resolve(J("BackupJob",{id:(0,g.randomUUID)(),...a.data,status:a.data.status??"running",startedAt:A(),stats:"{}"})),update:a=>Promise.resolve(K("BackupJob",a.where.id,a.data))},restoreJob:{findUnique:a=>Promise.resolve(C('SELECT * FROM "RestoreJob" WHERE "id" = ?').get(a.where.id)??null),findMany(a){let{query:b,params:c}=P("RestoreJob",a.where,a.orderBy,a.take);return Promise.resolve(C(b).all(...c))},create:a=>Promise.resolve(J("RestoreJob",{id:(0,g.randomUUID)(),...a.data,requestedAt:A()})),update:a=>Promise.resolve(K("RestoreJob",a.where.id,a.data))},restoreItemLog:{markDone(a,b){C('INSERT OR IGNORE INTO "RestoreItemLog" ("rootJobId","indexRowId") VALUES (?,?)').run(a,b)},doneIds:a=>new Set(C('SELECT "indexRowId" FROM "RestoreItemLog" WHERE "rootJobId" = ?').all(a).map(a=>a.indexRowId)),count(a){let b=C('SELECT COUNT(*) AS c FROM "RestoreItemLog" WHERE "rootJobId" = ?').get(a);return b?.c??0},clearChain(a){C('DELETE FROM "RestoreItemLog" WHERE "rootJobId" = ?').run(a),C('DELETE FROM "RestoreItemFailure" WHERE "rootJobId" = ?').run(a)},recordFailure(a,b,c,d,e){C(`
            INSERT INTO "RestoreItemFailure" ("rootJobId","indexRowId","attempts","permanent","lastError","fileName","lastAttemptAt")
            VALUES (?, ?, 1, ?, ?, ?, strftime('%Y-%m-%dT%H:%M:%fZ','now'))
            ON CONFLICT("rootJobId","indexRowId") DO UPDATE SET
                attempts = attempts + 1,
                permanent = MAX(permanent, excluded.permanent),
                lastError = excluded.lastError,
                lastAttemptAt = excluded.lastAttemptAt
        `).run(a,b,+!!e,d.slice(0,500),c.slice(0,300))},clearFailure(a,b){C('DELETE FROM "RestoreItemFailure" WHERE "rootJobId" = ? AND "indexRowId" = ?').run(a,b)},abandonedIds:(a,b)=>new Set(C(`
            SELECT "indexRowId" FROM "RestoreItemFailure"
            WHERE "rootJobId" = ? AND ("permanent" = 1 OR "attempts" >= ?)
        `).all(a,b).map(a=>a.indexRowId)),abandoned:(a,b)=>C(`
            SELECT "indexRowId", "fileName", "attempts", "permanent", "lastError"
            FROM "RestoreItemFailure"
            WHERE "rootJobId" = ? AND ("permanent" = 1 OR "attempts" >= ?)
            ORDER BY "lastAttemptAt" DESC
        `).all(a,b),clearAbandoned(a){let b=C('SELECT COUNT(*) AS c FROM "RestoreItemFailure" WHERE "rootJobId" = ?').get(a).c;return C('DELETE FROM "RestoreItemFailure" WHERE "rootJobId" = ?').run(a),b}},auditLog:{create(a){let b=(0,g.randomUUID)(),c={...a.data};if(c.clientId&&(!c.clientName||!c.clientDomain)){let a=C('SELECT "name", "primaryDomain" FROM "Client" WHERE "id" = ?').get(c.clientId);a&&(c.clientName||(c.clientName=a.name??null),c.clientDomain||(c.clientDomain=a.primaryDomain??null))}return Promise.resolve(J("AuditLog",{id:b,...c,detail:c.detail??"",createdAt:A()}))},findMany(a){let b='SELECT * FROM "AuditLog"',c=[];if(a?.where&&Object.keys(a.where).length){let{clause:d,params:e}=G(a.where);b+=` WHERE ${d}`,c.push(...e)}return b+=' ORDER BY "createdAt" DESC',a?.take&&(b+=` LIMIT ${a.take}`),Promise.resolve(C(b).all(...c))}},backupFileIndex:T,reportTemplate:{findMany:a=>{let b='SELECT * FROM "ReportTemplate"';return a?.orderBy?.createdAt==="desc"&&(b+=' ORDER BY "createdAt" DESC'),C(b).all()},create:a=>{let b=a.data.id||(0,g.randomUUID)(),c=a.data,d=Array.isArray(c.entities)?JSON.stringify(c.entities):c.entities||"[]",e=Array.isArray(c.metrics)?JSON.stringify(c.metrics):c.metrics||"[]";return C('INSERT INTO "ReportTemplate" ("id", "name", "targetType", "targetClientId", "entities", "metrics", "periodMonths", "globalStrategy", "customText", "layoutFormat", "layoutOrientation", "layoutColumns") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)').run(b,c.name,c.targetType,c.targetClientId||null,d,e,c.periodMonths,c.globalStrategy||"aggregate",c.customText||"",c.layoutFormat||"A4",c.layoutOrientation||"portrait",c.layoutColumns||1),{id:b,...a.data,entities:d,metrics:e}},update:a=>{let b=a.data,c=[],d=[];if(void 0!==b.name&&(c.push('"name" = ?'),d.push(b.name)),void 0!==b.targetType&&(c.push('"targetType" = ?'),d.push(b.targetType)),void 0!==b.targetClientId&&(c.push('"targetClientId" = ?'),d.push(b.targetClientId||null)),void 0!==b.entities&&(c.push('"entities" = ?'),d.push(Array.isArray(b.entities)?JSON.stringify(b.entities):b.entities||"[]")),void 0!==b.metrics&&(c.push('"metrics" = ?'),d.push(Array.isArray(b.metrics)?JSON.stringify(b.metrics):b.metrics||"[]")),void 0!==b.periodMonths&&(c.push('"periodMonths" = ?'),d.push(b.periodMonths)),void 0!==b.globalStrategy&&(c.push('"globalStrategy" = ?'),d.push(b.globalStrategy)),void 0!==b.customText&&(c.push('"customText" = ?'),d.push(b.customText)),void 0!==b.layoutFormat&&(c.push('"layoutFormat" = ?'),d.push(b.layoutFormat)),void 0!==b.layoutOrientation&&(c.push('"layoutOrientation" = ?'),d.push(b.layoutOrientation)),void 0!==b.layoutColumns&&(c.push('"layoutColumns" = ?'),d.push(b.layoutColumns)),c.push("\"updatedAt\" = (strftime('%Y-%m-%dT%H:%M:%fZ','now'))"),c.length>0){let b=`UPDATE "ReportTemplate" SET ${c.join(", ")} WHERE "id" = ?`;d.push(a.where.id),C(b).run(...d)}return{id:a.where.id,...b}},delete:a=>{C('DELETE FROM "ReportTemplate" WHERE "id" = ?').run(a.where.id)}},appUser:{create:a=>Promise.resolve(J("AppUser",{id:(0,g.randomUUID)(),...a.data,createdAt:A(),updatedAt:A()})),findMany:()=>Promise.resolve(C('SELECT * FROM "AppUser" ORDER BY "createdAt" DESC').all()),findByEmail:a=>Promise.resolve(C('SELECT * FROM "AppUser" WHERE "email" = ?').get(a.where.email)),findById:a=>Promise.resolve(C('SELECT * FROM "AppUser" WHERE "id" = ?').get(a)),bumpTokenVersion(a){C('UPDATE "AppUser" SET "tokenVersion" = COALESCE("tokenVersion", 0) + 1, "updatedAt" = ? WHERE "id" = ?').run(A(),a)},update:a=>Promise.resolve(K("AppUser",a.where.id,{...a.data,updatedAt:A()})),delete(a){C('DELETE FROM "AppUser" WHERE "id" = ?').run(a.where.id)}},reset:()=>(z().exec(`
            DELETE FROM LinuxFileIndex;
            DELETE FROM LinuxBackupJob;
            DELETE FROM LinuxServer;
            DELETE FROM BackupFileIndex;
            DELETE FROM AuditLog;
            DELETE FROM RestoreItemLog;
            DELETE FROM RestoreJob;
            DELETE FROM BackupJob;
            DELETE FROM BackupSchedule;
            DELETE FROM LicenceLedger;
            DELETE FROM ClientSharedDrive;
            DELETE FROM ClientGroup;
            DELETE FROM ClientDomain;
            DELETE FROM ClientAccount;
            DELETE FROM Client;
            DELETE FROM AppSettings;
            DELETE FROM ReportTemplate;
            DELETE FROM AppUser;
        `),Promise.resolve()),resetClientData(a){let b=z();b.exec("BEGIN");try{b.prepare('DELETE FROM "LinuxFileIndex" WHERE "clientId" = ?').run(a),b.prepare('DELETE FROM "LinuxBackupJob" WHERE "clientId" = ?').run(a),b.prepare('DELETE FROM "LinuxServer"    WHERE "clientId" = ?').run(a),b.prepare('DELETE FROM "BackupFileIndex" WHERE "clientId" = ?').run(a),b.prepare('DELETE FROM "BackupJob"       WHERE "clientId" = ?').run(a),b.prepare('DELETE FROM "RestoreJob"     WHERE "clientId" = ?').run(a),b.prepare('DELETE FROM "LicenceLedger"  WHERE "clientId" = ?').run(a),b.prepare('DELETE FROM "ClientAccount"  WHERE "clientId" = ?').run(a),b.prepare('DELETE FROM "ClientDomain"   WHERE "clientId" = ?').run(a),b.prepare('DELETE FROM "ClientGroup"    WHERE "clientId" = ?').run(a),b.prepare('DELETE FROM "ClientSharedDrive" WHERE "clientId" = ?').run(a),b.prepare('UPDATE "Client" SET "status" = \'pending\', "errorMessage" = NULL, "statusChangedAt" = ? WHERE "id" = ?').run(new Date().toISOString(),a),b.exec("COMMIT")}catch(a){throw b.exec("ROLLBACK"),a}return Promise.resolve()},rawGet:(a,b=[])=>z().prepare(a).get(...b),rawAll:(a,b=[])=>z().prepare(a).all(...b),rawRun(a,b=[]){z().prepare(a).run(...b)},vacuum(){try{z().exec("VACUUM")}catch(a){console.error("[db] Vacuum failed:",a)}try{z().exec('VACUUM "archive"')}catch(a){console.error("[db] Archive vacuum failed:",a)}if(q())for(let a of u())try{let b=s(a);b.exec("VACUUM"),b.exec("PRAGMA wal_checkpoint(TRUNCATE)")}catch(b){console.error(`[db] Vacuum failed for client ${a}:`,b)}try{z().exec("PRAGMA wal_checkpoint(TRUNCATE)")}catch(a){console.error("[db] WAL checkpoint failed:",a)}return Promise.resolve()}}},80408:()=>{},87032:()=>{}};