diff --git a/apps/web/.eslintignore b/apps/web/.eslintignore index 99b52a07f6..321e1ec56f 100644 --- a/apps/web/.eslintignore +++ b/apps/web/.eslintignore @@ -4,7 +4,6 @@ build/* out/* public/* -core/local-db/worker/wa-sqlite/src/* dist/* node_modules/* .turbo/* diff --git a/apps/web/core/components/issues/peek-overview/view.tsx b/apps/web/core/components/issues/peek-overview/view.tsx index fa4f514312..d9febc7a14 100644 --- a/apps/web/core/components/issues/peek-overview/view.tsx +++ b/apps/web/core/components/issues/peek-overview/view.tsx @@ -62,7 +62,7 @@ export const IssueView: FC = observer((props) => { const { setPeekIssue, isAnyModalOpen, - issue: { getIssueById, getIsLocalDBIssueDescription }, + issue: { getIssueById }, } = useIssueDetail(); const { isAnyModalOpen: isAnyEpicModalOpen } = useIssueDetail(EIssueServiceType.EPICS); const issue = getIssueById(issueId); @@ -72,8 +72,6 @@ export const IssueView: FC = observer((props) => { if (embedIssue && embedRemoveCurrentNotification) embedRemoveCurrentNotification(); }; - const isLocalDBIssueDescription = getIsLocalDBIssueDescription(issueId); - const toggleDeleteIssueModal = (value: boolean) => setIsDeleteIssueModalOpen(value); const toggleArchiveIssueModal = (value: boolean) => setIsArchiveIssueModalOpen(value); const toggleDuplicateIssueModal = (value: boolean) => setIsDuplicateIssueModalOpen(value); @@ -177,7 +175,7 @@ export const IssueView: FC = observer((props) => { projectId={projectId} issueId={issueId} issueOperations={issueOperations} - disabled={disabled || isLocalDBIssueDescription} + disabled={disabled} isArchived={is_archived} isSubmitting={isSubmitting} setIsSubmitting={(value) => setIsSubmitting(value)} @@ -218,7 +216,7 @@ export const IssueView: FC = observer((props) => { projectId={projectId} issueId={issueId} issueOperations={issueOperations} - disabled={disabled || isLocalDBIssueDescription} + disabled={disabled} isArchived={is_archived} isSubmitting={isSubmitting} setIsSubmitting={(value) => setIsSubmitting(value)} diff --git a/apps/web/core/constants/fetch-keys.ts b/apps/web/core/constants/fetch-keys.ts index f29b58a1d5..61b718d922 100644 --- a/apps/web/core/constants/fetch-keys.ts +++ b/apps/web/core/constants/fetch-keys.ts @@ -77,8 +77,6 @@ export const WORKSPACE_STATES = (workspaceSlug: string) => `WORKSPACE_STATES_${w export const WORKSPACE_SIDEBAR_PREFERENCES = (workspaceSlug: string) => `WORKSPACE_SIDEBAR_PREFERENCES_${workspaceSlug.toUpperCase()}`; -export const WORKSPACE_DB = (workspaceSlug: string) => `WORKSPACE_DB_${workspaceSlug.toUpperCase()}`; - export const PROJECT_GITHUB_REPOSITORY = (projectId: string) => `PROJECT_GITHUB_REPOSITORY_${projectId.toUpperCase()}`; // cycles diff --git a/apps/web/core/layouts/auth-layout/project-wrapper.tsx b/apps/web/core/layouts/auth-layout/project-wrapper.tsx index e0a25c961f..ce166a6a59 100644 --- a/apps/web/core/layouts/auth-layout/project-wrapper.tsx +++ b/apps/web/core/layouts/auth-layout/project-wrapper.tsx @@ -36,9 +36,7 @@ import { useProjectState } from "@/hooks/store/use-project-state"; import { useProjectView } from "@/hooks/store/use-project-view"; import { useUserPermissions } from "@/hooks/store/user"; import { useTimeLineChart } from "@/hooks/use-timeline-chart"; -// local -import { persistence } from "@/local-db/storage.sqlite"; -// plane web constants + interface IProjectAuthWrapper { workspaceSlug: string; projectId?: string; @@ -86,21 +84,6 @@ export const ProjectAuthWrapper: FC = observer((props) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - useSWR( - workspaceSlug && projectId ? `PROJECT_SYNC_ISSUES_${workspaceSlug.toString()}_${projectId.toString()}` : null, - workspaceSlug && projectId - ? () => { - persistence.syncIssues(projectId.toString()); - } - : null, - { - revalidateIfStale: true, - revalidateOnFocus: true, - revalidateOnReconnect: true, - refreshInterval: 5 * 60 * 1000, - } - ); - // fetching project details useSWR( workspaceSlug && projectId ? PROJECT_DETAILS(workspaceSlug.toString(), projectId.toString()) : null, diff --git a/apps/web/core/layouts/auth-layout/workspace-wrapper.tsx b/apps/web/core/layouts/auth-layout/workspace-wrapper.tsx index 050aefdd8c..924c997560 100644 --- a/apps/web/core/layouts/auth-layout/workspace-wrapper.tsx +++ b/apps/web/core/layouts/auth-layout/workspace-wrapper.tsx @@ -6,7 +6,6 @@ import Image from "next/image"; import Link from "next/link"; import { useParams } from "next/navigation"; import useSWR from "swr"; -import useSWRImmutable from "swr/immutable"; // ui import { LogOut } from "lucide-react"; import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants"; @@ -29,7 +28,6 @@ import { WORKSPACE_FAVORITE, WORKSPACE_STATES, WORKSPACE_SIDEBAR_PREFERENCES, - WORKSPACE_DB, } from "@/constants/fetch-keys"; import { useFavorite } from "@/hooks/store/use-favorite"; import { useMember } from "@/hooks/store/use-member"; @@ -38,8 +36,6 @@ import { useProjectState } from "@/hooks/store/use-project-state"; import { useWorkspace } from "@/hooks/store/use-workspace"; import { useUser, useUserPermissions } from "@/hooks/store/user"; import { usePlatformOS } from "@/hooks/use-platform-os"; -// local -import { persistence } from "@/local-db/storage.sqlite"; interface IWorkspaceAuthWrapper { children: ReactNode; @@ -120,20 +116,6 @@ export const WorkspaceAuthWrapper: FC = observer((props) { revalidateIfStale: false, revalidateOnFocus: false } ); - // initialize the local database - const { isLoading: isDBInitializing } = useSWRImmutable( - workspaceSlug ? WORKSPACE_DB(workspaceSlug.toString()) : null, - workspaceSlug - ? async () => { - // persistence.reset(); - await persistence.initialize(workspaceSlug.toString()); - // Load common data - persistence.syncWorkspace(); - return true; - } - : null - ); - const handleSignOut = async () => { await signOut().catch(() => setToast({ @@ -145,7 +127,7 @@ export const WorkspaceAuthWrapper: FC = observer((props) }; // if list of workspaces are not there then we have to render the spinner - if (isParentLoading || allWorkspaces === undefined || loader || isDBInitializing) { + if (isParentLoading || allWorkspaces === undefined || loader) { return (
diff --git a/apps/web/core/local-db/storage.sqlite.ts b/apps/web/core/local-db/storage.sqlite.ts deleted file mode 100644 index 3e926bdbeb..0000000000 --- a/apps/web/core/local-db/storage.sqlite.ts +++ /dev/null @@ -1,492 +0,0 @@ -import * as Comlink from "comlink"; -import { set } from "lodash-es"; -// plane -import { EIssueGroupBYServerToProperty } from "@plane/constants"; -import type { TIssue, TIssueParams } from "@plane/types"; -// lib -import { rootStore } from "@/lib/store-context"; -// services -import { IssueService } from "@/services/issue/issue.service"; -// -import { ARRAY_FIELDS, BOOLEAN_FIELDS } from "./utils/constants"; -import { getSubIssuesWithDistribution } from "./utils/data.utils"; -import createIndexes from "./utils/indexes"; -import { addIssuesBulk, syncDeletesToLocal } from "./utils/load-issues"; -import { loadWorkSpaceData } from "./utils/load-workspace"; -import { issueFilterCountQueryConstructor, issueFilterQueryConstructor } from "./utils/query-constructor"; -import { runQuery } from "./utils/query-executor"; -import { sanitizeWorkItemQueries } from "./utils/query-sanitizer.ts"; -import { createTables } from "./utils/tables"; -import { clearOPFS, getGroupedIssueResults, getSubGroupedIssueResults, log, logError } from "./utils/utils"; - -const DB_VERSION = 1.3; -const PAGE_SIZE = 500; -const BATCH_SIZE = 50; - -type TProjectStatus = { - issues: { status: undefined | "loading" | "ready" | "error" | "syncing"; sync: Promise | undefined }; -}; - -type TDBStatus = "initializing" | "ready" | "error" | undefined; -export class Storage { - db: any; - status: TDBStatus = undefined; - dbName = "plane"; - projectStatus: Record = {}; - workspaceSlug: string = ""; - - constructor() { - this.db = null; - - if (typeof window !== "undefined") { - window.addEventListener("beforeunload", this.closeDBConnection); - } - } - - closeDBConnection = async () => { - if (this.db) { - await this.db.close(); - } - }; - - reset = () => { - if (this.db) { - this.db.close(); - } - this.db = null; - this.status = undefined; - this.projectStatus = {}; - this.workspaceSlug = ""; - }; - - clearStorage = async (force = false) => { - try { - await this.db?.close(); - await clearOPFS(force); - this.reset(); - } catch (e) { - console.error("Error clearing sqlite sync storage", e); - } - }; - - private initializeWorker = async (workspaceSlug: string) => { - const { DBClass } = await import("./worker/db"); - const worker = new Worker(new URL("./worker/db.ts", import.meta.url)); - const MyWorker = Comlink.wrap(worker); - - // Add cleanup on window unload - window.addEventListener("unload", () => worker.terminate()); - - this.workspaceSlug = workspaceSlug; - this.dbName = workspaceSlug; - const instance = await new MyWorker(); - await instance.init(workspaceSlug); - - this.db = { - exec: instance.exec, - close: instance.close, - }; - }; - - initialize = async (workspaceSlug: string): Promise => { - if (!rootStore.user.localDBEnabled) return false; // return if the window gets hidden - - if (workspaceSlug !== this.workspaceSlug) { - this.reset(); - } - - try { - await this._initialize(workspaceSlug); - return true; - } catch (err) { - logError(err); - this.status = "error"; - return false; - } - }; - - _initialize = async (workspaceSlug: string): Promise => { - if (this.status === "initializing") { - console.warn(`Initialization already in progress for workspace ${workspaceSlug}`); - return false; - } - if (this.status === "ready") { - console.warn(`Already initialized for workspace ${workspaceSlug}`); - return true; - } - if (this.status === "error") { - console.warn(`Initialization failed for workspace ${workspaceSlug}`); - return false; - } - - try { - this.workspaceSlug = workspaceSlug; - this.dbName = workspaceSlug; - await this.initializeWorker(workspaceSlug); - - const dbVersion = await this.getOption("DB_VERSION"); - log("Stored db version", dbVersion); - log("Current db version", DB_VERSION); - // Check if the database version matches the current version - // If there's a mismatch, clear storage to avoid compatibility issues - if ( - dbVersion !== undefined && - dbVersion !== "" && - !isNaN(Number(dbVersion)) && - Number(dbVersion) !== DB_VERSION - ) { - log("Database version mismatch detected - clearing storage to ensure compatibility"); - await this.clearStorage(); - await this.initializeWorker(workspaceSlug); - } else { - log("Database version matches current version - proceeding with data load"); - } - - this.status = "ready"; - // Your SQLite code here. - await createTables(); - - await this.setOption("DB_VERSION", DB_VERSION.toString()); - return true; - } catch (error) { - this.status = "error"; - this.db = null; - throw new Error(`Failed to initialize database worker: ${error}`); - } - }; - - syncWorkspace = async () => { - if (!rootStore.user.localDBEnabled) return; - const syncInProgress = await this.getIsWriteInProgress("sync_workspace"); - if (syncInProgress) { - log("Sync in progress, skipping"); - return; - } - try { - this.setOption("sync_workspace", new Date().toUTCString()); - await loadWorkSpaceData(this.workspaceSlug); - this.deleteOption("sync_workspace"); - } catch (e) { - logError(e); - this.deleteOption("sync_workspace"); - } - }; - - syncProject = async (projectId: string) => { - if ( - // document.hidden || - !rootStore.user.localDBEnabled - ) - return false; // return if the window gets hidden - - // Load labels, members, states, modules, cycles - await this.syncIssues(projectId); - - // // Sync rest of the projects - // const projects = await getProjectIds(); - - // // Exclude the one we just synced - // const projectsToSync = projects.filter((p: string) => p !== projectId); - // for (const project of projectsToSync) { - // await delay(8000); - // await this.syncIssues(project); - // } - // this.setOption("workspace_synced_at", new Date().toISOString()); - }; - - syncIssues = async (projectId: string) => { - if (!rootStore.user.localDBEnabled || !this.db) { - return false; - } - try { - const sync = this._syncIssues(projectId); - this.setSync(projectId, sync); - await sync; - } catch (e) { - logError(e); - this.setStatus(projectId, "error"); - } - }; - - _syncIssues = async (projectId: string) => { - log("### Sync started"); - let status = this.getStatus(projectId); - if (status === "loading" || status === "syncing") { - log(`Project ${projectId} is already loading or syncing`); - return; - } - const syncPromise = this.getSync(projectId); - - if (syncPromise) { - // Redundant check? - return; - } - - const queryParams: { cursor: string; updated_at__gt?: string; description: boolean } = { - cursor: `${PAGE_SIZE}:0:0`, - description: true, - }; - - const syncedAt = await this.getLastSyncTime(projectId); - const projectSync = await this.getOption(projectId); - - if (syncedAt) { - queryParams["updated_at__gt"] = syncedAt; - } - - this.setStatus(projectId, projectSync === "ready" ? "syncing" : "loading"); - status = this.getStatus(projectId); - - log(`### ${projectSync === "ready" ? "Syncing" : "Loading"} issues to local db for project ${projectId}`); - - const start = performance.now(); - const issueService = new IssueService(); - - const response = await issueService.getIssuesForSync(this.workspaceSlug, projectId, queryParams); - - await addIssuesBulk(response.results, BATCH_SIZE); - if (response.total_pages > 1) { - const promiseArray = []; - for (let i = 1; i < response.total_pages; i++) { - queryParams.cursor = `${PAGE_SIZE}:${i}:0`; - promiseArray.push(issueService.getIssuesForSync(this.workspaceSlug, projectId, queryParams)); - } - const pages = await Promise.all(promiseArray); - for (const page of pages) { - await addIssuesBulk(page.results, BATCH_SIZE); - } - } - - if (syncedAt) { - await syncDeletesToLocal(this.workspaceSlug, projectId, { updated_at__gt: syncedAt }); - } - log("### Time taken to add work items", performance.now() - start); - - if (status === "loading") { - await createIndexes(); - } - this.setOption(projectId, "ready"); - this.setStatus(projectId, "ready"); - this.setSync(projectId, undefined); - }; - - getIssueCount = async (projectId: string) => { - const count = await runQuery(`select count(*) as count from issues where project_id='${projectId}'`); - return count[0]["count"]; - }; - - getLastUpdatedIssue = async (projectId: string) => { - const lastUpdatedIssue = await runQuery( - `select id, name, updated_at , sequence_id from issues WHERE project_id='${projectId}' AND is_local_update IS NULL order by datetime(updated_at) desc limit 1 ` - ); - - if (lastUpdatedIssue.length) { - return lastUpdatedIssue[0]; - } - return; - }; - - getLastSyncTime = async (projectId: string) => { - const issue = await this.getLastUpdatedIssue(projectId); - if (!issue) { - return false; - } - return issue.updated_at; - }; - - getIssues = async ( - workspaceSlug: string, - projectId: string, - queries: Partial> | undefined, - config: any - ) => { - log("#### Queries", queries); - - const currentProjectStatus = this.getStatus(projectId); - if ( - !currentProjectStatus || - this.status !== "ready" || - currentProjectStatus === "loading" || - currentProjectStatus === "error" || - !rootStore.user.localDBEnabled - ) { - if (rootStore.user.localDBEnabled) { - log(`Project ${projectId} is loading, falling back to server`); - } - const issueService = new IssueService(); - - // Ignore projectStatus if projectId is not provided - if (projectId) { - return await issueService.getIssuesFromServer(workspaceSlug, projectId, queries, config); - } - if (this.status !== "ready" && !rootStore.user.localDBEnabled) { - return; - } - } - - const sanitizedQueries = sanitizeWorkItemQueries(workspaceSlug, projectId, queries); - const { cursor, group_by, sub_group_by } = sanitizedQueries || {}; - - const query = issueFilterQueryConstructor(this.workspaceSlug, projectId, sanitizedQueries); - log("#### Query", query); - const countQuery = issueFilterCountQueryConstructor(this.workspaceSlug, projectId, sanitizedQueries); - const start = performance.now(); - let issuesRaw: any[] = []; - let count: any[]; - try { - [issuesRaw, count] = await Promise.all([runQuery(query), runQuery(countQuery)]); - } catch (e) { - log("Unable to get work items from local db, falling back to server"); - logError(e); - const issueService = new IssueService(); - return await issueService.getIssuesFromServer(workspaceSlug, projectId, queries, config); - } - const end = performance.now(); - - const { total_count } = count[0]; - - const [pageSize, page, offset] = cursor && typeof cursor === "string" ? cursor.split(":") : []; - - const groupByProperty: string = - EIssueGroupBYServerToProperty[group_by as keyof typeof EIssueGroupBYServerToProperty]; - const subGroupByProperty = - EIssueGroupBYServerToProperty[sub_group_by as keyof typeof EIssueGroupBYServerToProperty]; - - const parsingStart = performance.now(); - let issueResults = issuesRaw.map((issue: any) => formatLocalIssue(issue)); - - log("#### Work item Results", issueResults.length); - - const parsingEnd = performance.now(); - - const grouping = performance.now(); - if (groupByProperty && page === "0") { - if (subGroupByProperty) { - issueResults = getSubGroupedIssueResults(issueResults); - } else { - issueResults = getGroupedIssueResults(issueResults); - } - } - const groupCount = group_by ? Object.keys(issueResults).length : undefined; - // const subGroupCount = sub_group_by ? Object.keys(issueResults[Object.keys(issueResults)[0]]).length : undefined; - const groupingEnd = performance.now(); - - const times = { - IssueQuery: end - start, - Parsing: parsingEnd - parsingStart, - Grouping: groupingEnd - grouping, - }; - if ((window as any).DEBUG) { - console.table(times); - } - const total_pages = Math.ceil(total_count / Number(pageSize)); - const next_page_results = total_pages > parseInt(page) + 1; - - const out = { - results: issueResults, - next_cursor: `${pageSize}:${parseInt(page) + 1}:${Number(offset) + Number(pageSize)}`, - prev_cursor: `${pageSize}:${parseInt(page) - 1}:${Number(offset) - Number(pageSize)}`, - total_results: total_count, - total_count, - next_page_results, - total_pages, - }; - return out; - }; - - getIssue = async (issueId: string) => { - try { - if (!rootStore.user.localDBEnabled || this.status !== "ready") return; - - const issues = await runQuery(`select * from issues where id='${issueId}'`); - if (Array.isArray(issues) && issues.length) { - return formatLocalIssue(issues[0]); - } - } catch (err) { - logError(err); - console.warn("unable to fetch issue from local db"); - } - - return; - }; - - getSubIssues = async (workspaceSlug: string, projectId: string, issueId: string) => { - const workspace_synced_at = await this.getOption("workspace_synced_at"); - if (!workspace_synced_at) { - const issueService = new IssueService(); - return await issueService.subIssues(workspaceSlug, projectId, issueId); - } - return await getSubIssuesWithDistribution(issueId); - }; - - getStatus = (projectId: string) => this.projectStatus[projectId]?.issues?.status || undefined; - setStatus = (projectId: string, status: "loading" | "ready" | "error" | "syncing" | undefined = undefined) => { - set(this.projectStatus, `${projectId}.issues.status`, status); - }; - - getSync = (projectId: string) => this.projectStatus[projectId]?.issues?.sync; - setSync = (projectId: string, sync: Promise | undefined) => { - set(this.projectStatus, `${projectId}.issues.sync`, sync); - }; - - getOption = async (key: string, fallback?: string | boolean | number) => { - try { - const options = await runQuery(`select * from options where key='${key}'`); - if (options.length) { - return options[0].value; - } - - return fallback; - } catch (e) { - return fallback; - } - }; - setOption = async (key: string, value: string) => { - await runQuery(`insert or replace into options (key, value) values ('${key}', '${value}')`); - }; - - deleteOption = async (key: string) => { - await runQuery(` DELETE FROM options where key='${key}'`); - }; - getOptions = async (keys: string[]) => { - const options = await runQuery(`select * from options where key in ('${keys.join("','")}')`); - return options.reduce((acc: any, option: any) => { - acc[option.key] = option.value; - return acc; - }, {}); - }; - - getIsWriteInProgress = async (op: string) => { - const writeStartTime = await this.getOption(op, false); - if (writeStartTime) { - // Check if it has been more than 5seconds - const current = new Date(); - const start = new Date(writeStartTime); - - if (current.getTime() - start.getTime() < 5000) { - return true; - } - return false; - } - return false; - }; -} - -export const persistence = new Storage(); - -/** - * format the issue fetched from local db into an issue - * @param issue - * @returns - */ -export const formatLocalIssue = (issue: any) => { - const currIssue = issue; - ARRAY_FIELDS.forEach((field: string) => { - currIssue[field] = currIssue[field] ? JSON.parse(currIssue[field]) : []; - }); - // Convert boolean fields to actual boolean values - BOOLEAN_FIELDS.forEach((field: string) => { - currIssue[field] = currIssue[field] === 1; - }); - return currIssue as TIssue & { group_id?: string; total_issues: number; sub_group_id?: string }; -}; diff --git a/apps/web/core/local-db/utils/constants.ts b/apps/web/core/local-db/utils/constants.ts deleted file mode 100644 index 11b60bda04..0000000000 --- a/apps/web/core/local-db/utils/constants.ts +++ /dev/null @@ -1,23 +0,0 @@ -export const ARRAY_FIELDS = ["label_ids", "assignee_ids", "module_ids"]; - -export const BOOLEAN_FIELDS = ["is_draft"]; - -export const GROUP_BY_MAP = { - state_id: "state_id", - priority: "priority", - cycle_id: "cycle_id", - created_by: "created_by", - // Array Props - issue_module__module_id: "module_ids", - labels__id: "label_ids", - assignees__id: "assignee_ids", - target_date: "target_date", -}; - -export const PRIORITY_MAP = { - low: 1, - medium: 2, - high: 3, - urgent: 4, - none: 0, -}; diff --git a/apps/web/core/local-db/utils/data.utils.ts b/apps/web/core/local-db/utils/data.utils.ts deleted file mode 100644 index 532bb630c2..0000000000 --- a/apps/web/core/local-db/utils/data.utils.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { runQuery } from "./query-executor"; - -export const getProjectIds = async () => { - const q = `select project_id from states where project_id is not null group by project_id`; - return await runQuery(q); -}; - -export const getSubIssues = async (issueId: string) => { - const q = `select * from issues where parent_id = '${issueId}'`; - return await runQuery(q); -}; - -export const getSubIssueDistribution = async (issueId: string) => { - const q = `select s.'group', group_concat(i.id) as issues from issues i left join states s on s.id = i.state_id where i.parent_id = '${issueId}' group by s.'group'`; - - const result = await runQuery(q); - if (!result.length) { - return {}; - } - return result.reduce((acc: Record, item: { group: string; issues: string }) => { - acc[item.group] = item.issues.split(","); - return acc; - }, {}); -}; - -export const getSubIssuesWithDistribution = async (issueId: string) => { - const promises = [getSubIssues(issueId), getSubIssueDistribution(issueId)]; - const [sub_issues, state_distribution] = await Promise.all(promises); - return { sub_issues, state_distribution }; -}; diff --git a/apps/web/core/local-db/utils/indexes.ts b/apps/web/core/local-db/utils/indexes.ts deleted file mode 100644 index 0b2e987ed3..0000000000 --- a/apps/web/core/local-db/utils/indexes.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { persistence } from "../storage.sqlite"; -import { log } from "./utils"; - -export const createIssueIndexes = async () => { - const columns = [ - "state_id", - "sort_order", - // "priority", - "priority_proxy", - "project_id", - "created_by", - "cycle_id", - "sequence_id", - ]; - - const promises: Promise[] = []; - - promises.push(persistence.db.exec({ sql: `CREATE UNIQUE INDEX issues_issue_id_idx ON issues (id)` })); - - columns.forEach((column) => { - promises.push( - persistence.db.exec({ sql: `CREATE INDEX issues_issue_${column}_idx ON issues (project_id, ${column})` }) - ); - }); - await Promise.all(promises); -}; - -export const createIssueMetaIndexes = async () => { - // Drop indexes - await persistence.db.exec({ sql: `CREATE INDEX issue_meta_all_idx ON issue_meta (issue_id,key,value)` }); -}; - -export const createWorkSpaceIndexes = async () => { - const promises: Promise[] = []; - // Labels - promises.push(persistence.db.exec({ sql: `CREATE INDEX labels_name_idx ON labels (id,name,project_id)` })); - // Modules - promises.push(persistence.db.exec({ sql: `CREATE INDEX modules_name_idx ON modules (id,name,project_id)` })); - // States - promises.push(persistence.db.exec({ sql: `CREATE INDEX states_name_idx ON states (id,name,project_id)` })); - // Cycles - promises.push(persistence.db.exec({ sql: `CREATE INDEX cycles_name_idx ON cycles (id,name,project_id)` })); - - // Members - promises.push(persistence.db.exec({ sql: `CREATE INDEX members_name_idx ON members (id,first_name)` })); - - // Estimate Points @todo - promises.push(persistence.db.exec({ sql: `CREATE INDEX estimate_points_name_idx ON estimate_points (id,value)` })); - // Options - promises.push(persistence.db.exec({ sql: `CREATE INDEX options_key_idx ON options (key)` })); - - await Promise.all(promises); -}; - -const createIndexes = async () => { - log("### Creating indexes"); - const start = performance.now(); - const promises = [createIssueIndexes(), createIssueMetaIndexes(), createWorkSpaceIndexes()]; - try { - await Promise.all(promises); - } catch (e) { - console.log((e as Error).message); - } - log("### Indexes created in", `${performance.now() - start}ms`); -}; - -export default createIndexes; diff --git a/apps/web/core/local-db/utils/load-issues.ts b/apps/web/core/local-db/utils/load-issues.ts deleted file mode 100644 index a0c20fc0cc..0000000000 --- a/apps/web/core/local-db/utils/load-issues.ts +++ /dev/null @@ -1,133 +0,0 @@ -import type { TIssue } from "@plane/types"; -import { rootStore } from "@/lib/store-context"; -import { IssueService } from "@/services/issue"; -import { persistence } from "../storage.sqlite"; -import { ARRAY_FIELDS, PRIORITY_MAP } from "./constants"; -import { issueSchema } from "./schemas"; -import { log } from "./utils"; - -export const PROJECT_OFFLINE_STATUS: Record = {}; - -export const addIssue = async (issue: any) => { - if (document.hidden || !rootStore.user.localDBEnabled || !persistence.db) return; - await persistence.db.exec("BEGIN;"); - await stageIssueInserts(issue); - await persistence.db.exec("COMMIT;"); -}; - -export const addIssuesBulk = async (issues: any, batchSize = 50) => { - if (!rootStore.user.localDBEnabled || !persistence.db) return; - if (!issues.length) return; - const insertStart = performance.now(); - await persistence.db.exec("BEGIN;"); - - for (let i = 0; i < issues.length; i += batchSize) { - const batch = issues.slice(i, i + batchSize); - - const promises = []; - for (let j = 0; j < batch.length; j++) { - const issue = batch[j]; - if (!issue.type_id) { - issue.type_id = ""; - } - promises.push(stageIssueInserts(issue)); - } - await Promise.all(promises); - } - await persistence.db.exec("COMMIT;"); - - const insertEnd = performance.now(); - log("Inserted issues in ", `${insertEnd - insertStart}ms`, batchSize, issues.length); -}; -export const deleteIssueFromLocal = async (issue_id: any) => { - if (!rootStore.user.localDBEnabled || !persistence.db) return; - - const deleteQuery = `DELETE from issues where id='${issue_id}'`; - const deleteMetaQuery = `delete from issue_meta where issue_id='${issue_id}'`; - - await persistence.db.exec("BEGIN;"); - - await persistence.db.exec(deleteQuery); - await persistence.db.exec(deleteMetaQuery); - await persistence.db.exec("COMMIT;"); -}; -// @todo: Update deletes the issue description from local. Implement a separate update. -export const updateIssue = async (issue: TIssue & { is_local_update: number }) => { - if (document.hidden || !rootStore.user.localDBEnabled || !persistence.db) return; - - const issue_id = issue.id; - // delete the issue and its meta data - await deleteIssueFromLocal(issue_id); - await addIssue(issue); -}; - -export const syncDeletesToLocal = async (workspaceId: string, projectId: string, queries: any) => { - if (!rootStore.user.localDBEnabled || !persistence.db) return; - - const issueService = new IssueService(); - const response = await issueService.getDeletedIssues(workspaceId, projectId, queries); - if (Array.isArray(response)) { - response.map(async (issue) => deleteIssueFromLocal(issue)); - } -}; - -const stageIssueInserts = async (issue: any) => { - const issue_id = issue.id; - issue.priority_proxy = PRIORITY_MAP[issue.priority as keyof typeof PRIORITY_MAP]; - - const keys = Object.keys(issueSchema); - const sanitizedIssue = keys.reduce((acc: any, key) => { - if (issue[key] || issue[key] === 0) { - acc[key] = issue[key]; - } - return acc; - }, {}); - - const columns = "'" + Object.keys(sanitizedIssue).join("','") + "'"; - - const values = Object.values(sanitizedIssue) - .map((value) => { - if (value === null) { - return ""; - } - if (typeof value === "object") { - return `'${JSON.stringify(value).replace(/'/g, "''")}'`; - } - if (typeof value === "string") { - return `'${value.replace(/'/g, "''")}'`; - } - return value; - }) - .join(", "); - - const query = `INSERT OR REPLACE INTO issues (${columns}) VALUES (${values});`; - await persistence.db.exec(query); - - await persistence.db.exec({ - sql: `DELETE from issue_meta where issue_id='${issue_id}'`, - }); - - const metaPromises: Promise[] = []; - - ARRAY_FIELDS.forEach((field) => { - const values = issue[field]; - if (values && values.length) { - values.forEach((val: any) => { - const p = persistence.db.exec({ - sql: `INSERT OR REPLACE into issue_meta(issue_id,key,value) values (?,?,?) `, - bind: [issue_id, field, val], - }); - metaPromises.push(p); - }); - } else { - // Added for empty fields? - const p = persistence.db.exec({ - sql: `INSERT OR REPLACE into issue_meta(issue_id,key,value) values (?,?,?) `, - bind: [issue_id, field, ""], - }); - metaPromises.push(p); - } - }); - - await Promise.all(metaPromises); -}; diff --git a/apps/web/core/local-db/utils/load-workspace.ts b/apps/web/core/local-db/utils/load-workspace.ts deleted file mode 100644 index f388ea3b3e..0000000000 --- a/apps/web/core/local-db/utils/load-workspace.ts +++ /dev/null @@ -1,303 +0,0 @@ -import { difference } from "lodash-es"; -import type { IEstimate, IEstimatePoint, IWorkspaceMember, TIssue } from "@plane/types"; -import { EstimateService } from "@/plane-web/services/project/estimate.service"; -import { CycleService } from "@/services/cycle.service"; -import { IssueLabelService } from "@/services/issue/issue_label.service"; -import { ModuleService } from "@/services/module.service"; -import { ProjectStateService } from "@/services/project"; -import { WorkspaceService } from "@/services/workspace.service"; -import { persistence } from "../storage.sqlite"; -import { updateIssue } from "./load-issues"; -import type { Schema } from "./schemas"; -import { cycleSchema, estimatePointSchema, labelSchema, memberSchema, moduleSchema, stateSchema } from "./schemas"; -import { log } from "./utils"; - -const stageInserts = async (table: string, schema: Schema, data: any) => { - const keys = Object.keys(schema); - // Pick only the keys that are in the schema - const filteredData = keys.reduce((acc: any, key) => { - if (data[key] || data[key] === 0) { - acc[key] = data[key]; - } - return acc; - }, {}); - const columns = "'" + Object.keys(filteredData).join("','") + "'"; - // Add quotes to column names - - const values = Object.values(filteredData) - .map((value) => { - if (value === null) { - return ""; - } - if (typeof value === "object") { - return `'${JSON.stringify(value).replace(/'/g, "''")}'`; - } - if (typeof value === "string") { - return `'${value.replace(/'/g, "''")}'`; - } - return value; - }) - .join(", "); - const query = `INSERT OR REPLACE INTO ${table} (${columns}) VALUES (${values});`; - await persistence.db.exec(query); -}; - -const batchInserts = async (data: any[], table: string, schema: Schema, batchSize = 500) => { - for (let i = 0; i < data.length; i += batchSize) { - const batch = data.slice(i, i + batchSize); - for (let j = 0; j < batch.length; j++) { - const item = batch[j]; - await stageInserts(table, schema, item); - } - } -}; - -export const getLabels = async (workspaceSlug: string) => { - const issueLabelService = new IssueLabelService(); - const objects = await issueLabelService.getWorkspaceIssueLabels(workspaceSlug); - - return objects; -}; - -export const getModules = async (workspaceSlug: string) => { - const moduleService = new ModuleService(); - const objects = await moduleService.getWorkspaceModules(workspaceSlug); - return objects; -}; - -export const getCycles = async (workspaceSlug: string) => { - const cycleService = new CycleService(); - - const objects = await cycleService.getWorkspaceCycles(workspaceSlug); - return objects; -}; - -export const getStates = async (workspaceSlug: string) => { - const stateService = new ProjectStateService(); - const objects = await stateService.getWorkspaceStates(workspaceSlug); - return objects; -}; - -export const getEstimatePoints = async (workspaceSlug: string) => { - const estimateService = new EstimateService(); - const estimates = await estimateService.fetchWorkspaceEstimates(workspaceSlug); - let objects: IEstimatePoint[] = []; - (estimates || []).forEach((estimate: IEstimate) => { - if (estimate?.points) { - objects = objects.concat(estimate.points); - } - }); - return objects; -}; - -export const getMembers = async (workspaceSlug: string) => { - const workspaceService = new WorkspaceService(); - const members = await workspaceService.fetchWorkspaceMembers(workspaceSlug); - const objects = members.map((member: IWorkspaceMember) => member.member); - return objects; -}; - -const syncLabels = async (currentLabels: any) => { - const currentIdList = currentLabels.map((label: any) => label.id); - const existingLabels = await persistence.db.exec("SELECT id FROM labels;"); - - const existingIdList = existingLabels ? existingLabels.map((label: any) => label.id) : []; - - const deletedIds = difference(existingIdList, currentIdList); - - await syncIssuesWithDeletedLabels(deletedIds as string[]); -}; - -export const syncIssuesWithDeletedLabels = async (deletedLabelIds: string[]) => { - if (!deletedLabelIds.length) { - return; - } - - // Ideally we should use recursion to fetch all the issues, but 10000 issues is more than enough for now. - const issues = await persistence.getIssues("", "", { labels: deletedLabelIds.join(","), cursor: "10000:0:0" }, {}); - if (issues?.results && Array.isArray(issues.results)) { - const promises = issues.results.map(async (issue: TIssue) => { - const updatedIssue = { - ...issue, - label_ids: issue.label_ids.filter((id: string) => !deletedLabelIds.includes(id)), - is_local_update: 1, - }; - // We should await each update because it uses a transaction. But transaction are handled in the query executor. - updateIssue(updatedIssue); - }); - await Promise.all(promises); - } -}; - -const syncModules = async (currentModules: any) => { - const currentIdList = currentModules.map((module: any) => module.id); - const existingModules = await persistence.db.exec("SELECT id FROM modules;"); - const existingIdList = existingModules ? existingModules.map((module: any) => module.id) : []; - const deletedIds = difference(existingIdList, currentIdList); - await syncIssuesWithDeletedModules(deletedIds as string[]); -}; - -export const syncIssuesWithDeletedModules = async (deletedModuleIds: string[]) => { - if (!deletedModuleIds.length) { - return; - } - - const issues = await persistence.getIssues("", "", { module: deletedModuleIds.join(","), cursor: "10000:0:0" }, {}); - if (issues?.results && Array.isArray(issues.results)) { - const promises = issues.results.map(async (issue: TIssue) => { - const updatedIssue = { - ...issue, - module_ids: issue.module_ids?.filter((id: string) => !deletedModuleIds.includes(id)) || [], - is_local_update: 1, - }; - updateIssue(updatedIssue); - }); - await Promise.all(promises); - } -}; - -const syncCycles = async (currentCycles: any) => { - const currentIdList = currentCycles.map((cycle: any) => cycle.id); - const existingCycles = await persistence.db.exec("SELECT id FROM cycles;"); - const existingIdList = existingCycles ? existingCycles.map((cycle: any) => cycle.id) : []; - const deletedIds = difference(existingIdList, currentIdList); - await syncIssuesWithDeletedCycles(deletedIds as string[]); -}; - -export const syncIssuesWithDeletedCycles = async (deletedCycleIds: string[]) => { - if (!deletedCycleIds.length) { - return; - } - - const issues = await persistence.getIssues("", "", { cycle: deletedCycleIds.join(","), cursor: "10000:0:0" }, {}); - if (issues?.results && Array.isArray(issues.results)) { - const promises = issues.results.map(async (issue: TIssue) => { - const updatedIssue = { - ...issue, - cycle_id: null, - is_local_update: 1, - }; - updateIssue(updatedIssue); - }); - await Promise.all(promises); - } -}; - -const syncStates = async (currentStates: any) => { - const currentIdList = currentStates.map((state: any) => state.id); - const existingStates = await persistence.db.exec("SELECT id FROM states;"); - const existingIdList = existingStates ? existingStates.map((state: any) => state.id) : []; - const deletedIds = difference(existingIdList, currentIdList); - await syncIssuesWithDeletedStates(deletedIds as string[]); -}; - -export const syncIssuesWithDeletedStates = async (deletedStateIds: string[]) => { - if (!deletedStateIds.length) { - return; - } - - const issues = await persistence.getIssues("", "", { state: deletedStateIds.join(","), cursor: "10000:0:0" }, {}); - if (issues?.results && Array.isArray(issues.results)) { - const promises = issues.results.map(async (issue: TIssue) => { - const updatedIssue = { - ...issue, - state_id: null, - is_local_update: 1, - }; - updateIssue(updatedIssue); - }); - await Promise.all(promises); - } -}; - -const syncMembers = async (currentMembers: any) => { - const currentIdList = currentMembers.map((member: any) => member.id); - const existingMembers = await persistence.db.exec("SELECT id FROM members;"); - const existingIdList = existingMembers ? existingMembers.map((member: any) => member.id) : []; - const deletedIds = difference(existingIdList, currentIdList); - await syncIssuesWithDeletedMembers(deletedIds as string[]); -}; - -export const syncIssuesWithDeletedMembers = async (deletedMemberIds: string[]) => { - if (!deletedMemberIds.length) { - return; - } - - const issues = await persistence.getIssues( - "", - "", - { assignees: deletedMemberIds.join(","), cursor: "10000:0:0" }, - {} - ); - if (issues?.results && Array.isArray(issues.results)) { - const promises = issues.results.map(async (issue: TIssue) => { - const updatedIssue = { - ...issue, - assignee_ids: issue.assignee_ids.filter((id: string) => !deletedMemberIds.includes(id)), - is_local_update: 1, - }; - updateIssue(updatedIssue); - }); - await Promise.all(promises); - } -}; - -export const loadWorkSpaceData = async (workspaceSlug: string) => { - if (!persistence.db || !persistence.db.exec) { - return; - } - log("Loading workspace data"); - const promises = []; - promises.push(getLabels(workspaceSlug)); - promises.push(getModules(workspaceSlug)); - promises.push(getCycles(workspaceSlug)); - promises.push(getStates(workspaceSlug)); - promises.push(getEstimatePoints(workspaceSlug)); - promises.push(getMembers(workspaceSlug)); - const [labels, modules, cycles, states, estimates, members] = await Promise.all(promises); - - // @todo: we don't need this manual sync here, when backend adds these changes to issue activity and updates the updated_at of the issue. - await syncLabels(labels); - await syncModules(modules); - await syncCycles(cycles); - await syncStates(states); - // TODO: Not handling sync estimates yet, as we don't know the new estimate point assigned. - // Backend should update the updated_at of the issue when estimate point is updated, or we should have realtime sync on the issues table. - // await syncEstimates(estimates); - await syncMembers(members); - - const start = performance.now(); - - await persistence.db.exec("BEGIN;"); - await persistence.db.exec("DELETE FROM labels WHERE 1=1;"); - await batchInserts(labels, "labels", labelSchema); - await persistence.db.exec("COMMIT;"); - - await persistence.db.exec("BEGIN;"); - await persistence.db.exec("DELETE FROM modules WHERE 1=1;"); - await batchInserts(modules, "modules", moduleSchema); - await persistence.db.exec("COMMIT;"); - - await persistence.db.exec("BEGIN;"); - await persistence.db.exec("DELETE FROM cycles WHERE 1=1;"); - await batchInserts(cycles, "cycles", cycleSchema); - await persistence.db.exec("COMMIT;"); - - await persistence.db.exec("BEGIN;"); - await persistence.db.exec("DELETE FROM states WHERE 1=1;"); - await batchInserts(states, "states", stateSchema); - await persistence.db.exec("COMMIT;"); - - await persistence.db.exec("BEGIN;"); - await persistence.db.exec("DELETE FROM estimate_points WHERE 1=1;"); - await batchInserts(estimates, "estimate_points", estimatePointSchema); - await persistence.db.exec("COMMIT;"); - - await persistence.db.exec("BEGIN;"); - await persistence.db.exec("DELETE FROM members WHERE 1=1;"); - await batchInserts(members, "members", memberSchema); - await persistence.db.exec("COMMIT;"); - - const end = performance.now(); - log("Time taken to load workspace data", end - start); -}; diff --git a/apps/web/core/local-db/utils/query-constructor.ts b/apps/web/core/local-db/utils/query-constructor.ts deleted file mode 100644 index f2316bce55..0000000000 --- a/apps/web/core/local-db/utils/query-constructor.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { - getFilteredRowsForGrouping, - getIssueFieldsFragment, - getMetaKeys, - getOrderByFragment, - singleFilterConstructor, - translateQueryParams, -} from "./query.utils"; -import { log } from "./utils"; -export const SPECIAL_ORDER_BY = { - labels__name: "labels", - "-labels__name": "labels", - assignees__first_name: "members", - "-assignees__first_name": "members", - issue_module__module__name: "modules", - "-issue_module__module__name": "modules", - issue_cycle__cycle__name: "cycles", - "-issue_cycle__cycle__name": "cycles", - state__name: "states", - "-state__name": "states", - estimate_point__key: "estimate_point", - "-estimate_point__key": "estimate_point", -}; -export const issueFilterQueryConstructor = (workspaceSlug: string, projectId: string, queries: any) => { - const { - cursor, - per_page, - group_by, - sub_group_by, - order_by = "-created_at", - ...otherProps - } = translateQueryParams(queries); - - const [pageSize, page, offset] = cursor.split(":"); - - let sql = ""; - - const fieldsFragment = getIssueFieldsFragment(); - - if (sub_group_by) { - const orderByString = getOrderByFragment(order_by); - sql = getFilteredRowsForGrouping(projectId, queries); - sql += `, ranked_issues AS ( SELECT fi.*, - ROW_NUMBER() OVER (PARTITION BY group_id, sub_group_id ${orderByString}) as rank, - COUNT(*) OVER (PARTITION by group_id, sub_group_id) as total_issues from fi) - SELECT ri.*, ${fieldsFragment} - FROM ranked_issues ri - JOIN issues i ON ri.id = i.id - WHERE rank <= ${per_page} - - `; - - return sql; - } - if (group_by) { - const orderByString = getOrderByFragment(order_by); - sql = getFilteredRowsForGrouping(projectId, queries); - sql += `, ranked_issues AS ( SELECT fi.*, - ROW_NUMBER() OVER (PARTITION BY group_id ${orderByString}) as rank, - COUNT(*) OVER (PARTITION by group_id) as total_issues FROM fi) - SELECT ri.*, ${fieldsFragment} - FROM ranked_issues ri - JOIN issues i ON ri.id = i.id - WHERE rank <= ${per_page} - `; - - return sql; - } - - if (order_by && Object.keys(SPECIAL_ORDER_BY).includes(order_by)) { - const name = order_by.replace("-", ""); - const orderByString = getOrderByFragment(order_by, "i."); - - sql = `WITH sorted_issues AS (`; - sql += getFilteredRowsForGrouping(projectId, queries); - sql += `SELECT fi.* , `; - if (order_by.includes("assignee")) { - sql += ` s.first_name as ${name} `; - } else if (order_by.includes("estimate")) { - sql += ` s.key as ${name} `; - } else { - sql += ` s.name as ${name} `; - } - sql += `FROM fi `; - if (order_by && Object.keys(SPECIAL_ORDER_BY).includes(order_by)) { - if (order_by.includes("cycle")) { - sql += ` - LEFT JOIN cycles s on fi.cycle_id = s.id`; - } - if (order_by.includes("estimate_point__key")) { - sql += ` - LEFT JOIN estimate_points s on fi.estimate_point = s.id`; - } - if (order_by.includes("state")) { - sql += ` - LEFT JOIN states s on fi.state_id = s.id`; - } - if (order_by.includes("label")) { - sql += ` - LEFT JOIN issue_meta sm ON fi.id = sm.issue_id AND sm.key = 'label_ids' - LEFT JOIN labels s ON s.id = sm.value`; - } - if (order_by.includes("module")) { - sql += ` - LEFT JOIN issue_meta sm ON fi.id = sm.issue_id AND sm.key = 'module_ids' - LEFT JOIN modules s ON s.id = sm.value`; - } - - if (order_by.includes("assignee")) { - sql += ` - LEFT JOIN issue_meta sm ON fi.id = sm.issue_id AND sm.key = 'assignee_ids' - LEFT JOIN members s ON s.id = sm.value`; - } - - sql += ` ORDER BY ${name} ASC NULLS LAST`; - } - sql += `)`; - - sql += `SELECT ${fieldsFragment}, group_concat(si.${name}) as ${name} from sorted_issues si JOIN issues i ON si.id = i.id - `; - sql += ` group by i.id ${orderByString} LIMIT ${pageSize} OFFSET ${offset * 1 + page * pageSize};`; - - return sql; - } - - const filterJoinFields = getMetaKeys(queries); - const orderByString = getOrderByFragment(order_by); - - sql = `SELECT ${fieldsFragment}`; - if (otherProps.state_group) { - sql += `, states.'group' as state_group`; - } - sql += ` from issues i - `; - - if (otherProps.state_group) { - sql += `LEFT JOIN states ON i.state_id = states.id `; - } - filterJoinFields.forEach((field: string) => { - const value = otherProps[field] || ""; - sql += ` INNER JOIN issue_meta ${field} ON i.id = ${field}.issue_id AND ${field}.key = '${field}' AND ${field}.value IN ('${value.split(",").join("','")}') - `; - }); - - sql += ` WHERE 1=1 `; - if (projectId) { - sql += ` AND i.project_id = '${projectId}' `; - } - sql += ` ${singleFilterConstructor(otherProps)} group by i.id `; - sql += orderByString; - - // Add offset and paging to query - sql += ` LIMIT ${pageSize} OFFSET ${offset * 1 + page * pageSize};`; - - return sql; -}; - -export const issueFilterCountQueryConstructor = (workspaceSlug: string, projectId: string, queries: any) => { - //@todo Very crude way to extract count from the actual query. Needs to be refactored - // Remove group by from the query to fallback to non group query - const { group_by, sub_group_by, order_by, ...otherProps } = queries; - let sql = issueFilterQueryConstructor(workspaceSlug, projectId, otherProps); - const fieldsFragment = getIssueFieldsFragment(); - - sql = sql.replace(`SELECT ${fieldsFragment}`, "SELECT COUNT(DISTINCT i.id) as total_count"); - // Remove everything after group by i.id - sql = `${sql.split("group by i.id")[0]};`; - return sql; -}; diff --git a/apps/web/core/local-db/utils/query-executor.ts b/apps/web/core/local-db/utils/query-executor.ts deleted file mode 100644 index a6844dff43..0000000000 --- a/apps/web/core/local-db/utils/query-executor.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { persistence } from "../storage.sqlite"; - -export const runQuery = async (sql: string) => { - const data = await persistence.db?.exec({ - sql, - rowMode: "object", - returnValue: "resultRows", - }); - - return data; -}; diff --git a/apps/web/core/local-db/utils/query-sanitizer.ts.ts b/apps/web/core/local-db/utils/query-sanitizer.ts.ts deleted file mode 100644 index 3488217dab..0000000000 --- a/apps/web/core/local-db/utils/query-sanitizer.ts.ts +++ /dev/null @@ -1,38 +0,0 @@ -// plane constants -import { EUserPermissions } from "@plane/constants"; -import type { TIssueParams } from "@plane/types"; -// root store -import { rootStore } from "@/lib/store-context"; - -export const sanitizeWorkItemQueries = ( - workspaceSlug: string, - projectId: string, - queries: Partial> | undefined -): Partial> | undefined => { - // Get current project details and user id and role for the project - const currentProject = rootStore.projectRoot.project.getProjectById(projectId); - const currentUserId = rootStore.user.data?.id; - const currentUserRole = rootStore.user.permission.getProjectRoleByWorkspaceSlugAndProjectId(workspaceSlug, projectId); - - // Only apply this restriction for guests when guest_view_all_features is disabled - if ( - currentUserId && - currentUserRole === EUserPermissions.GUEST && - currentProject?.guest_view_all_features === false - ) { - // Sanitize the created_by filter if it doesn't exist or if it exists and includes the current user id - const existingCreatedByFilter = queries?.created_by; - const shouldApplyFilter = - !existingCreatedByFilter || - (typeof existingCreatedByFilter === "string" && existingCreatedByFilter.includes(currentUserId)); - - if (shouldApplyFilter) { - queries = { - ...queries, - created_by: currentUserId, - }; - } - } - - return queries; -}; diff --git a/apps/web/core/local-db/utils/query.utils.ts b/apps/web/core/local-db/utils/query.utils.ts deleted file mode 100644 index 583b623c88..0000000000 --- a/apps/web/core/local-db/utils/query.utils.ts +++ /dev/null @@ -1,357 +0,0 @@ -import { ARRAY_FIELDS, GROUP_BY_MAP, PRIORITY_MAP } from "./constants"; -import { SPECIAL_ORDER_BY } from "./query-constructor"; -import { issueSchema } from "./schemas"; -import { wrapDateTime } from "./utils"; - -export const translateQueryParams = (queries: any) => { - const { - group_by, - layout, - sub_group_by, - labels, - assignees, - state, - cycle, - module, - priority, - type, - issue_type, - ...otherProps - } = queries; - - const order_by = queries.order_by; - if (state) otherProps.state_id = state; - if (cycle) otherProps.cycle_id = cycle; - if (module) otherProps.module_ids = module; - if (labels) otherProps.label_ids = labels; - if (assignees) otherProps.assignee_ids = assignees; - if (group_by) otherProps.group_by = GROUP_BY_MAP[group_by as keyof typeof GROUP_BY_MAP]; - if (sub_group_by) otherProps.sub_group_by = GROUP_BY_MAP[sub_group_by as keyof typeof GROUP_BY_MAP]; - if (priority) { - otherProps.priority_proxy = priority - .split(",") - .map((priority: string) => PRIORITY_MAP[priority as keyof typeof PRIORITY_MAP]) - .join(","); - } - if (type) { - otherProps.state_group = type === "backlog" ? "backlog" : "unstarted,started"; - } - if (issue_type) { - otherProps.type_id = issue_type; - } - - if (order_by?.includes("priority")) { - otherProps.order_by = order_by.replace("priority", "priority_proxy"); - } - - // Fix invalid orderby when switching from spreadsheet layout - if (layout !== "spreadsheet" && Object.keys(SPECIAL_ORDER_BY).includes(order_by)) { - otherProps.order_by = "sort_order"; - } - // For each property value, replace None with empty string - Object.keys(otherProps).forEach((key) => { - if (otherProps[key] === "None") { - otherProps[key] = ""; - } - }); - - return otherProps; -}; - -export const getOrderByFragment = (order_by: string, table = "") => { - let orderByString = ""; - if (!order_by) return orderByString; - - if (order_by.startsWith("-")) { - orderByString += ` ORDER BY ${wrapDateTime(order_by.slice(1))} DESC NULLS LAST, ${table}sequence_id DESC`; - } else { - orderByString += ` ORDER BY ${wrapDateTime(order_by)} ASC NULLS LAST, ${table}sequence_id DESC`; - } - return orderByString; -}; - -export const isMetaJoinRequired = (groupBy: string, subGroupBy: string) => - ARRAY_FIELDS.includes(groupBy) || ARRAY_FIELDS.includes(subGroupBy); - -export const getMetaKeysFragment = (queries: any) => { - const { group_by, sub_group_by, ...otherProps } = translateQueryParams(queries); - - const fields: Set = new Set(); - if (ARRAY_FIELDS.includes(group_by)) { - fields.add(group_by); - } - - if (ARRAY_FIELDS.includes(sub_group_by)) { - fields.add(sub_group_by); - } - - const keys = Object.keys(otherProps); - - keys.forEach((field: string) => { - if (ARRAY_FIELDS.includes(field)) { - fields.add(field); - } - }); - - const sql = ` ('${Array.from(fields).join("','")}')`; - - return sql; -}; - -export const getMetaKeys = (queries: any): string[] => { - const { group_by, sub_group_by, ...otherProps } = translateQueryParams(queries); - - const fields: Set = new Set(); - if (ARRAY_FIELDS.includes(group_by)) { - fields.add(group_by); - } - - if (ARRAY_FIELDS.includes(sub_group_by)) { - fields.add(sub_group_by); - } - - const keys = Object.keys(otherProps); - - keys.forEach((field: string) => { - if (ARRAY_FIELDS.includes(field)) { - fields.add(field); - } - }); - - return Array.from(fields); -}; - -const areJoinsRequired = (queries: any) => { - const { group_by, sub_group_by, ...otherProps } = translateQueryParams(queries); - - if (ARRAY_FIELDS.includes(group_by) || ARRAY_FIELDS.includes(sub_group_by)) { - return true; - } - if (Object.keys(otherProps).some((field) => ARRAY_FIELDS.includes(field))) { - return true; - } - return false; -}; - -// Apply filters to the query -export const getFilteredRowsForGrouping = (projectId: string, queries: any) => { - const { group_by, sub_group_by, ...otherProps } = translateQueryParams(queries); - - const filterJoinFields = getMetaKeys(otherProps); - - const temp = getSingleFilterFields(queries); - const issueTableFilterFields = temp.length ? "," + temp.join(",") : ""; - - const joinsRequired = areJoinsRequired(queries); - - let sql = ""; - if (!joinsRequired) { - sql = `WITH fi as (SELECT i.id,i.created_at, i.sequence_id ${issueTableFilterFields}`; - if (group_by) { - if (group_by === "target_date") { - sql += `, date(i.${group_by}) as group_id`; - } else { - sql += `, i.${group_by} as group_id`; - } - } - if (sub_group_by) { - sql += `, i.${sub_group_by} as sub_group_id`; - } - sql += ` FROM issues i `; - if (otherProps.state_group) { - sql += `LEFT JOIN states ON i.state_id = states.id `; - } - sql += `WHERE 1=1 `; - if (projectId) { - sql += ` AND i.project_id = '${projectId}' - `; - } - sql += `${singleFilterConstructor(otherProps)}) - `; - return sql; - } - - sql = `WITH fi AS (`; - sql += `SELECT i.id,i.created_at,i.sequence_id ${issueTableFilterFields} `; - if (group_by) { - if (ARRAY_FIELDS.includes(group_by)) { - sql += `, ${group_by}.value as group_id - `; - } else if (group_by === "target_date") { - sql += `, date(i.${group_by}) as group_id - `; - } else { - sql += `, i.${group_by} as group_id - `; - } - } - if (sub_group_by) { - if (ARRAY_FIELDS.includes(sub_group_by)) { - sql += `, ${sub_group_by}.value as sub_group_id - `; - } else { - sql += `, i.${sub_group_by} as sub_group_id - `; - } - } - - sql += ` from issues i - `; - if (otherProps.state_group) { - sql += `LEFT JOIN states ON i.state_id = states.id `; - } - filterJoinFields.forEach((field: string) => { - sql += ` INNER JOIN issue_meta ${field} ON i.id = ${field}.issue_id AND ${field}.key = '${field}' AND ${field}.value IN ('${otherProps[field].split(",").join("','")}') - `; - }); - - // If group by field is not already joined, join it - if (ARRAY_FIELDS.includes(group_by) && !filterJoinFields.includes(group_by)) { - sql += ` LEFT JOIN issue_meta ${group_by} ON i.id = ${group_by}.issue_id AND ${group_by}.key = '${group_by}' - `; - } - if (ARRAY_FIELDS.includes(sub_group_by) && !filterJoinFields.includes(sub_group_by)) { - sql += ` LEFT JOIN issue_meta ${sub_group_by} ON i.id = ${sub_group_by}.issue_id AND ${sub_group_by}.key = '${sub_group_by}' - `; - } - - sql += ` WHERE 1=1 `; - if (projectId) { - sql += ` AND i.project_id = '${projectId}' - `; - } - sql += singleFilterConstructor(otherProps); - - sql += `) - `; - return sql; -}; - -export const singleFilterConstructor = (queries: any) => { - const { - order_by, - cursor, - per_page, - group_by, - sub_group_by, - state_group, - sub_issue, - target_date, - start_date, - ...filters - } = translateQueryParams(queries); - - let sql = ""; - if (!sub_issue) { - sql += ` AND parent_id IS NULL - `; - } - if (target_date) { - sql += createDateFilter("target_date", target_date); - } - if (start_date) { - sql += createDateFilter("start_date", start_date); - } - if (state_group) { - sql += ` AND state_group in ('${state_group.split(",").join("','")}') - `; - } - const keys = Object.keys(filters); - - keys.forEach((key) => { - const value = filters[key] ? filters[key].split(",") : ""; - if (!ARRAY_FIELDS.includes(key)) { - if (!value) { - sql += ` AND ${key} IS NULL`; - return; - } - sql += ` AND ${key} in ('${value.join("','")}') - `; - } - }); - // - - return sql; -}; - -const createDateFilter = (key: string, q: string) => { - let sql = " "; - // get todays date in YYYY-MM-DD format - const queries = q.split(","); - const customRange: string[] = []; - let isAnd = true; - queries.forEach((query: string) => { - const [date, type, from] = query.split(";"); - if (from) { - // Assuming type is always after - let after = ""; - const [_length, unit] = date.split("_"); - const length = parseInt(_length); - - if (unit === "weeks") { - // get date in yyyy-mm-dd format one week from now - after = new Date(new Date().setDate(new Date().getDate() + length * 7)).toISOString().split("T")[0]; - } - if (unit === "months") { - after = new Date(new Date().setDate(new Date().getDate() + length * 30)).toISOString().split("T")[0]; - } - sql += ` ${isAnd ? "AND" : "OR"} ${key} >= date('${after}')`; - isAnd = false; - // sql += ` AND ${key} ${type === "after" ? ">=" : "<="} date('${date}', '${today}')`; - } else { - customRange.push(query); - } - }); - - if (customRange.length === 2) { - const end = customRange.find((date) => date.includes("before"))?.split(";")[0]; - const start = customRange.find((date) => date.includes("after"))?.split(";")[0]; - if (end && start) { - sql += ` ${isAnd ? "AND" : "OR"} ${key} BETWEEN date('${start}') AND date('${end}')`; - } - } - if (customRange.length === 1) { - sql += ` AND ${key}=date('${customRange[0].split(";")[0]}')`; - } - - return sql; -}; -const getSingleFilterFields = (queries: any) => { - const { order_by, cursor, per_page, group_by, sub_group_by, sub_issue, state_group, ...otherProps } = - translateQueryParams(queries); - - const fields = new Set(); - - if (order_by && !order_by.includes("created_at") && !Object.keys(SPECIAL_ORDER_BY).includes(order_by)) - fields.add(order_by.replace("-", "")); - - const keys = Object.keys(otherProps); - - keys.forEach((field: string) => { - if (!ARRAY_FIELDS.includes(field)) { - fields.add(field); - } - }); - - if (order_by?.includes("state__name")) { - fields.add("state_id"); - } - if (order_by?.includes("cycle__name")) { - fields.add("cycle_id"); - } - if (state_group) { - fields.add("states.'group' as state_group"); - } - if (order_by?.includes("estimate_point__key")) { - fields.add("estimate_point"); - } - return Array.from(fields); -}; - -export const getIssueFieldsFragment = () => { - const { description_html, ...filtered } = issueSchema; - const keys = Object.keys(filtered); - const sql = ` ${keys.map((key) => `i.${key}`).join(`, - `)}`; - return sql; -}; diff --git a/apps/web/core/local-db/utils/schemas.ts b/apps/web/core/local-db/utils/schemas.ts deleted file mode 100644 index 068ab9234f..0000000000 --- a/apps/web/core/local-db/utils/schemas.ts +++ /dev/null @@ -1,136 +0,0 @@ -export type Schema = { - [key: string]: string; -}; - -export const issueSchema: Schema = { - id: "TEXT UNIQUE", - name: "TEXT", - state_id: "TEXT", - sort_order: "REAL", - completed_at: "TEXT", - estimate_point: "REAL", - priority: "TEXT", - priority_proxy: "INTEGER", - start_date: "TEXT", - target_date: "TEXT", - sequence_id: "INTEGER", - project_id: "TEXT", - parent_id: "TEXT", - created_at: "TEXT", - updated_at: "TEXT", - created_by: "TEXT", - updated_by: "TEXT", - is_draft: "INTEGER", - archived_at: "TEXT", - state__group: "TEXT", - sub_issues_count: "INTEGER", - cycle_id: "TEXT", - link_count: "INTEGER", - attachment_count: "INTEGER", - type_id: "TEXT", - label_ids: "TEXT", - assignee_ids: "TEXT", - module_ids: "TEXT", - description_html: "TEXT", - is_local_update: "INTEGER", -}; - -export const issueMetaSchema: Schema = { - issue_id: "TEXT", - key: "TEXT", - value: "TEXT", -}; -export const moduleSchema: Schema = { - id: "TEXT UNIQUE", - workspace_id: "TEXT", - project_id: "TEXT", - name: "TEXT", - description: "TEXT", - description_text: "TEXT", - description_html: "TEXT", - start_date: "TEXT", - target_date: "TEXT", - status: "TEXT", - lead_id: "TEXT", - member_ids: "TEXT", - view_props: "TEXT", - sort_order: "INTEGER", - external_source: "TEXT", - external_id: "TEXT", - logo_props: "TEXT", - total_issues: "INTEGER", - cancelled_issues: "INTEGER", - completed_issues: "INTEGER", - started_issues: "INTEGER", - unstarted_issues: "INTEGER", - backlog_issues: "INTEGER", - created_at: "TEXT", - updated_at: "TEXT", - archived_at: "TEXT", -}; - -export const labelSchema: Schema = { - id: "TEXT UNIQUE", - name: "TEXT", - color: "TEXT", - parent: "TEXT", - project_id: "TEXT", - workspace_id: "TEXT", - sort_order: "INTEGER", -}; - -export const cycleSchema: Schema = { - id: "TEXT UNIQUE", - workspace_id: "TEXT", - project_id: "TEXT", - name: "TEXT", - description: "TEXT", - start_date: "TEXT", - end_date: "TEXT", - owned_by_id: "TEXT", - view_props: "TEXT", - sort_order: "INTEGER", - external_source: "TEXT", - external_id: "TEXT", - progress_snapshot: "TEXT", - logo_props: "TEXT", - total_issues: "INTEGER", - cancelled_issues: "INTEGER", - completed_issues: "INTEGER", - started_issues: "INTEGER", - unstarted_issues: "INTEGER", - backlog_issues: "INTEGER", -}; - -export const stateSchema: Schema = { - id: "TEXT UNIQUE", - project_id: "TEXT", - workspace_id: "TEXT", - name: "TEXT", - color: "TEXT", - group: "TEXT", - default: "BOOLEAN", - description: "TEXT", - sequence: "INTEGER", -}; - -export const estimatePointSchema: Schema = { - id: "TEXT UNIQUE", - key: "TEXT", - value: "REAL", -}; - -export const memberSchema: Schema = { - id: "TEXT UNIQUE", - first_name: "TEXT", - last_name: "TEXT", - avatar: "TEXT", - is_bot: "BOOLEAN", - display_name: "TEXT", - email: "TEXT", -}; - -export const optionsSchema: Schema = { - key: "TEXT UNIQUE", - value: "TEXT", -}; diff --git a/apps/web/core/local-db/utils/tables.ts b/apps/web/core/local-db/utils/tables.ts deleted file mode 100644 index 6319f6e9c5..0000000000 --- a/apps/web/core/local-db/utils/tables.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { persistence } from "../storage.sqlite"; -import type { Schema } from "./schemas"; -import { - labelSchema, - moduleSchema, - issueMetaSchema, - issueSchema, - stateSchema, - cycleSchema, - estimatePointSchema, - memberSchema, - optionsSchema, -} from "./schemas"; -import { log } from "./utils"; - -const createTableSQLfromSchema = (tableName: string, schema: Schema) => { - let sql = `CREATE TABLE IF NOT EXISTS ${tableName} (`; - sql += Object.keys(schema) - .map((key) => `'${key}' ${schema[key]}`) - .join(", "); - sql += `);`; - log("#####", sql); - return sql; -}; - -export const createTables = async () => { - //@todo use promise.all or send all statements in one go - await persistence.db.exec("BEGIN;"); - - await persistence.db.exec(createTableSQLfromSchema("issues", issueSchema)); - await persistence.db.exec(createTableSQLfromSchema("issue_meta", issueMetaSchema)); - await persistence.db.exec(createTableSQLfromSchema("modules", moduleSchema)); - await persistence.db.exec(createTableSQLfromSchema("labels", labelSchema)); - await persistence.db.exec(createTableSQLfromSchema("states", stateSchema)); - await persistence.db.exec(createTableSQLfromSchema("cycles", cycleSchema)); - await persistence.db.exec(createTableSQLfromSchema("estimate_points", estimatePointSchema)); - await persistence.db.exec(createTableSQLfromSchema("members", memberSchema)); - await persistence.db.exec(createTableSQLfromSchema("options", optionsSchema)); - - await persistence.db.exec("COMMIT;"); -}; diff --git a/apps/web/core/local-db/utils/utils.ts b/apps/web/core/local-db/utils/utils.ts deleted file mode 100644 index 1cb44c6724..0000000000 --- a/apps/web/core/local-db/utils/utils.ts +++ /dev/null @@ -1,206 +0,0 @@ -import { pick } from "lodash-es"; -import type { TIssue } from "@plane/types"; -import { rootStore } from "@/lib/store-context"; -import { persistence } from "../storage.sqlite"; -import { updateIssue } from "./load-issues"; - -export const log = (...args: any) => { - if ((window as any).DEBUG) { - console.log(...args); - } -}; -export const logError = (e: any) => { - if (e?.result?.errorClass === "SQLite3Error") { - e = parseSQLite3Error(e); - } - console.error(e); -}; -export const logInfo = console.info; - -export const addIssueToPersistanceLayer = async (issue: TIssue) => { - try { - const issuePartial = pick({ ...JSON.parse(JSON.stringify(issue)) }, [ - "id", - "name", - "state_id", - "sort_order", - "completed_at", - "estimate_point", - "priority", - "start_date", - "target_date", - "sequence_id", - "project_id", - "parent_id", - "created_at", - "updated_at", - "created_by", - "updated_by", - "is_draft", - "archived_at", - "state__group", - "cycle_id", - "link_count", - "attachment_count", - "sub_issues_count", - "assignee_ids", - "label_ids", - "module_ids", - "type_id", - "description_html", - ]); - await updateIssue({ ...issuePartial, is_local_update: 1 }); - } catch (e) { - logError("Error while adding issue to db"); - } -}; - -export const updatePersistentLayer = async (issueIds: string | string[]) => { - if (typeof issueIds === "string") { - issueIds = [issueIds]; - } - issueIds.forEach(async (issueId) => { - const dbIssue = await persistence.getIssue(issueId); - const issue = rootStore.issue.issues.getIssueById(issueId); - const updatedIssue = dbIssue ? { ...dbIssue, ...issue } : issue; - - if (updatedIssue) { - addIssueToPersistanceLayer(updatedIssue); - } - }); -}; - -export const wrapDateTime = (field: string) => { - const DATE_TIME_FIELDS = ["created_at", "updated_at", "completed_at", "start_date", "target_date"]; - - if (DATE_TIME_FIELDS.includes(field)) { - return `datetime(${field})`; - } - return field; -}; - -export const getGroupedIssueResults = (issueResults: (TIssue & { group_id?: string; total_issues: number })[]): any => { - const groupedResults: { - [key: string]: { - results: TIssue[]; - total_results: number; - }; - } = {}; - - for (const issue of issueResults) { - const { group_id, total_issues } = issue; - const groupId = group_id ? group_id : "None"; - if (groupedResults?.[groupId] !== undefined && Array.isArray(groupedResults?.[groupId]?.results)) { - groupedResults?.[groupId]?.results.push(issue); - } else { - groupedResults[groupId] = { results: [issue], total_results: total_issues }; - } - } - - return groupedResults; -}; - -export const getSubGroupedIssueResults = ( - issueResults: (TIssue & { group_id?: string; total_issues: number; sub_group_id?: string })[] -): any => { - const subGroupedResults: { - [key: string]: { - results: { - [key: string]: { - results: TIssue[]; - total_results: number; - }; - }; - total_results: number; - }; - } = {}; - - for (const issue of issueResults) { - const { group_id, total_issues, sub_group_id } = issue; - const groupId = group_id ? group_id : "None"; - const subGroupId = sub_group_id ? sub_group_id : "None"; - - if (subGroupedResults?.[groupId] === undefined) { - subGroupedResults[groupId] = { results: {}, total_results: 0 }; - } - - if ( - subGroupedResults[groupId].results[subGroupId] !== undefined && - Array.isArray(subGroupedResults[groupId].results[subGroupId]?.results) - ) { - subGroupedResults[groupId].results[subGroupId]?.results.push(issue); - } else { - subGroupedResults[groupId].results[subGroupId] = { results: [issue], total_results: total_issues }; - } - } - - const groupByKeys = Object.keys(subGroupedResults); - - for (const groupByKey of groupByKeys) { - let totalIssues = 0; - const groupedResults = subGroupedResults[groupByKey]?.results ?? {}; - const subGroupByKeys = Object.keys(groupedResults); - - for (const subGroupByKey of subGroupByKeys) { - const subGroupedResultsCount = groupedResults[subGroupByKey].total_results ?? 0; - totalIssues += subGroupedResultsCount; - } - - subGroupedResults[groupByKey].total_results = totalIssues; - } - - return subGroupedResults; -}; - -export const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); - -const parseSQLite3Error = (error: any) => { - error.result = JSON.stringify(error.result); - return error; -}; - -export const isChrome = () => { - const userAgent = navigator.userAgent; - return userAgent.includes("Chrome") && !userAgent.includes("Edg") && !userAgent.includes("OPR"); -}; - -export const clearOPFS = async (force = false) => { - const storageManager = window.navigator.storage; - const root = await storageManager.getDirectory(); - - if (force && isChrome()) { - await (root as any).remove({ recursive: true }); - return; - } - // ts-ignore - for await (const entry of (root as any)?.values()) { - if (entry.kind === "directory" && entry.name.startsWith(".ahp-")) { - // A lock with the same name as the directory protects it from - // being deleted. - - if (force) { - // don't wait for the lock - try { - await root.removeEntry(entry.name, { recursive: true }); - } catch (e) { - console.log(e); - } - } else { - await navigator.locks.request(entry.name, { ifAvailable: true }, async (lock) => { - if (lock) { - log?.(`Deleting temporary directory ${entry.name}`); - try { - await root.removeEntry(entry.name, { recursive: true }); - } catch (e) { - console.log(e); - } - } else { - log?.(`Temporary directory ${entry.name} is in use`); - } - }); - } - } else { - root.removeEntry(entry.name); - } - } -}; diff --git a/apps/web/core/local-db/worker/db.ts b/apps/web/core/local-db/worker/db.ts deleted file mode 100644 index d8a7997c0a..0000000000 --- a/apps/web/core/local-db/worker/db.ts +++ /dev/null @@ -1,136 +0,0 @@ -import * as Comlink from "comlink"; -import { OPFSCoopSyncVFS as MyVFS } from "./wa-sqlite/src/OPFSCoopSyncVFS"; -import * as SQLite from "./wa-sqlite/src/sqlite-api"; -import SQLiteESMFactory from "./wa-sqlite/src/wa-sqlite.mjs"; - -type TQueryProps = { - sql: string; - rowMode: string; - returnValue: string; - bind: any[]; -}; -const mergeToObject = (columns: string[], row: any[]) => { - const obj: any = {}; - columns.forEach((column, index) => { - obj[column] = row[index]; - }); - return obj; -}; -interface SQLiteInstance { - db: unknown; - exec: (sql: string) => Promise; -} - -export class DBClass { - private instance: SQLiteInstance = {} as SQLiteInstance; - private sqlite3: any; - private tp: Promise[] = []; - private tpResolver: any = []; - async init(dbName: string) { - if (!dbName || typeof dbName !== "string") { - throw new Error("Invalid database name"); - } - - try { - const m = await SQLiteESMFactory(); - this.sqlite3 = SQLite.Factory(m); - const vfs = await MyVFS.create("plane", m); - this.sqlite3.vfs_register(vfs, true); - // Fallback in rare cases where the database is not initialized in time - const p = new Promise((resolve) => setTimeout(() => resolve(false), 2000)); - const dbPromise = this.sqlite3.open_v2( - `${dbName}.sqlite3`, - this.sqlite3.OPEN_READWRITE | this.sqlite3.OPEN_CREATE, - "plane" - ); - - const db = await Promise.any([dbPromise, p]); - - if (!db) { - throw new Error("Failed to initialize in time"); - } - - this.instance.db = db; - this.instance.exec = async (sql: string) => { - const rows: any[] = []; - await this.sqlite3.exec(db, sql, (row: any[], columns: string[]) => { - rows.push(mergeToObject(columns, row)); - }); - - return rows; - }; - return true; - } catch (error) { - throw new Error(`Failed to initialize database: ${(error as any)?.message}`); - } - } - - runQuery(sql: string) { - return this.instance?.exec?.(sql); - } - - async exec(props: string | TQueryProps) { - // @todo this will fail if the transaction is started any other way - // eg: BEGIN, OR BEGIN TRANSACTION - if (props === "BEGIN;") { - let promiseToAwait; - if (this.tp.length > 0) { - promiseToAwait = this.tp.shift(); - } - const p = new Promise((resolve, reject) => { - this.tpResolver.push({ resolve, reject }); - }); - this.tp.push(p); - - if (promiseToAwait) { - await promiseToAwait; - } - } - let sql: string, bind: any[]; - if (typeof props === "string") { - sql = props; - } else { - ({ sql, bind } = props); - if (bind) { - for await (const stmt of this.sqlite3.statements(this.instance.db, sql)) { - bind.forEach((b, i) => { - this.sqlite3.bind(stmt, i + 1, b); - }); - - const rows = []; - - do { - const columns = await this.sqlite3.column_names(stmt); - const row = await this.sqlite3.row(stmt); - rows.push(mergeToObject(columns, row)); - } while ((await this.sqlite3.step(stmt)) === SQLite.SQLITE_ROW); - - return rows; - } - } - } - - if (sql === "COMMIT;" && this.tp) { - await this.instance?.exec?.(sql); - if (this.tp.length > 0) { - const { resolve } = this.tpResolver.shift(); - resolve(); - } - return; - } - return await this.instance?.exec?.(sql); - } - async close() { - try { - if (!this.instance.db) { - return; - } - await this.sqlite3.close(this.instance.db); - // Clear instance to prevent usage after closing - this.instance = {} as SQLiteInstance; - } catch (error) { - throw new Error(`Failed to close database: ${(error as any)?.message}`); - } - } -} -Comlink.expose(DBClass); diff --git a/apps/web/core/local-db/worker/wa-sqlite/src/FacadeVFS.js b/apps/web/core/local-db/worker/wa-sqlite/src/FacadeVFS.js deleted file mode 100644 index c975fdc913..0000000000 --- a/apps/web/core/local-db/worker/wa-sqlite/src/FacadeVFS.js +++ /dev/null @@ -1,508 +0,0 @@ -// Copyright 2024 Roy T. Hashimoto. All Rights Reserved. -import * as VFS from './VFS.js'; - -const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor; - -// Convenience base class for a JavaScript VFS. -// The raw xOpen, xRead, etc. function signatures receive only C primitives -// which aren't easy to work with. This class provides corresponding calls -// like jOpen, jRead, etc., which receive JavaScript-friendlier arguments -// such as string, Uint8Array, and DataView. -export class FacadeVFS extends VFS.Base { - /** - * @param {string} name - * @param {object} module - */ - constructor(name, module) { - super(name, module); - } - - /** - * Override to indicate which methods are asynchronous. - * @param {string} methodName - * @returns {boolean} - */ - hasAsyncMethod(methodName) { - // The input argument is a string like "xOpen", so convert to "jOpen". - // Then check if the method exists and is async. - const jMethodName = `j${methodName.slice(1)}`; - return this[jMethodName] instanceof AsyncFunction; - } - - /** - * Return the filename for a file id for use by mixins. - * @param {number} pFile - * @returns {string} - */ - getFilename(pFile) { - throw new Error('unimplemented'); - } - - /** - * @param {string?} filename - * @param {number} pFile - * @param {number} flags - * @param {DataView} pOutFlags - * @returns {number|Promise} - */ - jOpen(filename, pFile, flags, pOutFlags) { - return VFS.SQLITE_CANTOPEN; - } - - /** - * @param {string} filename - * @param {number} syncDir - * @returns {number|Promise} - */ - jDelete(filename, syncDir) { - return VFS.SQLITE_OK; - } - - /** - * @param {string} filename - * @param {number} flags - * @param {DataView} pResOut - * @returns {number|Promise} - */ - jAccess(filename, flags, pResOut) { - return VFS.SQLITE_OK; - } - - /** - * @param {string} filename - * @param {Uint8Array} zOut - * @returns {number|Promise} - */ - jFullPathname(filename, zOut) { - // Copy the filename to the output buffer. - const { read, written } = new TextEncoder().encodeInto(filename, zOut); - if (read < filename.length) return VFS.SQLITE_IOERR; - if (written >= zOut.length) return VFS.SQLITE_IOERR; - zOut[written] = 0; - return VFS.SQLITE_OK; - } - - /** - * @param {Uint8Array} zBuf - * @returns {number|Promise} - */ - jGetLastError(zBuf) { - return VFS.SQLITE_OK; - } - - /** - * @param {number} pFile - * @returns {number|Promise} - */ - jClose(pFile) { - return VFS.SQLITE_OK; - } - - /** - * @param {number} pFile - * @param {Uint8Array} pData - * @param {number} iOffset - * @returns {number|Promise} - */ - jRead(pFile, pData, iOffset) { - pData.fill(0); - return VFS.SQLITE_IOERR_SHORT_READ; - } - - /** - * @param {number} pFile - * @param {Uint8Array} pData - * @param {number} iOffset - * @returns {number|Promise} - */ - jWrite(pFile, pData, iOffset) { - return VFS.SQLITE_IOERR_WRITE; - } - - /** - * @param {number} pFile - * @param {number} size - * @returns {number|Promise} - */ - jTruncate(pFile, size) { - return VFS.SQLITE_OK; - } - - /** - * @param {number} pFile - * @param {number} flags - * @returns {number|Promise} - */ - jSync(pFile, flags) { - return VFS.SQLITE_OK; - } - - /** - * @param {number} pFile - * @param {DataView} pSize - * @returns {number|Promise} - */ - jFileSize(pFile, pSize) { - return VFS.SQLITE_OK; - } - - /** - * @param {number} pFile - * @param {number} lockType - * @returns {number|Promise} - */ - jLock(pFile, lockType) { - return VFS.SQLITE_OK; - } - - /** - * @param {number} pFile - * @param {number} lockType - * @returns {number|Promise} - */ - jUnlock(pFile, lockType) { - return VFS.SQLITE_OK; - } - - /** - * @param {number} pFile - * @param {DataView} pResOut - * @returns {number|Promise} - */ - jCheckReservedLock(pFile, pResOut) { - pResOut.setInt32(0, 0, true); - return VFS.SQLITE_OK; - } - - /** - * @param {number} pFile - * @param {number} op - * @param {DataView} pArg - * @returns {number|Promise} - */ - jFileControl(pFile, op, pArg) { - return VFS.SQLITE_NOTFOUND; - } - - /** - * @param {number} pFile - * @returns {number|Promise} - */ - jSectorSize(pFile) { - return super.xSectorSize(pFile); - } - - /** - * @param {number} pFile - * @returns {number|Promise} - */ - jDeviceCharacteristics(pFile) { - return 0; - } - - /** - * @param {number} pVfs - * @param {number} zName - * @param {number} pFile - * @param {number} flags - * @param {number} pOutFlags - * @returns {number|Promise} - */ - xOpen(pVfs, zName, pFile, flags, pOutFlags) { - const filename = this.#decodeFilename(zName, flags); - const pOutFlagsView = this.#makeTypedDataView('Int32', pOutFlags); - this['log']?.('jOpen', filename, pFile, '0x' + flags.toString(16)); - return this.jOpen(filename, pFile, flags, pOutFlagsView); - } - - /** - * @param {number} pVfs - * @param {number} zName - * @param {number} syncDir - * @returns {number|Promise} - */ - xDelete(pVfs, zName, syncDir) { - const filename = this._module.UTF8ToString(zName); - this['log']?.('jDelete', filename, syncDir); - return this.jDelete(filename, syncDir); - } - - /** - * @param {number} pVfs - * @param {number} zName - * @param {number} flags - * @param {number} pResOut - * @returns {number|Promise} - */ - xAccess(pVfs, zName, flags, pResOut) { - const filename = this._module.UTF8ToString(zName); - const pResOutView = this.#makeTypedDataView('Int32', pResOut); - this['log']?.('jAccess', filename, flags); - return this.jAccess(filename, flags, pResOutView); - } - - /** - * @param {number} pVfs - * @param {number} zName - * @param {number} nOut - * @param {number} zOut - * @returns {number|Promise} - */ - xFullPathname(pVfs, zName, nOut, zOut) { - const filename = this._module.UTF8ToString(zName); - const zOutArray = this._module.HEAPU8.subarray(zOut, zOut + nOut); - this['log']?.('jFullPathname', filename, nOut); - return this.jFullPathname(filename, zOutArray); - } - - /** - * @param {number} pVfs - * @param {number} nBuf - * @param {number} zBuf - * @returns {number|Promise} - */ - xGetLastError(pVfs, nBuf, zBuf) { - const zBufArray = this._module.HEAPU8.subarray(zBuf, zBuf + nBuf); - this['log']?.('jGetLastError', nBuf); - return this.jGetLastError(zBufArray); - } - - /** - * @param {number} pFile - * @returns {number|Promise} - */ - xClose(pFile) { - this['log']?.('jClose', pFile); - return this.jClose(pFile); - } - - /** - * @param {number} pFile - * @param {number} pData - * @param {number} iAmt - * @param {number} iOffsetLo - * @param {number} iOffsetHi - * @returns {number|Promise} - */ - xRead(pFile, pData, iAmt, iOffsetLo, iOffsetHi) { - const pDataArray = this.#makeDataArray(pData, iAmt); - const iOffset = delegalize(iOffsetLo, iOffsetHi); - this['log']?.('jRead', pFile, iAmt, iOffset); - return this.jRead(pFile, pDataArray, iOffset); - } - - /** - * @param {number} pFile - * @param {number} pData - * @param {number} iAmt - * @param {number} iOffsetLo - * @param {number} iOffsetHi - * @returns {number|Promise} - */ - xWrite(pFile, pData, iAmt, iOffsetLo, iOffsetHi) { - const pDataArray = this.#makeDataArray(pData, iAmt); - const iOffset = delegalize(iOffsetLo, iOffsetHi); - this['log']?.('jWrite', pFile, pDataArray, iOffset); - return this.jWrite(pFile, pDataArray, iOffset); - } - - /** - * @param {number} pFile - * @param {number} sizeLo - * @param {number} sizeHi - * @returns {number|Promise} - */ - xTruncate(pFile, sizeLo, sizeHi) { - const size = delegalize(sizeLo, sizeHi); - this['log']?.('jTruncate', pFile, size); - return this.jTruncate(pFile, size); - } - - /** - * @param {number} pFile - * @param {number} flags - * @returns {number|Promise} - */ - xSync(pFile, flags) { - this['log']?.('jSync', pFile, flags); - return this.jSync(pFile, flags); - } - - /** - * - * @param {number} pFile - * @param {number} pSize - * @returns {number|Promise} - */ - xFileSize(pFile, pSize) { - const pSizeView = this.#makeTypedDataView('BigInt64', pSize); - this['log']?.('jFileSize', pFile); - return this.jFileSize(pFile, pSizeView); - } - - /** - * @param {number} pFile - * @param {number} lockType - * @returns {number|Promise} - */ - xLock(pFile, lockType) { - this['log']?.('jLock', pFile, lockType); - return this.jLock(pFile, lockType); - } - - /** - * @param {number} pFile - * @param {number} lockType - * @returns {number|Promise} - */ - xUnlock(pFile, lockType) { - this['log']?.('jUnlock', pFile, lockType); - return this.jUnlock(pFile, lockType); - } - - /** - * @param {number} pFile - * @param {number} pResOut - * @returns {number|Promise} - */ - xCheckReservedLock(pFile, pResOut) { - const pResOutView = this.#makeTypedDataView('Int32', pResOut); - this['log']?.('jCheckReservedLock', pFile); - return this.jCheckReservedLock(pFile, pResOutView); - } - - /** - * @param {number} pFile - * @param {number} op - * @param {number} pArg - * @returns {number|Promise} - */ - xFileControl(pFile, op, pArg) { - const pArgView = new DataView( - this._module.HEAPU8.buffer, - this._module.HEAPU8.byteOffset + pArg); - this['log']?.('jFileControl', pFile, op, pArgView); - return this.jFileControl(pFile, op, pArgView); - } - - /** - * @param {number} pFile - * @returns {number|Promise} - */ - xSectorSize(pFile) { - this['log']?.('jSectorSize', pFile); - return this.jSectorSize(pFile); - } - - /** - * @param {number} pFile - * @returns {number|Promise} - */ - xDeviceCharacteristics(pFile) { - this['log']?.('jDeviceCharacteristics', pFile); - return this.jDeviceCharacteristics(pFile); - } - - /** - * Wrapped DataView for pointer arguments. - * Pointers to a single value are passed using DataView. A Proxy - * wrapper prevents use of incorrect type or endianness. - * @param {'Int32'|'BigInt64'} type - * @param {number} byteOffset - * @returns {DataView} - */ - #makeTypedDataView(type, byteOffset) { - const byteLength = type === 'Int32' ? 4 : 8; - const getter = `get${type}`; - const setter = `set${type}`; - const makeDataView = () => new DataView( - this._module.HEAPU8.buffer, - this._module.HEAPU8.byteOffset + byteOffset, - byteLength); - let dataView = makeDataView(); - return new Proxy(dataView, { - get(_, prop) { - if (dataView.buffer.byteLength === 0) { - // WebAssembly memory resize detached the buffer. - dataView = makeDataView(); - } - if (prop === getter) { - return function(byteOffset, littleEndian) { - if (!littleEndian) throw new Error('must be little endian'); - return dataView[prop](byteOffset, littleEndian); - } - } - if (prop === setter) { - return function(byteOffset, value, littleEndian) { - if (!littleEndian) throw new Error('must be little endian'); - return dataView[prop](byteOffset, value, littleEndian); - } - } - if (typeof prop === 'string' && (prop.match(/^(get)|(set)/))) { - throw new Error('invalid type'); - } - const result = dataView[prop]; - return typeof result === 'function' ? result.bind(dataView) : result; - } - }); - } - - /** - * @param {number} byteOffset - * @param {number} byteLength - */ - #makeDataArray(byteOffset, byteLength) { - let target = this._module.HEAPU8.subarray(byteOffset, byteOffset + byteLength); - return new Proxy(target, { - get: (_, prop, receiver) => { - if (target.buffer.byteLength === 0) { - // WebAssembly memory resize detached the buffer. - target = this._module.HEAPU8.subarray(byteOffset, byteOffset + byteLength); - } - const result = target[prop]; - return typeof result === 'function' ? result.bind(target) : result; - } - }); - } - - #decodeFilename(zName, flags) { - if (flags & VFS.SQLITE_OPEN_URI) { - // The first null-terminated string is the URI path. Subsequent - // strings are query parameter keys and values. - // https://www.sqlite.org/c3ref/open.html#urifilenamesinsqlite3open - let pName = zName; - let state = 1; - const charCodes = []; - while (state) { - const charCode = this._module.HEAPU8[pName++]; - if (charCode) { - charCodes.push(charCode); - } else { - if (!this._module.HEAPU8[pName]) state = null; - switch (state) { - case 1: // path - charCodes.push('?'.charCodeAt(0)); - state = 2; - break; - case 2: // key - charCodes.push('='.charCodeAt(0)); - state = 3; - break; - case 3: // value - charCodes.push('&'.charCodeAt(0)); - state = 2; - break; - } - } - } - return new TextDecoder().decode(new Uint8Array(charCodes)); - } - return zName ? this._module.UTF8ToString(zName) : null; - } -} - -// Emscripten "legalizes" 64-bit integer arguments by passing them as -// two 32-bit signed integers. -function delegalize(lo32, hi32) { - return (hi32 * 0x100000000) + lo32 + (lo32 < 0 ? 2**32 : 0); -} diff --git a/apps/web/core/local-db/worker/wa-sqlite/src/OPFSCoopSyncVFS.js b/apps/web/core/local-db/worker/wa-sqlite/src/OPFSCoopSyncVFS.js deleted file mode 100644 index 2757ca9db9..0000000000 --- a/apps/web/core/local-db/worker/wa-sqlite/src/OPFSCoopSyncVFS.js +++ /dev/null @@ -1,592 +0,0 @@ -// Copyright 2024 Roy T. Hashimoto. All Rights Reserved. -import { FacadeVFS } from "./FacadeVFS.js"; -import * as VFS from "./VFS.js"; - -const DEFAULT_TEMPORARY_FILES = 10; -const LOCK_NOTIFY_INTERVAL = 1000; - -const DB_RELATED_FILE_SUFFIXES = ["", "-journal", "-wal"]; - -const finalizationRegistry = new FinalizationRegistry((releaser) => releaser()); - -class File { - /** @type {string} */ path; - /** @type {number} */ flags; - /** @type {FileSystemSyncAccessHandle} */ accessHandle; - - /** @type {PersistentFile?} */ persistentFile; - - constructor(path, flags) { - this.path = path; - this.flags = flags; - } -} - -class PersistentFile { - /** @type {FileSystemFileHandle} */ fileHandle; - /** @type {FileSystemSyncAccessHandle} */ accessHandle = null; - - // The following properties are for main database files. - - /** @type {boolean} */ isLockBusy = false; - /** @type {boolean} */ isFileLocked = false; - /** @type {boolean} */ isRequestInProgress = false; - /** @type {function} */ handleLockReleaser = null; - - /** @type {BroadcastChannel} */ handleRequestChannel; - /** @type {boolean} */ isHandleRequested = false; - - constructor(fileHandle) { - this.fileHandle = fileHandle; - } -} - -export class OPFSCoopSyncVFS extends FacadeVFS { - /** @type {Map} */ mapIdToFile = new Map(); - - lastError = null; - log = null; //function(...args) { console.log(`[${contextName}]`, ...args) }; - - /** @type {Map} */ persistentFiles = new Map(); - /** @type {Map} */ boundAccessHandles = new Map(); - /** @type {Set} */ unboundAccessHandles = new Set(); - /** @type {Set} */ accessiblePaths = new Set(); - releaser = null; - - static async create(name, module) { - const vfs = new OPFSCoopSyncVFS(name, module); - await Promise.all([vfs.isReady(), vfs.#initialize(DEFAULT_TEMPORARY_FILES)]); - return vfs; - } - - constructor(name, module) { - super(name, module); - } - - async #initialize(nTemporaryFiles) { - // Delete temporary directories no longer in use. - const root = await navigator.storage.getDirectory(); - // @ts-ignore - for await (const entry of root.values()) { - if (entry.kind === "directory" && entry.name.startsWith(".ahp-")) { - // A lock with the same name as the directory protects it from - // being deleted. - await navigator.locks.request(entry.name, { ifAvailable: true }, async (lock) => { - if (lock) { - this.log?.(`Deleting temporary directory ${entry.name}`); - await root.removeEntry(entry.name, { recursive: true }); - } else { - this.log?.(`Temporary directory ${entry.name} is in use`); - } - }); - } - } - - // Create our temporary directory. - const tmpDirName = `.ahp-${Math.random().toString(36).slice(2)}`; - this.releaser = await new Promise((resolve) => { - navigator.locks.request(tmpDirName, () => { - return new Promise((release) => { - resolve(release); - }); - }); - }); - finalizationRegistry.register(this, this.releaser); - const tmpDir = await root.getDirectoryHandle(tmpDirName, { create: true }); - - // Populate temporary directory. - for (let i = 0; i < nTemporaryFiles; i++) { - const tmpFile = await tmpDir.getFileHandle(`${i}.tmp`, { create: true }); - const tmpAccessHandle = await tmpFile.createSyncAccessHandle(); - this.unboundAccessHandles.add(tmpAccessHandle); - } - } - - /** - * @param {string?} zName - * @param {number} fileId - * @param {number} flags - * @param {DataView} pOutFlags - * @returns {number} - */ - jOpen(zName, fileId, flags, pOutFlags) { - try { - const url = new URL(zName || Math.random().toString(36).slice(2), "file://"); - const path = url.pathname; - - if (flags & VFS.SQLITE_OPEN_MAIN_DB) { - const persistentFile = this.persistentFiles.get(path); - if (persistentFile?.isRequestInProgress) { - // Should not reach here unless SQLite itself retries an open. - // Otherwise, asynchronous operations started on a previous - // open try should have completed. - return VFS.SQLITE_BUSY; - } else if (!persistentFile) { - // This is the usual starting point for opening a database. - // Register a Promise that resolves when the database and related - // files are ready to be used. - this.log?.(`creating persistent file for ${path}`); - const create = !!(flags & VFS.SQLITE_OPEN_CREATE); - this._module.retryOps.push( - (async () => { - try { - // Get the path directory handle. - let dirHandle = await navigator.storage.getDirectory(); - const directories = path.split("/").filter((d) => d); - const filename = directories.pop(); - for (const directory of directories) { - dirHandle = await dirHandle.getDirectoryHandle(directory, { create }); - } - - // Get file handles for the database and related files, - // and create persistent file instances. - for (const suffix of DB_RELATED_FILE_SUFFIXES) { - const fileHandle = await dirHandle.getFileHandle(filename + suffix, { create }); - await this.#createPersistentFile(fileHandle); - } - - // Get access handles for the files. - const file = new File(path, flags); - file.persistentFile = this.persistentFiles.get(path); - await this.#requestAccessHandle(file); - } catch (e) { - // Use an invalid persistent file to signal this error - // for the retried open. - const persistentFile = new PersistentFile(null); - this.persistentFiles.set(path, persistentFile); - console.error(e); - } - })() - ); - return VFS.SQLITE_BUSY; - } else if (!persistentFile.fileHandle) { - // The asynchronous open operation failed. - this.persistentFiles.delete(path); - return VFS.SQLITE_CANTOPEN; - } else if (!persistentFile.accessHandle) { - // This branch is reached if the database was previously opened - // and closed. - this._module.retryOps.push( - (async () => { - const file = new File(path, flags); - file.persistentFile = this.persistentFiles.get(path); - await this.#requestAccessHandle(file); - })() - ); - return VFS.SQLITE_BUSY; - } - } - - if (!this.accessiblePaths.has(path) && !(flags & VFS.SQLITE_OPEN_CREATE)) { - throw new Error(`File ${path} not found`); - } - - const file = new File(path, flags); - this.mapIdToFile.set(fileId, file); - - if (this.persistentFiles.has(path)) { - file.persistentFile = this.persistentFiles.get(path); - } else if (this.boundAccessHandles.has(path)) { - // This temporary file was previously created and closed. Reopen - // the same access handle. - file.accessHandle = this.boundAccessHandles.get(path); - } else if (this.unboundAccessHandles.size) { - // Associate an unbound access handle to this file. - file.accessHandle = this.unboundAccessHandles.values().next().value; - file.accessHandle.truncate(0); - this.unboundAccessHandles.delete(file.accessHandle); - this.boundAccessHandles.set(path, file.accessHandle); - } - this.accessiblePaths.add(path); - - pOutFlags.setInt32(0, flags, true); - return VFS.SQLITE_OK; - } catch (e) { - this.lastError = e; - return VFS.SQLITE_CANTOPEN; - } - } - - /** - * @param {string} zName - * @param {number} syncDir - * @returns {number} - */ - jDelete(zName, syncDir) { - try { - const url = new URL(zName, "file://"); - const path = url.pathname; - if (this.persistentFiles.has(path)) { - const persistentFile = this.persistentFiles.get(path); - persistentFile.accessHandle.truncate(0); - } else { - this.boundAccessHandles.get(path)?.truncate(0); - } - this.accessiblePaths.delete(path); - return VFS.SQLITE_OK; - } catch (e) { - this.lastError = e; - return VFS.SQLITE_IOERR_DELETE; - } - } - - /** - * @param {string} zName - * @param {number} flags - * @param {DataView} pResOut - * @returns {number} - */ - jAccess(zName, flags, pResOut) { - try { - const url = new URL(zName, "file://"); - const path = url.pathname; - pResOut.setInt32(0, this.accessiblePaths.has(path) ? 1 : 0, true); - return VFS.SQLITE_OK; - } catch (e) { - this.lastError = e; - return VFS.SQLITE_IOERR_ACCESS; - } - } - - /** - * @param {number} fileId - * @returns {number} - */ - jClose(fileId) { - try { - const file = this.mapIdToFile.get(fileId); - this.mapIdToFile.delete(fileId); - - if (file?.flags & VFS.SQLITE_OPEN_MAIN_DB) { - if (file.persistentFile?.handleLockReleaser) { - this.#releaseAccessHandle(file); - } - } else if (file?.flags & VFS.SQLITE_OPEN_DELETEONCLOSE) { - file.accessHandle.truncate(0); - this.accessiblePaths.delete(file.path); - if (!this.persistentFiles.has(file.path)) { - this.boundAccessHandles.delete(file.path); - this.unboundAccessHandles.add(file.accessHandle); - } - } - return VFS.SQLITE_OK; - } catch (e) { - this.lastError = e; - return VFS.SQLITE_IOERR_CLOSE; - } - } - - /** - * @param {number} fileId - * @param {Uint8Array} pData - * @param {number} iOffset - * @returns {number} - */ - jRead(fileId, pData, iOffset) { - try { - const file = this.mapIdToFile.get(fileId); - - // On Chrome (at least), passing pData to accessHandle.read() is - // an error because pData is a Proxy of a Uint8Array. Calling - // subarray() produces a real Uint8Array and that works. - const accessHandle = file.accessHandle || file.persistentFile.accessHandle; - const bytesRead = accessHandle.read(pData.subarray(), { at: iOffset }); - - // Opening a database file performs one read without a xLock call. - if (file.flags & VFS.SQLITE_OPEN_MAIN_DB && !file.persistentFile.isFileLocked) { - this.#releaseAccessHandle(file); - } - - if (bytesRead < pData.byteLength) { - pData.fill(0, bytesRead); - return VFS.SQLITE_IOERR_SHORT_READ; - } - return VFS.SQLITE_OK; - } catch (e) { - this.lastError = e; - return VFS.SQLITE_IOERR_READ; - } - } - - /** - * @param {number} fileId - * @param {Uint8Array} pData - * @param {number} iOffset - * @returns {number} - */ - jWrite(fileId, pData, iOffset) { - try { - const file = this.mapIdToFile.get(fileId); - - // On Chrome (at least), passing pData to accessHandle.write() is - // an error because pData is a Proxy of a Uint8Array. Calling - // subarray() produces a real Uint8Array and that works. - const accessHandle = file.accessHandle || file.persistentFile.accessHandle; - const nBytes = accessHandle.write(pData.subarray(), { at: iOffset }); - if (nBytes !== pData.byteLength) throw new Error("short write"); - return VFS.SQLITE_OK; - } catch (e) { - this.lastError = e; - return VFS.SQLITE_IOERR_WRITE; - } - } - - /** - * @param {number} fileId - * @param {number} iSize - * @returns {number} - */ - jTruncate(fileId, iSize) { - try { - const file = this.mapIdToFile.get(fileId); - const accessHandle = file.accessHandle || file.persistentFile.accessHandle; - accessHandle.truncate(iSize); - return VFS.SQLITE_OK; - } catch (e) { - this.lastError = e; - return VFS.SQLITE_IOERR_TRUNCATE; - } - } - - /** - * @param {number} fileId - * @param {number} flags - * @returns {number} - */ - jSync(fileId, flags) { - try { - const file = this.mapIdToFile.get(fileId); - const accessHandle = file.accessHandle || file.persistentFile.accessHandle; - accessHandle.flush(); - return VFS.SQLITE_OK; - } catch (e) { - this.lastError = e; - return VFS.SQLITE_IOERR_FSYNC; - } - } - - /** - * @param {number} fileId - * @param {DataView} pSize64 - * @returns {number} - */ - jFileSize(fileId, pSize64) { - try { - const file = this.mapIdToFile.get(fileId); - const accessHandle = file.accessHandle || file.persistentFile.accessHandle; - const size = accessHandle.getSize(); - pSize64.setBigInt64(0, BigInt(size), true); - return VFS.SQLITE_OK; - } catch (e) { - this.lastError = e; - return VFS.SQLITE_IOERR_FSTAT; - } - } - - /** - * @param {number} fileId - * @param {number} lockType - * @returns {number} - */ - jLock(fileId, lockType) { - const file = this.mapIdToFile.get(fileId); - if (file.persistentFile.isRequestInProgress) { - file.persistentFile.isLockBusy = true; - return VFS.SQLITE_BUSY; - } - - file.persistentFile.isFileLocked = true; - if (!file.persistentFile.handleLockReleaser) { - // Start listening for notifications from other connections. - // This is before we actually get access handles, but waiting to - // listen until then allows a race condition where notifications - // are missed. - file.persistentFile.handleRequestChannel.onmessage = () => { - this.log?.(`received notification for ${file.path}`); - if (file.persistentFile.isFileLocked) { - // We're still using the access handle, so mark it to be - // released when we're done. - file.persistentFile.isHandleRequested = true; - } else { - // Release the access handles immediately. - this.#releaseAccessHandle(file); - } - file.persistentFile.handleRequestChannel.onmessage = null; - }; - - this.#requestAccessHandle(file); - this.log?.("returning SQLITE_BUSY"); - file.persistentFile.isLockBusy = true; - return VFS.SQLITE_BUSY; - } - file.persistentFile.isLockBusy = false; - return VFS.SQLITE_OK; - } - - /** - * @param {number} fileId - * @param {number} lockType - * @returns {number} - */ - jUnlock(fileId, lockType) { - const file = this.mapIdToFile.get(fileId); - if (lockType === VFS.SQLITE_LOCK_NONE) { - // Don't change any state if this unlock is because xLock returned - // SQLITE_BUSY. - if (!file.persistentFile.isLockBusy) { - if (file.persistentFile.isHandleRequested) { - // Another connection wants the access handle. - this.#releaseAccessHandle(file); - this.isHandleRequested = false; - } - file.persistentFile.isFileLocked = false; - } - } - return VFS.SQLITE_OK; - } - - /** - * @param {number} fileId - * @param {number} op - * @param {DataView} pArg - * @returns {number|Promise} - */ - jFileControl(fileId, op, pArg) { - try { - const file = this.mapIdToFile.get(fileId); - switch (op) { - case VFS.SQLITE_FCNTL_PRAGMA: - const key = extractString(pArg, 4); - const value = extractString(pArg, 8); - this.log?.("xFileControl", file.path, "PRAGMA", key, value); - switch (key.toLowerCase()) { - case "journal_mode": - if (value && !["off", "memory", "delete", "wal"].includes(value.toLowerCase())) { - throw new Error('journal_mode must be "off", "memory", "delete", or "wal"'); - } - break; - } - break; - } - } catch (e) { - this.lastError = e; - return VFS.SQLITE_IOERR; - } - return VFS.SQLITE_NOTFOUND; - } - - /** - * @param {Uint8Array} zBuf - * @returns - */ - jGetLastError(zBuf) { - if (this.lastError) { - console.error(this.lastError); - const outputArray = zBuf.subarray(0, zBuf.byteLength - 1); - const { written } = new TextEncoder().encodeInto(this.lastError.message, outputArray); - zBuf[written] = 0; - } - return VFS.SQLITE_OK; - } - - /** - * @param {FileSystemFileHandle} fileHandle - * @returns {Promise} - */ - async #createPersistentFile(fileHandle) { - const persistentFile = new PersistentFile(fileHandle); - const root = await navigator.storage.getDirectory(); - const relativePath = await root.resolve(fileHandle); - const path = `/${relativePath.join("/")}`; - persistentFile.handleRequestChannel = new BroadcastChannel(`ahp:${path}`); - this.persistentFiles.set(path, persistentFile); - - const f = await fileHandle.getFile(); - if (f.size) { - this.accessiblePaths.add(path); - } - return persistentFile; - } - - /** - * @param {File} file - */ - #requestAccessHandle(file) { - console.assert(!file.persistentFile.handleLockReleaser); - if (!file.persistentFile.isRequestInProgress) { - file.persistentFile.isRequestInProgress = true; - this._module.retryOps.push( - (async () => { - // Acquire the Web Lock. - file.persistentFile.handleLockReleaser = await this.#acquireLock(file.persistentFile); - - // Get access handles for the database and releated files in parallel. - this.log?.(`creating access handles for ${file.path}`); - await Promise.all( - DB_RELATED_FILE_SUFFIXES.map(async (suffix) => { - const persistentFile = this.persistentFiles.get(file.path + suffix); - if (persistentFile) { - persistentFile.accessHandle = await persistentFile.fileHandle.createSyncAccessHandle(); - } - }) - ); - file.persistentFile.isRequestInProgress = false; - })() - ); - return this._module.retryOps.at(-1); - } - return Promise.resolve(); - } - - /** - * @param {File} file - */ - async #releaseAccessHandle(file) { - DB_RELATED_FILE_SUFFIXES.forEach(async (suffix) => { - const persistentFile = this.persistentFiles.get(file.path + suffix); - if (persistentFile) { - persistentFile.accessHandle?.close(); - persistentFile.accessHandle = null; - } - }); - this.log?.(`access handles closed for ${file.path}`); - - file.persistentFile.handleLockReleaser?.(); - file.persistentFile.handleLockReleaser = null; - this.log?.(`lock released for ${file.path}`); - } - - /** - * @param {PersistentFile} persistentFile - * @returns {Promise} lock releaser - */ - #acquireLock(persistentFile) { - return new Promise((resolve) => { - // Tell other connections we want the access handle. - const lockName = persistentFile.handleRequestChannel.name; - const notify = () => { - this.log?.(`notifying for ${lockName}`); - persistentFile.handleRequestChannel.postMessage(null); - }; - const notifyId = setInterval(notify, LOCK_NOTIFY_INTERVAL); - setTimeout(notify); - - this.log?.(`lock requested: ${lockName}`); - navigator.locks.request(lockName, (lock) => { - // We have the lock. Stop asking other connections for it. - this.log?.(`lock acquired: ${lockName}`, lock); - clearInterval(notifyId); - return new Promise(resolve); - }); - }); - } -} - -function extractString(dataView, offset) { - const p = dataView.getUint32(offset, true); - if (p) { - const chars = new Uint8Array(dataView.buffer, p); - return new TextDecoder().decode(chars.subarray(0, chars.indexOf(0))); - } - return null; -} diff --git a/apps/web/core/local-db/worker/wa-sqlite/src/VFS.js b/apps/web/core/local-db/worker/wa-sqlite/src/VFS.js deleted file mode 100644 index 12966b9cfb..0000000000 --- a/apps/web/core/local-db/worker/wa-sqlite/src/VFS.js +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright 2024 Roy T. Hashimoto. All Rights Reserved. -import * as VFS from './sqlite-constants.js'; -export * from './sqlite-constants.js'; - -const DEFAULT_SECTOR_SIZE = 512; - -// Base class for a VFS. -export class Base { - name; - mxPathname = 64; - _module; - - /** - * @param {string} name - * @param {object} module - */ - constructor(name, module) { - this.name = name; - this._module = module; - } - - /** - * @returns {void|Promise} - */ - close() { - } - - /** - * @returns {boolean|Promise} - */ - isReady() { - return true; - } - - /** - * Overload in subclasses to indicate which methods are asynchronous. - * @param {string} methodName - * @returns {boolean} - */ - hasAsyncMethod(methodName) { - return false; - } - - /** - * @param {number} pVfs - * @param {number} zName - * @param {number} pFile - * @param {number} flags - * @param {number} pOutFlags - * @returns {number|Promise} - */ - xOpen(pVfs, zName, pFile, flags, pOutFlags) { - return VFS.SQLITE_CANTOPEN; - } - - /** - * @param {number} pVfs - * @param {number} zName - * @param {number} syncDir - * @returns {number|Promise} - */ - xDelete(pVfs, zName, syncDir) { - return VFS.SQLITE_OK; - } - - /** - * @param {number} pVfs - * @param {number} zName - * @param {number} flags - * @param {number} pResOut - * @returns {number|Promise} - */ - xAccess(pVfs, zName, flags, pResOut) { - return VFS.SQLITE_OK; - } - - /** - * @param {number} pVfs - * @param {number} zName - * @param {number} nOut - * @param {number} zOut - * @returns {number|Promise} - */ - xFullPathname(pVfs, zName, nOut, zOut) { - return VFS.SQLITE_OK; - } - - /** - * @param {number} pVfs - * @param {number} nBuf - * @param {number} zBuf - * @returns {number|Promise} - */ - xGetLastError(pVfs, nBuf, zBuf) { - return VFS.SQLITE_OK; - } - - /** - * @param {number} pFile - * @returns {number|Promise} - */ - xClose(pFile) { - return VFS.SQLITE_OK; - } - - /** - * @param {number} pFile - * @param {number} pData - * @param {number} iAmt - * @param {number} iOffsetLo - * @param {number} iOffsetHi - * @returns {number|Promise} - */ - xRead(pFile, pData, iAmt, iOffsetLo, iOffsetHi) { - return VFS.SQLITE_OK; - } - - /** - * @param {number} pFile - * @param {number} pData - * @param {number} iAmt - * @param {number} iOffsetLo - * @param {number} iOffsetHi - * @returns {number|Promise} - */ - xWrite(pFile, pData, iAmt, iOffsetLo, iOffsetHi) { - return VFS.SQLITE_OK; - } - - /** - * @param {number} pFile - * @param {number} sizeLo - * @param {number} sizeHi - * @returns {number|Promise} - */ - xTruncate(pFile, sizeLo, sizeHi) { - return VFS.SQLITE_OK; - } - - /** - * @param {number} pFile - * @param {number} flags - * @returns {number|Promise} - */ - xSync(pFile, flags) { - return VFS.SQLITE_OK; - } - - /** - * - * @param {number} pFile - * @param {number} pSize - * @returns {number|Promise} - */ - xFileSize(pFile, pSize) { - return VFS.SQLITE_OK; - } - - /** - * @param {number} pFile - * @param {number} lockType - * @returns {number|Promise} - */ - xLock(pFile, lockType) { - return VFS.SQLITE_OK; - } - - /** - * @param {number} pFile - * @param {number} lockType - * @returns {number|Promise} - */ - xUnlock(pFile, lockType) { - return VFS.SQLITE_OK; - } - - /** - * @param {number} pFile - * @param {number} pResOut - * @returns {number|Promise} - */ - xCheckReservedLock(pFile, pResOut) { - return VFS.SQLITE_OK; - } - - /** - * @param {number} pFile - * @param {number} op - * @param {number} pArg - * @returns {number|Promise} - */ - xFileControl(pFile, op, pArg) { - return VFS.SQLITE_NOTFOUND; - } - - /** - * @param {number} pFile - * @returns {number|Promise} - */ - xSectorSize(pFile) { - return DEFAULT_SECTOR_SIZE; - } - - /** - * @param {number} pFile - * @returns {number|Promise} - */ - xDeviceCharacteristics(pFile) { - return 0; - } -} - -export const FILE_TYPE_MASK = [ - VFS.SQLITE_OPEN_MAIN_DB, - VFS.SQLITE_OPEN_MAIN_JOURNAL, - VFS.SQLITE_OPEN_TEMP_DB, - VFS.SQLITE_OPEN_TEMP_JOURNAL, - VFS.SQLITE_OPEN_TRANSIENT_DB, - VFS.SQLITE_OPEN_SUBJOURNAL, - VFS.SQLITE_OPEN_SUPER_JOURNAL, - VFS.SQLITE_OPEN_WAL -].reduce((mask, element) => mask | element); \ No newline at end of file diff --git a/apps/web/core/local-db/worker/wa-sqlite/src/sqlite-api.js b/apps/web/core/local-db/worker/wa-sqlite/src/sqlite-api.js deleted file mode 100644 index 500980b4ec..0000000000 --- a/apps/web/core/local-db/worker/wa-sqlite/src/sqlite-api.js +++ /dev/null @@ -1,899 +0,0 @@ -// Copyright 2021 Roy T. Hashimoto. All Rights Reserved. - -import * as SQLite from "./sqlite-constants.js"; -export * from "./sqlite-constants.js"; - -const MAX_INT64 = 0x7fffffffffffffffn; -const MIN_INT64 = -0x8000000000000000n; - -const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor; - -export class SQLiteError extends Error { - constructor(message, code) { - super(message); - this.code = code; - } -} - -const async = true; - -/** - * 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 Emscripten module - * @returns {SQLiteAPI} - */ -export function Factory(Module) { - /** @type {SQLiteAPI} */ const sqlite3 = {}; - - Module.retryOps = []; - const sqliteFreeAddress = Module._getSqliteFree(); - - // Allocate some space for 32-bit returned values. - const tmp = Module._malloc(8); - const tmpPtr = [tmp, tmp + 4]; - - // Convert a JS string to a C string. sqlite3_malloc is used to allocate - // memory (use sqlite3_free to deallocate). - function createUTF8(s) { - if (typeof s !== "string") return 0; - const utf8 = new TextEncoder().encode(s); - const zts = Module._sqlite3_malloc(utf8.byteLength + 1); - Module.HEAPU8.set(utf8, zts); - Module.HEAPU8[zts + utf8.byteLength] = 0; - return zts; - } - - /** - * Concatenate 32-bit numbers into a 64-bit (signed) BigInt. - * @param {number} lo32 - * @param {number} hi32 - * @returns {bigint} - */ - function cvt32x2ToBigInt(lo32, hi32) { - return (BigInt(hi32) << 32n) | (BigInt(lo32) & 0xffffffffn); - } - - /** - * Concatenate 32-bit numbers and return as number or BigInt, depending - * on the value. - * @param {number} lo32 - * @param {number} hi32 - * @returns {number|bigint} - */ - const cvt32x2AsSafe = (function () { - const hiMax = BigInt(Number.MAX_SAFE_INTEGER) >> 32n; - const hiMin = BigInt(Number.MIN_SAFE_INTEGER) >> 32n; - - return function (lo32, hi32) { - if (hi32 > hiMax || hi32 < hiMin) { - // Can't be expressed as a Number so use BigInt. - return cvt32x2ToBigInt(lo32, hi32); - } else { - // Combine the upper and lower 32-bit numbers. The complication is - // that lo32 is a signed integer which makes manipulating its bits - // a little tricky - the sign bit gets handled separately. - return hi32 * 0x100000000 + (lo32 & 0x7fffffff) - (lo32 & 0x80000000); - } - }; - })(); - - const databases = new Set(); - function verifyDatabase(db) { - if (!databases.has(db)) { - throw new SQLiteError("not a database", SQLite.SQLITE_MISUSE); - } - } - - const mapStmtToDB = new Map(); - function verifyStatement(stmt) { - if (!mapStmtToDB.has(stmt)) { - throw new SQLiteError("not a statement", SQLite.SQLITE_MISUSE); - } - } - - sqlite3.bind_collection = function (stmt, bindings) { - verifyStatement(stmt); - const isArray = Array.isArray(bindings); - const nBindings = sqlite3.bind_parameter_count(stmt); - for (let i = 1; i <= nBindings; ++i) { - const key = isArray ? i - 1 : sqlite3.bind_parameter_name(stmt, i); - const value = bindings[key]; - if (value !== undefined) { - sqlite3.bind(stmt, i, value); - } - } - return SQLite.SQLITE_OK; - }; - - sqlite3.bind = function (stmt, i, value) { - verifyStatement(stmt); - switch (typeof value) { - case "number": - if (value === (value | 0)) { - return sqlite3.bind_int(stmt, i, value); - } else { - return sqlite3.bind_double(stmt, i, value); - } - case "string": - return sqlite3.bind_text(stmt, i, value); - default: - if (value instanceof Uint8Array || Array.isArray(value)) { - return sqlite3.bind_blob(stmt, i, value); - } else if (value === null) { - return sqlite3.bind_null(stmt, i); - } else if (typeof value === "bigint") { - return sqlite3.bind_int64(stmt, i, value); - } else if (value === undefined) { - // Existing binding (or NULL) will be used. - return SQLite.SQLITE_NOTICE; - } else { - console.warn("unknown binding converted to null", value); - return sqlite3.bind_null(stmt, i); - } - } - }; - - sqlite3.bind_blob = (function () { - const fname = "sqlite3_bind_blob"; - const f = Module.cwrap(fname, ...decl("nnnnn:n")); - return function (stmt, i, value) { - verifyStatement(stmt); - // @ts-ignore - const byteLength = value.byteLength ?? value.length; - const ptr = Module._sqlite3_malloc(byteLength); - Module.HEAPU8.subarray(ptr).set(value); - const result = f(stmt, i, ptr, byteLength, sqliteFreeAddress); - return check(fname, result, mapStmtToDB.get(stmt)); - }; - })(); - - sqlite3.bind_parameter_count = (function () { - const fname = "sqlite3_bind_parameter_count"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (stmt) { - verifyStatement(stmt); - const result = f(stmt); - return result; - }; - })(); - - sqlite3.bind_double = (function () { - const fname = "sqlite3_bind_double"; - const f = Module.cwrap(fname, ...decl("nnn:n")); - return function (stmt, i, value) { - verifyStatement(stmt); - const result = f(stmt, i, value); - return check(fname, result, mapStmtToDB.get(stmt)); - }; - })(); - - sqlite3.bind_int = (function () { - const fname = "sqlite3_bind_int"; - const f = Module.cwrap(fname, ...decl("nnn:n")); - return function (stmt, i, value) { - verifyStatement(stmt); - if (value > 0x7fffffff || value < -0x80000000) return SQLite.SQLITE_RANGE; - - const result = f(stmt, i, value); - return check(fname, result, mapStmtToDB.get(stmt)); - }; - })(); - - sqlite3.bind_int64 = (function () { - const fname = "sqlite3_bind_int64"; - const f = Module.cwrap(fname, ...decl("nnnn:n")); - return function (stmt, i, value) { - verifyStatement(stmt); - if (value > MAX_INT64 || value < MIN_INT64) return SQLite.SQLITE_RANGE; - - const lo32 = value & 0xffffffffn; - const hi32 = value >> 32n; - const result = f(stmt, i, Number(lo32), Number(hi32)); - return check(fname, result, mapStmtToDB.get(stmt)); - }; - })(); - - sqlite3.bind_null = (function () { - const fname = "sqlite3_bind_null"; - const f = Module.cwrap(fname, ...decl("nn:n")); - return function (stmt, i) { - verifyStatement(stmt); - const result = f(stmt, i); - return check(fname, result, mapStmtToDB.get(stmt)); - }; - })(); - - sqlite3.bind_parameter_name = (function () { - const fname = "sqlite3_bind_parameter_name"; - const f = Module.cwrap(fname, ...decl("n:s")); - return function (stmt, i) { - verifyStatement(stmt); - const result = f(stmt, i); - return result; - }; - })(); - - sqlite3.bind_text = (function () { - const fname = "sqlite3_bind_text"; - const f = Module.cwrap(fname, ...decl("nnnnn:n")); - return function (stmt, i, value) { - verifyStatement(stmt); - const ptr = createUTF8(value); - const result = f(stmt, i, ptr, -1, sqliteFreeAddress); - return check(fname, result, mapStmtToDB.get(stmt)); - }; - })(); - - sqlite3.changes = (function () { - const fname = "sqlite3_changes"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (db) { - verifyDatabase(db); - const result = f(db); - return result; - }; - })(); - - sqlite3.clear_bindings = (function () { - const fname = "sqlite3_clear_bindings"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (stmt) { - verifyStatement(stmt); - const result = f(stmt); - return check(fname, result, mapStmtToDB.get(stmt)); - }; - })(); - - sqlite3.close = (function () { - const fname = "sqlite3_close"; - const f = Module.cwrap(fname, ...decl("n:n"), { async }); - return async function (db) { - verifyDatabase(db); - const result = await f(db); - databases.delete(db); - return check(fname, result, db); - }; - })(); - - sqlite3.column = function (stmt, iCol) { - verifyStatement(stmt); - const type = sqlite3.column_type(stmt, iCol); - switch (type) { - case SQLite.SQLITE_BLOB: - return sqlite3.column_blob(stmt, iCol); - case SQLite.SQLITE_FLOAT: - return sqlite3.column_double(stmt, iCol); - case SQLite.SQLITE_INTEGER: - const lo32 = sqlite3.column_int(stmt, iCol); - const hi32 = Module.getTempRet0(); - return cvt32x2AsSafe(lo32, hi32); - case SQLite.SQLITE_NULL: - return null; - case SQLite.SQLITE_TEXT: - return sqlite3.column_text(stmt, iCol); - default: - throw new SQLiteError("unknown type", type); - } - }; - - sqlite3.column_blob = (function () { - const fname = "sqlite3_column_blob"; - const f = Module.cwrap(fname, ...decl("nn:n")); - return function (stmt, iCol) { - verifyStatement(stmt); - const nBytes = sqlite3.column_bytes(stmt, iCol); - const address = f(stmt, iCol); - const result = Module.HEAPU8.subarray(address, address + nBytes); - return result; - }; - })(); - - sqlite3.column_bytes = (function () { - const fname = "sqlite3_column_bytes"; - const f = Module.cwrap(fname, ...decl("nn:n")); - return function (stmt, iCol) { - verifyStatement(stmt); - const result = f(stmt, iCol); - return result; - }; - })(); - - sqlite3.column_count = (function () { - const fname = "sqlite3_column_count"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (stmt) { - verifyStatement(stmt); - const result = f(stmt); - return result; - }; - })(); - - sqlite3.column_double = (function () { - const fname = "sqlite3_column_double"; - const f = Module.cwrap(fname, ...decl("nn:n")); - return function (stmt, iCol) { - verifyStatement(stmt); - const result = f(stmt, iCol); - return result; - }; - })(); - - sqlite3.column_int = (function () { - // Retrieve int64 but use only the lower 32 bits. The upper 32-bits are - // accessible with Module.getTempRet0(). - const fname = "sqlite3_column_int64"; - const f = Module.cwrap(fname, ...decl("nn:n")); - return function (stmt, iCol) { - verifyStatement(stmt); - const result = f(stmt, iCol); - return result; - }; - })(); - - sqlite3.column_int64 = (function () { - const fname = "sqlite3_column_int64"; - const f = Module.cwrap(fname, ...decl("nn:n")); - return function (stmt, iCol) { - verifyStatement(stmt); - const lo32 = f(stmt, iCol); - const hi32 = Module.getTempRet0(); - const result = cvt32x2ToBigInt(lo32, hi32); - return result; - }; - })(); - - sqlite3.column_name = (function () { - const fname = "sqlite3_column_name"; - const f = Module.cwrap(fname, ...decl("nn:s")); - return function (stmt, iCol) { - verifyStatement(stmt); - const result = f(stmt, iCol); - return result; - }; - })(); - - sqlite3.column_names = function (stmt) { - const columns = []; - const nColumns = sqlite3.column_count(stmt); - for (let i = 0; i < nColumns; ++i) { - columns.push(sqlite3.column_name(stmt, i)); - } - return columns; - }; - - sqlite3.column_text = (function () { - const fname = "sqlite3_column_text"; - const f = Module.cwrap(fname, ...decl("nn:s")); - return function (stmt, iCol) { - verifyStatement(stmt); - const result = f(stmt, iCol); - return result; - }; - })(); - - sqlite3.column_type = (function () { - const fname = "sqlite3_column_type"; - const f = Module.cwrap(fname, ...decl("nn:n")); - return function (stmt, iCol) { - verifyStatement(stmt); - const result = f(stmt, iCol); - return result; - }; - })(); - - sqlite3.create_function = function (db, zFunctionName, nArg, eTextRep, pApp, xFunc, xStep, xFinal) { - verifyDatabase(db); - - // Convert SQLite callback arguments to JavaScript-friendly arguments. - function adapt(f) { - return f instanceof AsyncFunction - ? async (ctx, n, values) => f(ctx, Module.HEAP32.subarray(values / 4, values / 4 + n)) - : (ctx, n, values) => f(ctx, Module.HEAP32.subarray(values / 4, values / 4 + n)); - } - - const result = Module.create_function( - db, - zFunctionName, - nArg, - eTextRep, - pApp, - xFunc && adapt(xFunc), - xStep && adapt(xStep), - xFinal - ); - return check("sqlite3_create_function", result, db); - }; - - sqlite3.data_count = (function () { - const fname = "sqlite3_data_count"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (stmt) { - verifyStatement(stmt); - const result = f(stmt); - return result; - }; - })(); - - sqlite3.exec = async function (db, sql, callback) { - for await (const stmt of sqlite3.statements(db, sql)) { - let columns; - while ((await sqlite3.step(stmt)) === SQLite.SQLITE_ROW) { - if (callback) { - columns = columns ?? sqlite3.column_names(stmt); - const row = sqlite3.row(stmt); - await callback(row, columns); - } - } - } - return SQLite.SQLITE_OK; - }; - - sqlite3.finalize = (function () { - const fname = "sqlite3_finalize"; - const f = Module.cwrap(fname, ...decl("n:n"), { async }); - return async function (stmt) { - const result = await f(stmt); - mapStmtToDB.delete(stmt); - - // Don't throw on error here. Typically the error has already been - // thrown and finalize() is part of the cleanup. - return result; - }; - })(); - - sqlite3.get_autocommit = (function () { - const fname = "sqlite3_get_autocommit"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (db) { - const result = f(db); - return result; - }; - })(); - - sqlite3.libversion = (function () { - const fname = "sqlite3_libversion"; - const f = Module.cwrap(fname, ...decl(":s")); - return function () { - const result = f(); - return result; - }; - })(); - - sqlite3.libversion_number = (function () { - const fname = "sqlite3_libversion_number"; - const f = Module.cwrap(fname, ...decl(":n")); - return function () { - const result = f(); - return result; - }; - })(); - - sqlite3.limit = (function () { - const fname = "sqlite3_limit"; - const f = Module.cwrap(fname, ...decl("nnn:n")); - return function (db, id, newVal) { - const result = f(db, id, newVal); - return result; - }; - })(); - - sqlite3.open_v2 = (function () { - const fname = "sqlite3_open_v2"; - const f = Module.cwrap(fname, ...decl("snnn:n"), { async }); - return async function (zFilename, flags, zVfs) { - flags = flags || SQLite.SQLITE_OPEN_CREATE | SQLite.SQLITE_OPEN_READWRITE; - zVfs = createUTF8(zVfs); - try { - // Allow retry operations. - const rc = await retry(() => f(zFilename, tmpPtr[0], flags, zVfs)); - - const db = Module.getValue(tmpPtr[0], "*"); - databases.add(db); - - Module.ccall("RegisterExtensionFunctions", "void", ["number"], [db]); - check(fname, rc); - return db; - } finally { - Module._sqlite3_free(zVfs); - } - }; - })(); - - sqlite3.progress_handler = function (db, nProgressOps, handler, userData) { - verifyDatabase(db); - Module.progress_handler(db, nProgressOps, handler, userData); - }; - - sqlite3.reset = (function () { - const fname = "sqlite3_reset"; - const f = Module.cwrap(fname, ...decl("n:n"), { async }); - return async function (stmt) { - verifyStatement(stmt); - const result = await f(stmt); - return check(fname, result, mapStmtToDB.get(stmt)); - }; - })(); - - sqlite3.result = function (context, value) { - switch (typeof value) { - case "number": - if (value === (value | 0)) { - sqlite3.result_int(context, value); - } else { - sqlite3.result_double(context, value); - } - break; - case "string": - sqlite3.result_text(context, value); - break; - default: - if (value instanceof Uint8Array || Array.isArray(value)) { - sqlite3.result_blob(context, value); - } else if (value === null) { - sqlite3.result_null(context); - } else if (typeof value === "bigint") { - return sqlite3.result_int64(context, value); - } else { - console.warn("unknown result converted to null", value); - sqlite3.result_null(context); - } - break; - } - }; - - sqlite3.result_blob = (function () { - const fname = "sqlite3_result_blob"; - const f = Module.cwrap(fname, ...decl("nnnn:n")); - return function (context, value) { - // @ts-ignore - const byteLength = value.byteLength ?? value.length; - const ptr = Module._sqlite3_malloc(byteLength); - Module.HEAPU8.subarray(ptr).set(value); - f(context, ptr, byteLength, sqliteFreeAddress); // void return - }; - })(); - - sqlite3.result_double = (function () { - const fname = "sqlite3_result_double"; - const f = Module.cwrap(fname, ...decl("nn:n")); - return function (context, value) { - f(context, value); // void return - }; - })(); - - sqlite3.result_int = (function () { - const fname = "sqlite3_result_int"; - const f = Module.cwrap(fname, ...decl("nn:n")); - return function (context, value) { - f(context, value); // void return - }; - })(); - - sqlite3.result_int64 = (function () { - const fname = "sqlite3_result_int64"; - const f = Module.cwrap(fname, ...decl("nnn:n")); - return function (context, value) { - if (value > MAX_INT64 || value < MIN_INT64) return SQLite.SQLITE_RANGE; - - const lo32 = value & 0xffffffffn; - const hi32 = value >> 32n; - f(context, Number(lo32), Number(hi32)); // void return - }; - })(); - - sqlite3.result_null = (function () { - const fname = "sqlite3_result_null"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (context) { - f(context); // void return - }; - })(); - - sqlite3.result_text = (function () { - const fname = "sqlite3_result_text"; - const f = Module.cwrap(fname, ...decl("nnnn:n")); - return function (context, value) { - const ptr = createUTF8(value); - f(context, ptr, -1, sqliteFreeAddress); // void return - }; - })(); - - sqlite3.row = function (stmt) { - const row = []; - const nColumns = sqlite3.data_count(stmt); - for (let i = 0; i < nColumns; ++i) { - const value = sqlite3.column(stmt, i); - - // Copy blob if aliasing volatile WebAssembly memory. This avoids an - // unnecessary copy if users monkey patch column_blob to copy. - // @ts-ignore - row.push(value?.buffer === Module.HEAPU8.buffer ? value.slice() : value); - } - return row; - }; - - sqlite3.set_authorizer = function (db, xAuth, pApp) { - verifyDatabase(db); - - // Convert SQLite callback arguments to JavaScript-friendly arguments. - function cvtArgs(_, iAction, p3, p4, p5, p6) { - return [ - _, - iAction, - Module.UTF8ToString(p3), - Module.UTF8ToString(p4), - Module.UTF8ToString(p5), - Module.UTF8ToString(p6), - ]; - } - function adapt(f) { - return f instanceof AsyncFunction - ? async (_, iAction, p3, p4, p5, p6) => f(...cvtArgs(_, iAction, p3, p4, p5, p6)) - : (_, iAction, p3, p4, p5, p6) => f(...cvtArgs(_, iAction, p3, p4, p5, p6)); - } - - const result = Module.set_authorizer(db, adapt(xAuth), pApp); - return check("sqlite3_set_authorizer", result, db); - }; - - sqlite3.sql = (function () { - const fname = "sqlite3_sql"; - const f = Module.cwrap(fname, ...decl("n:s")); - return function (stmt) { - verifyStatement(stmt); - const result = f(stmt); - return result; - }; - })(); - - sqlite3.statements = function (db, sql, options = {}) { - const prepare = Module.cwrap( - "sqlite3_prepare_v3", - "number", - ["number", "number", "number", "number", "number", "number"], - { async: true } - ); - - return (async function* () { - const onFinally = []; - try { - // Encode SQL string to UTF-8. - const utf8 = new TextEncoder().encode(sql); - - // Copy encoded string to WebAssembly memory. The SQLite docs say - // zero-termination is a minor optimization so add room for that. - // Also add space for the statement handle and SQL tail pointer. - const allocSize = utf8.byteLength - (utf8.byteLength % 4) + 12; - const pzHead = Module._sqlite3_malloc(allocSize); - const pzEnd = pzHead + utf8.byteLength + 1; - onFinally.push(() => Module._sqlite3_free(pzHead)); - Module.HEAPU8.set(utf8, pzHead); - Module.HEAPU8[pzEnd - 1] = 0; - - // Use extra space for the statement handle and SQL tail pointer. - const pStmt = pzHead + allocSize - 8; - const pzTail = pzHead + allocSize - 4; - - // Ensure that statement handles are not leaked. - let stmt; - function maybeFinalize() { - if (stmt && !options.unscoped) { - sqlite3.finalize(stmt); - } - stmt = 0; - } - onFinally.push(maybeFinalize); - - // Loop over statements. - Module.setValue(pzTail, pzHead, "*"); - do { - // Reclaim resources for the previous iteration. - maybeFinalize(); - - // Call sqlite3_prepare_v3() for the next statement. - // Allow retry operations. - const zTail = Module.getValue(pzTail, "*"); - const rc = await retry(() => { - return prepare(db, zTail, pzEnd - pzTail, options.flags || 0, pStmt, pzTail); - }); - - if (rc !== SQLite.SQLITE_OK) { - check("sqlite3_prepare_v3", rc, db); - } - - stmt = Module.getValue(pStmt, "*"); - if (stmt) { - mapStmtToDB.set(stmt, db); - yield stmt; - } - } while (stmt); - } finally { - while (onFinally.length) { - onFinally.pop()(); - } - } - })(); - }; - - sqlite3.step = (function () { - const fname = "sqlite3_step"; - const f = Module.cwrap(fname, ...decl("n:n"), { async }); - return async function (stmt) { - verifyStatement(stmt); - - // Allow retry operations. - const rc = await retry(() => f(stmt)); - - return check(fname, rc, mapStmtToDB.get(stmt), [SQLite.SQLITE_ROW, SQLite.SQLITE_DONE]); - }; - })(); - - sqlite3.update_hook = function (db, xUpdateHook) { - verifyDatabase(db); - - // Convert SQLite callback arguments to JavaScript-friendly arguments. - function cvtArgs(iUpdateType, dbName, tblName, lo32, hi32) { - return [iUpdateType, Module.UTF8ToString(dbName), Module.UTF8ToString(tblName), cvt32x2ToBigInt(lo32, hi32)]; - } - function adapt(f) { - return f instanceof AsyncFunction - ? async (iUpdateType, dbName, tblName, lo32, hi32) => f(...cvtArgs(iUpdateType, dbName, tblName, lo32, hi32)) - : (iUpdateType, dbName, tblName, lo32, hi32) => f(...cvtArgs(iUpdateType, dbName, tblName, lo32, hi32)); - } - - Module.update_hook(db, adapt(xUpdateHook)); - }; - - sqlite3.value = function (pValue) { - const type = sqlite3.value_type(pValue); - switch (type) { - case SQLite.SQLITE_BLOB: - return sqlite3.value_blob(pValue); - case SQLite.SQLITE_FLOAT: - return sqlite3.value_double(pValue); - case SQLite.SQLITE_INTEGER: - const lo32 = sqlite3.value_int(pValue); - const hi32 = Module.getTempRet0(); - return cvt32x2AsSafe(lo32, hi32); - case SQLite.SQLITE_NULL: - return null; - case SQLite.SQLITE_TEXT: - return sqlite3.value_text(pValue); - default: - throw new SQLiteError("unknown type", type); - } - }; - - sqlite3.value_blob = (function () { - const fname = "sqlite3_value_blob"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (pValue) { - const nBytes = sqlite3.value_bytes(pValue); - const address = f(pValue); - const result = Module.HEAPU8.subarray(address, address + nBytes); - return result; - }; - })(); - - sqlite3.value_bytes = (function () { - const fname = "sqlite3_value_bytes"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (pValue) { - const result = f(pValue); - return result; - }; - })(); - - sqlite3.value_double = (function () { - const fname = "sqlite3_value_double"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (pValue) { - const result = f(pValue); - return result; - }; - })(); - - sqlite3.value_int = (function () { - const fname = "sqlite3_value_int64"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (pValue) { - const result = f(pValue); - return result; - }; - })(); - - sqlite3.value_int64 = (function () { - const fname = "sqlite3_value_int64"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (pValue) { - const lo32 = f(pValue); - const hi32 = Module.getTempRet0(); - const result = cvt32x2ToBigInt(lo32, hi32); - return result; - }; - })(); - - sqlite3.value_text = (function () { - const fname = "sqlite3_value_text"; - const f = Module.cwrap(fname, ...decl("n:s")); - return function (pValue) { - const result = f(pValue); - return result; - }; - })(); - - sqlite3.value_type = (function () { - const fname = "sqlite3_value_type"; - const f = Module.cwrap(fname, ...decl("n:n")); - return function (pValue) { - const result = f(pValue); - return result; - }; - })(); - - sqlite3.vfs_register = function (vfs, makeDefault) { - const result = Module.vfs_register(vfs, makeDefault); - return check("sqlite3_vfs_register", result); - }; - - function check(fname, result, db = null, allowed = [SQLite.SQLITE_OK]) { - if (allowed.includes(result)) return result; - const message = db ? Module.ccall("sqlite3_errmsg", "string", ["number"], [db]) : fname; - throw new SQLiteError(message, result); - } - - // This function is used to automatically retry failed calls that - // have pending retry operations that should allow the retry to - // succeed. - async function retry(f) { - let rc; - do { - // Wait for all pending retry operations to complete. This is - // normally empty on the first loop iteration. - if (Module.retryOps.length) { - await Promise.all(Module.retryOps); - Module.retryOps = []; - } - - rc = await f(); - - // Retry on failure with new pending retry operations. - } while (rc && Module.retryOps.length); - return rc; - } - - return sqlite3; -} - -// Helper function to use a more compact signature specification. -function decl(s) { - const result = []; - const m = s.match(/([ns@]*):([nsv@])/); - switch (m[2]) { - case "n": - result.push("number"); - break; - case "s": - result.push("string"); - break; - case "v": - result.push(null); - break; - } - - const args = []; - for (let c of m[1]) { - switch (c) { - case "n": - args.push("number"); - break; - case "s": - args.push("string"); - break; - } - } - result.push(args); - return result; -} diff --git a/apps/web/core/local-db/worker/wa-sqlite/src/sqlite-constants.js b/apps/web/core/local-db/worker/wa-sqlite/src/sqlite-constants.js deleted file mode 100644 index 3878b16963..0000000000 --- a/apps/web/core/local-db/worker/wa-sqlite/src/sqlite-constants.js +++ /dev/null @@ -1,275 +0,0 @@ -// Primary result codes. -// https://www.sqlite.org/rescode.html -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; - -// Extended error codes. -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; - -// Other extended result codes. -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; - -// Open flags. -// https://www.sqlite.org/c3ref/c_open_autoproxy.html -export const SQLITE_OPEN_READONLY = 0x00000001; -export const SQLITE_OPEN_READWRITE = 0x00000002; -export const SQLITE_OPEN_CREATE = 0x00000004; -export const SQLITE_OPEN_DELETEONCLOSE = 0x00000008; -export const SQLITE_OPEN_EXCLUSIVE = 0x00000010; -export const SQLITE_OPEN_AUTOPROXY = 0x00000020; -export const SQLITE_OPEN_URI = 0x00000040; -export const SQLITE_OPEN_MEMORY = 0x00000080; -export const SQLITE_OPEN_MAIN_DB = 0x00000100; -export const SQLITE_OPEN_TEMP_DB = 0x00000200; -export const SQLITE_OPEN_TRANSIENT_DB = 0x00000400; -export const SQLITE_OPEN_MAIN_JOURNAL = 0x00000800; -export const SQLITE_OPEN_TEMP_JOURNAL = 0x00001000; -export const SQLITE_OPEN_SUBJOURNAL = 0x00002000; -export const SQLITE_OPEN_SUPER_JOURNAL = 0x00004000; -export const SQLITE_OPEN_NOMUTEX = 0x00008000; -export const SQLITE_OPEN_FULLMUTEX = 0x00010000; -export const SQLITE_OPEN_SHAREDCACHE = 0x00020000; -export const SQLITE_OPEN_PRIVATECACHE = 0x00040000; -export const SQLITE_OPEN_WAL = 0x00080000; -export const SQLITE_OPEN_NOFOLLOW = 0x01000000; - -// Locking levels. -// https://www.sqlite.org/c3ref/c_lock_exclusive.html -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; - -// Device characteristics. -// https://www.sqlite.org/c3ref/c_iocap_atomic.html -export const SQLITE_IOCAP_ATOMIC = 0x00000001; -export const SQLITE_IOCAP_ATOMIC512 = 0x00000002; -export const SQLITE_IOCAP_ATOMIC1K = 0x00000004; -export const SQLITE_IOCAP_ATOMIC2K = 0x00000008; -export const SQLITE_IOCAP_ATOMIC4K = 0x00000010; -export const SQLITE_IOCAP_ATOMIC8K = 0x00000020; -export const SQLITE_IOCAP_ATOMIC16K = 0x00000040; -export const SQLITE_IOCAP_ATOMIC32K = 0x00000080; -export const SQLITE_IOCAP_ATOMIC64K = 0x00000100; -export const SQLITE_IOCAP_SAFE_APPEND = 0x00000200; -export const SQLITE_IOCAP_SEQUENTIAL = 0x00000400; -export const SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN = 0x00000800; -export const SQLITE_IOCAP_POWERSAFE_OVERWRITE = 0x00001000; -export const SQLITE_IOCAP_IMMUTABLE = 0x00002000; -export const SQLITE_IOCAP_BATCH_ATOMIC = 0x00004000; - -// xAccess flags. -// https://www.sqlite.org/c3ref/c_access_exists.html -export const SQLITE_ACCESS_EXISTS = 0; -export const SQLITE_ACCESS_READWRITE = 1; -export const SQLITE_ACCESS_READ = 2; - -// File control opcodes -// https://www.sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlbeginatomicwrite -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; - -// Fundamental datatypes. -// https://www.sqlite.org/c3ref/c_blob.html -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; - -// Special destructor behavior. -// https://www.sqlite.org/c3ref/c_static.html -export const SQLITE_STATIC = 0; -export const SQLITE_TRANSIENT = -1; - -// Text encodings. -// https://sqlite.org/c3ref/c_any.html -export const SQLITE_UTF8 = 1; /* IMP: R-37514-35566 */ -export const SQLITE_UTF16LE = 2; /* IMP: R-03371-37637 */ -export const SQLITE_UTF16BE = 3; /* IMP: R-51971-34154 */ -export const SQLITE_UTF16 = 4; /* Use native byte order */ - -// Module constraint ops. -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; /* Scan visits at most = 1 row */ - -// Function flags -export const SQLITE_DETERMINISTIC = 0x000000800; -export const SQLITE_DIRECTONLY = 0x000080000; -export const SQLITE_SUBTYPE = 0x000100000; -export const SQLITE_INNOCUOUS = 0x000200000; - -// Sync flags -export const SQLITE_SYNC_NORMAL = 0x00002; -export const SQLITE_SYNC_FULL = 0x00003; -export const SQLITE_SYNC_DATAONLY = 0x00010; - -// Authorizer action codes -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; - -// Authorizer return codes -export const SQLITE_DENY = 1; -export const SQLITE_IGNORE = 2; - -// Limit categories -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; - -export const SQLITE_PREPARE_PERSISTENT = 0x01; -export const SQLITE_PREPARE_NORMALIZED = 0x02; -export const SQLITE_PREPARE_NO_VTAB = 0x04; \ No newline at end of file diff --git a/apps/web/core/local-db/worker/wa-sqlite/src/types/globals.d.ts b/apps/web/core/local-db/worker/wa-sqlite/src/types/globals.d.ts deleted file mode 100644 index e32bd32c80..0000000000 --- a/apps/web/core/local-db/worker/wa-sqlite/src/types/globals.d.ts +++ /dev/null @@ -1,62 +0,0 @@ -/* eslint-disable no-var */ - -declare namespace Asyncify { - function handleAsync(f: () => Promise); -} - -declare function UTF8ToString(ptr: number): string; -declare function lengthBytesUTF8(s: string): number; -declare function stringToUTF8(s: string, p: number, n: number); -declare function ccall(name: string, returns: string, args: Array, options?: object): any; -declare function getValue(ptr: number, type: string): number; -declare function setValue(ptr: number, value: number, type: string): number; -declare function mergeInto(library: object, methods: object): void; - -declare var HEAPU8: Uint8Array; -declare var HEAPU32: Uint32Array; -declare var LibraryManager; -declare var Module; -declare var _vfsAccess; -declare var _vfsCheckReservedLock; -declare var _vfsClose; -declare var _vfsDelete; -declare var _vfsDeviceCharacteristics; -declare var _vfsFileControl; -declare var _vfsFileSize; -declare var _vfsLock; -declare var _vfsOpen; -declare var _vfsRead; -declare var _vfsSectorSize; -declare var _vfsSync; -declare var _vfsTruncate; -declare var _vfsUnlock; -declare var _vfsWrite; - -declare var _jsFunc; -declare var _jsStep; -declare var _jsFinal; - -declare var _modStruct; -declare var _modCreate; -declare var _modConnect; -declare var _modBestIndex; -declare var _modDisconnect; -declare var _modDestroy; -declare var _modOpen; -declare var _modClose; -declare var _modFilter; -declare var _modNext; -declare var _modEof; -declare var _modColumn; -declare var _modRowid; -declare var _modUpdate; -declare var _modBegin; -declare var _modSync; -declare var _modCommit; -declare var _modRollback; -declare var _modFindFunction; -declare var _modRename; - -declare var _jsAuth; - -declare var _jsProgress; diff --git a/apps/web/core/local-db/worker/wa-sqlite/src/types/index.d.ts b/apps/web/core/local-db/worker/wa-sqlite/src/types/index.d.ts deleted file mode 100644 index 54da72fdd1..0000000000 --- a/apps/web/core/local-db/worker/wa-sqlite/src/types/index.d.ts +++ /dev/null @@ -1,1294 +0,0 @@ -/** - * This is a WebAssembly build of SQLite with experimental support for - * writing SQLite virtual file systems and modules (for virtual tables) - * in Javascript. Also see the - * [GitHub repository](https://github.com/rhashimoto/wa-sqlite) and the - * [online demo](https://rhashimoto.github.io/wa-sqlite/demo/). - * @module - */ - -/** - * Javascript types that SQLite can use - * - * C integer and floating-point types both map to/from Javascript `number`. - * Blob data can be provided to SQLite as `Uint8Array` or `number[]` (with - * each element converted to a byte); SQLite always returns blob data as - * `Uint8Array` - */ -type SQLiteCompatibleType = number | string | Uint8Array | Array | bigint | null; - -/** - * SQLite Virtual File System object - * - * Objects with this interface can be passed to {@link SQLiteAPI.vfs_register} - * to define a new filesystem. - * - * There are examples of a synchronous - * [MemoryVFS.js](https://github.com/rhashimoto/wa-sqlite/blob/master/src/examples/MemoryVFS.js), - * and asynchronous - * [MemoryAsyncVFS.js](https://github.com/rhashimoto/wa-sqlite/blob/master/src/examples/MemoryAsyncVFS.js) - * and - * [IndexedDbVFS.js](https://github.com/rhashimoto/wa-sqlite/blob/master/src/examples/IndexedDbVFS.js). - * - * @see https://sqlite.org/vfs.html - * @see https://sqlite.org/c3ref/io_methods.html - */ -declare interface SQLiteVFS { - /** Maximum length of a file path in UTF-8 bytes (default 64) */ - mxPathName?: number; - - close(): void | Promise; - isReady(): boolean | Promise; - - /** @see https://sqlite.org/c3ref/io_methods.html */ - xClose(fileId: number): number | Promise; - - /** @see https://sqlite.org/c3ref/io_methods.html */ - xRead(fileId: number, pData: number, iAmt: number, iOffsetLo: number, iOffsetHi: number): number | Promise; - - /** @see https://sqlite.org/c3ref/io_methods.html */ - xWrite(fileId: number, pData: number, iAmt: number, iOffsetLo: number, iOffsetHi: number): number | Promise; - - /** @see https://sqlite.org/c3ref/io_methods.html */ - xTruncate(fileId: number, iSizeLo: number, iSizeHi): number | Promise; - - /** @see https://sqlite.org/c3ref/io_methods.html */ - xSync(fileId: number, flags: number): number | Promise; - - /** @see https://sqlite.org/c3ref/io_methods.html */ - xFileSize(fileId: number, pSize64: number): number | Promise; - - /** @see https://sqlite.org/c3ref/io_methods.html */ - xLock(fileId: number, flags: number): number | Promise; - - /** @see https://sqlite.org/c3ref/io_methods.html */ - xUnlock(fileId: number, flags: number): number | Promise; - - /** @see https://sqlite.org/c3ref/io_methods.html */ - xCheckReservedLock(fileId: number, pResOut: number): number | Promise; - - /** @see https://sqlite.org/c3ref/io_methods.html */ - xFileControl(fileId: number, flags: number, pOut: number): number | Promise; - - /** @see https://sqlite.org/c3ref/io_methods.html */ - xDeviceCharacteristics(fileId: number): number | Promise; - - /** @see https://sqlite.org/c3ref/vfs.html */ - xOpen(pVfs: number, zName: number, pFile: number, flags: number, pOutFlags: number): number | Promise; - - /** @see https://sqlite.org/c3ref/vfs.html */ - xDelete(pVfs: number, zName: number, syncDir: number): number | Promise; - - /** @see https://sqlite.org/c3ref/vfs.html */ - xAccess(pVfs: number, zName: number, flags: number, pResOut: number): number | Promise; -} - -/** - * Options object argument for {@link SQLiteAPI.statements} - */ -declare interface SQLitePrepareOptions { - /** - * Statement handles prepared and yielded by {@link SQLiteAPI.statements} - * are normally valid only within the scope of an iteration. - * Set `unscoped` to `true` to give iterated statements an arbitrary - * lifetime. - */ - unscoped?: boolean; - - /** - * SQLITE_PREPARE_* flags - * @see https://www.sqlite.org/c3ref/c_prepare_normalize.html#sqlitepreparepersistent - */ - flags?: number; -} - -/** - * Javascript wrappers for the SQLite C API (plus a few convenience functions) - * - * Function signatures have been slightly modified to be more - * Javascript-friendly. For the C functions that return an error code, - * the corresponding Javascript wrapper will throw an exception with a - * `code` property on an error. - * - * Note that a few functions return a Promise in order to accommodate - * either a synchronous or asynchronous SQLite build, generally those - * involved with opening/closing a database or executing a statement. - * - * To create an instance of the API, follow these steps: - * - * ```javascript - * // Import an ES6 module factory function from one of the - * // package builds, either 'wa-sqlite.mjs' (synchronous) or - * // 'wa-sqlite-async.mjs' (asynchronous). You should only - * // use the asynchronous build if you plan to use an - * // asynchronous VFS or module. - * import SQLiteESMFactory from 'wa-sqlite/dist/wa-sqlite.mjs'; - * - * // Import the Javascript API wrappers. - * import * as SQLite from 'wa-sqlite'; - * - * // Use an async function to simplify Promise handling. - * (async function() { - * // Invoke the ES6 module factory to create the SQLite - * // Emscripten module. This will fetch and compile the - * // .wasm file. - * const module = await SQLiteESMFactory(); - * - * // Use the module to build the API instance. - * const sqlite3 = SQLite.Factory(module); - * - * // Use the API to open and access a database. - * const db = await sqlite3.open_v2('myDB'); - * ... - * })(); - * ``` - * - * @see https://sqlite.org/c3ref/funclist.html - */ -declare interface SQLiteAPI { - /** - * Bind a collection of values to a statement - * - * This convenience function binds values from either an array or object - * to a prepared statement with placeholder parameters. - * - * Array example using numbered parameters (numbering is implicit in - * this example): - * ``` - * const sql = 'INSERT INTO tbl VALUES (?, ?, ?)'; - * for await (const stmt of sqlite3.statements(db, sql) { - * sqlite3.bind_collection(stmt, [42, 'hello', null]); - * ... - * } - * ``` - * - * Object example using named parameters (':', '@', or '$' prefixes - * are allowed): - * ``` - * const sql = 'INSERT INTO tbl VALUES (?, ?, ?)'; - * for await (const stmt of sqlite3.statements(db, sql) { - * sqlite3.bind_collection(stmt, { - * '@foo': 42, - * '@bar': 'hello', - * '@baz': null, - * }); - * ... - * } - * ``` - * - * Note that SQLite bindings are indexed beginning with 1, but when - * binding values from an array `a` the values begin with `a[0]`. - * @param stmt prepared statement pointer - * @param bindings - * @returns `SQLITE_OK` (throws exception on error) - */ - bind_collection( - stmt: number, - bindings: { [index: string]: SQLiteCompatibleType | null } | Array - ): number; - - /** - * Bind value to prepared statement - * - * This convenience function calls the appropriate `bind_*` function - * based on the type of `value`. Note that binding indices begin with 1. - * @param stmt prepared statement pointer - * @param i binding index - * @param value - * @returns `SQLITE_OK` (throws exception on error) - */ - bind(stmt: number, i: number, value: SQLiteCompatibleType | null): number; - - /** - * Bind blob to prepared statement parameter - * - * Note that binding indices begin with 1. - * @see https://www.sqlite.org/c3ref/bind_blob.html - * @param stmt prepared statement pointer - * @param i binding index - * @param value - * @returns `SQLITE_OK` (throws exception on error) - */ - bind_blob(stmt: number, i: number, value: Uint8Array | Array): number; - - /** - * Bind number to prepared statement parameter - * - * Note that binding indices begin with 1. - * @see https://www.sqlite.org/c3ref/bind_blob.html - * @param stmt prepared statement pointer - * @param i binding index - * @param value - * @returns `SQLITE_OK` (throws exception on error) - */ - bind_double(stmt: number, i: number, value: number): number; - - /** - * Bind number to prepared statement parameter - * - * Note that binding indices begin with 1. - * @see https://www.sqlite.org/c3ref/bind_blob.html - * @param stmt prepared statement pointer - * @param i binding index - * @param value - * @returns `SQLITE_OK` (throws exception on error) - */ - bind_int(stmt: number, i: number, value: number): number; - - /** - * Bind number to prepared statement parameter - * - * Note that binding indices begin with 1. - * @see https://www.sqlite.org/c3ref/bind_blob.html - * @param stmt prepared statement pointer - * @param i binding index - * @param value - * @returns `SQLITE_OK` (throws exception on error) - */ - bind_int64(stmt: number, i: number, value: bigint): number; - - /** - * Bind null to prepared statement - * - * Note that binding indices begin with 1. - * @see https://www.sqlite.org/c3ref/bind_blob.html - * @param stmt prepared statement pointer - * @param i binding index - * @returns `SQLITE_OK` (throws exception on error) - */ - bind_null(stmt: number, i: number): number; - - /** - * Get number of bound parameters - * @see https://www.sqlite.org/c3ref/bind_parameter_count.html - * @param stmt prepared statement pointer - * @returns number of statement binding locations - */ - bind_parameter_count(stmt: number): number; - - /** - * Get name of bound parameter - * - * Note that binding indices begin with 1. - * @see https://www.sqlite.org/c3ref/bind_parameter_name.html - * @param stmt prepared statement pointer - * @param i binding index - * @returns binding name - */ - bind_parameter_name(stmt: number, i: number): string; - - /** - * Bind string to prepared statement - * - * Note that binding indices begin with 1. - * @see https://www.sqlite.org/c3ref/bind_blob.html - * @param stmt prepared statement pointer - * @param i binding index - * @param value - * @returns `SQLITE_OK` (throws exception on error) - */ - bind_text(stmt: number, i: number, value: string): number; - - /** - * Get count of rows modified by last insert/update - * @see https://www.sqlite.org/c3ref/changes.html - * @param db database pointer - * @returns number of rows modified - */ - changes(db): number; - - /** - * Reset all bindings on a prepared statement. - * @see https://www.sqlite.org/c3ref/clear_bindings.html - * @param stmt prepared statement pointer - * @returns `SQLITE_OK` (throws exception on error) - */ - clear_bindings(stmt: number): number; - - /** - * Close database connection - * @see https://www.sqlite.org/c3ref/close.html - * @param db database pointer - * @returns `SQLITE_OK` (throws exception on error) - */ - close(db): Promise; - - /** - * Call the appropriate `column_*` function based on the column type - * - * The type is determined by calling {@link column_type}, which may - * not match the type declared in `CREATE TABLE`. Note that if the column - * value is a blob then as with `column_blob` the result may be invalid - * after the next SQLite call; copy if it needs to be retained. - * - * Integer values are returned as Number if within the min/max safe - * integer bounds, otherwise they are returned as BigInt. - * @param stmt prepared statement pointer - * @param i column index - * @returns column value - */ - column(stmt: number, i: number): SQLiteCompatibleType; - - /** - * Extract a column value from a row after a prepared statement {@link step} - * - * The contents of the returned buffer may be invalid after the - * next SQLite call. Make a copy of the data (e.g. with `.slice()`) - * if longer retention is required. - * @see https://www.sqlite.org/c3ref/column_blob.html - * @param stmt prepared statement pointer - * @param i column index - * @returns column value - */ - column_blob(stmt: number, i: number): Uint8Array; - - /** - * Get storage size for column text or blob - * @see https://www.sqlite.org/c3ref/column_blob.html - * @param stmt prepared statement pointer - * @param i column index - * @returns number of bytes in column text or blob - */ - column_bytes(stmt: number, i: number): number; - - /** - * Get number of columns for a prepared statement - * @see https://www.sqlite.org/c3ref/column_blob.html - * @param stmt prepared statement pointer - * @returns number of columns - */ - column_count(stmt: number): number; - - /** - * Extract a column value from a row after a prepared statement {@link step} - * @see https://www.sqlite.org/c3ref/column_blob.html - * @param stmt prepared statement pointer - * @param i column index - * @returns column value - */ - column_double(stmt: number, i: number): number; - - /** - * Extract a column value from a row after a prepared statement {@link step} - * @see https://www.sqlite.org/c3ref/column_blob.html - * @param stmt prepared statement pointer - * @param i column index - * @returns column value - */ - column_int(stmt: number, i: number): number; - - /** - * Extract a column value from a row after a prepared statement {@link step} - * @see https://www.sqlite.org/c3ref/column_blob.html - * @param stmt prepared statement pointer - * @param i column index - * @returns column value - */ - column_int64(stmt: number, i: number): bigint; - - /** - * Get a column name for a prepared statement - * @see https://www.sqlite.org/c3ref/column_blob.html - * @param stmt prepared statement pointer - * @param i column index - * @returns column name - */ - column_name(stmt: number, i: number): string; - - /** - * Get names for all columns of a prepared statement - * - * This is a convenience function that calls {@link column_count} and - * {@link column_name}. - * @param stmt - * @returns array of column names - */ - column_names(stmt: number): Array; - - /** - * Extract a column value from a row after a prepared statement {@link step} - * @see https://www.sqlite.org/c3ref/column_blob.html - * @param stmt prepared statement pointer - * @param i column index - * @returns column value - */ - column_text(stmt: number, i: number): string; - - /** - * Get column type for a prepared statement - * - * Note that this type may not match the type declared in `CREATE TABLE`. - * @see https://www.sqlite.org/c3ref/column_blob.html - * @param stmt prepared statement pointer - * @param i column index - * @returns enumeration value for type - */ - column_type(stmt: number, i: number): number; - - /** - * Create or redefine SQL functions - * - * The application data passed is ignored. Use closures instead. - * - * If any callback function returns a Promise, that function must - * be declared `async`, i.e. it must allow use of `await`. - * @see https://sqlite.org/c3ref/create_function.html - * @param db database pointer - * @param zFunctionName - * @param nArg number of function arguments - * @param eTextRep text encoding (and other flags) - * @param pApp application data (ignored) - * @param xFunc - * @param xStep - * @param xFinal - * @returns `SQLITE_OK` (throws exception on error) - */ - create_function( - db: number, - zFunctionName: string, - nArg: number, - eTextRep: number, - pApp: number, - xFunc?: (context: number, values: Uint32Array) => void | Promise, - xStep?: (context: number, values: Uint32Array) => void | Promise, - xFinal?: (context: number) => void | Promise - ): number; - - /** - * Get number of columns in current row of a prepared statement - * @see https://www.sqlite.org/c3ref/data_count.html - * @param stmt prepared statement pointer - * @returns number of columns - */ - data_count(stmt: number): number; - - /** - * One-step query execution interface - * - * The implementation of this function uses {@link row}, which makes a - * copy of blobs and returns BigInt for integers outside the safe integer - * bounds for Number. - * @see https://www.sqlite.org/c3ref/exec.html - * @param db database pointer - * @param zSQL queries - * @param callback called for each output row - * @returns Promise resolving to `SQLITE_OK` (rejects on error) - */ - exec( - db: number, - zSQL: string, - callback?: (row: Array, columns: string[]) => void - ): Promise; - - /** - * Destroy a prepared statement object compiled by {@link statements} - * with the `unscoped` option set to `true` - * - * This function does *not* throw on error. - * @see https://www.sqlite.org/c3ref/finalize.html - * @param stmt prepared statement pointer - * @returns Promise resolving to `SQLITE_OK` or error status - */ - finalize(stmt: number): Promise; - - /** - * Test for autocommit mode - * @see https://sqlite.org/c3ref/get_autocommit.html - * @param db database pointer - * @returns Non-zero if autocommit mode is on, zero otherwise - */ - get_autocommit(db: number): number; - - /** - * Get SQLite library version - * @see https://www.sqlite.org/c3ref/libversion.html - * @returns version string, e.g. '3.35.5' - */ - libversion(): string; - - /** - * Get SQLite library version - * @see https://www.sqlite.org/c3ref/libversion.html - * @returns version number, e.g. 3035005 - */ - libversion_number(): number; - - /** - * Set a usage limit on a connection. - * @see https://www.sqlite.org/c3ref/limit.html - * @param db database pointer - * @param id limit category - * @param newVal - * @returns previous setting - */ - limit(db: number, id: number, newVal: number): number; - - /** - * Opening a new database connection. - * - * Note that this function differs from the C API in that it - * returns the Promise-wrapped database pointer (instead of a - * result code). - * @see https://sqlite.org/c3ref/open.html - * @param zFilename - * @param iFlags `SQLite.SQLITE_OPEN_CREATE | SQLite.SQLITE_OPEN_READWRITE` (0x6) if omitted - * @param zVfs VFS name - * @returns Promise-wrapped database pointer. - */ - open_v2(zFilename: string, iFlags?: number, zVfs?: string): Promise; - - /** - * Specify callback to be invoked between long-running queries - * - * The application data passed is ignored. Use closures instead. - * - * If any callback function returns a Promise, that function must - * be declared `async`, i.e. it must allow use of `await`. - * @param db database pointer - * @param nProgressOps target number of database operations between handler invocations - * @param handler - * @param userData - */ - progress_handler(db: number, nProgressOps: number, handler: (userData: any) => number | Promise, userData); - - /** - * Reset a prepared statement object - * @see https://www.sqlite.org/c3ref/reset.html - * @param stmt prepared statement pointer - * @returns Promise-wrapped `SQLITE_OK` (rejects on error) - */ - reset(stmt: number): Promise; - - /** - * Convenience function to call `result_*` based of the type of `value` - * @param context context pointer - * @param value - */ - result(context: number, value: (SQLiteCompatibleType | number[]) | null): void; - - /** - * Set the result of a function or vtable column - * @see https://sqlite.org/c3ref/result_blob.html - * @param context context pointer - * @param value - */ - result_blob(context: number, value: Uint8Array | number[]): void; - - /** - * Set the result of a function or vtable column - * @see https://sqlite.org/c3ref/result_blob.html - * @param context context pointer - * @param value - */ - result_double(context: number, value: number): void; - - /** - * Set the result of a function or vtable column - * @see https://sqlite.org/c3ref/result_blob.html - * @param context context pointer - * @param value - */ - result_int(context: number, value: number): void; - - /** - * Set the result of a function or vtable column - * @see https://sqlite.org/c3ref/result_blob.html - * @param context context pointer - * @param value - */ - result_int64(context: number, value: bigint): void; - - /** - * Set the result of a function or vtable column - * @see https://sqlite.org/c3ref/result_blob.html - * @param context context pointer - */ - result_null(context: number): void; - - /** - * Set the result of a function or vtable column - * @see https://sqlite.org/c3ref/result_blob.html - * @param context context pointer - * @param value - */ - result_text(context: number, value: string): void; - - /** - * Get all column data for a row from a prepared statement step - * - * This convenience function will return a copy of any blob, unlike - * {@link column_blob} which returns a value referencing volatile WASM - * memory with short validity. Like {@link column}, it will return a - * BigInt for integers outside the safe integer bounds for Number. - * @param stmt prepared statement pointer - * @returns row data - */ - row(stmt: number): Array; - - /** - * Register a callback function that is invoked to authorize certain SQL statement actions. - * @see https://www.sqlite.org/c3ref/set_authorizer.html - * @param db database pointer - * @param authFunction - * @param userData - */ - set_authorizer( - db: number, - authFunction: ( - userData: any, - iActionCode: number, - param3: string | null, - param4: string | null, - param5: string | null, - param6: string | null - ) => number | Promise, - userData: any - ): number; - - /** - * Get statement SQL - * @see https://www.sqlite.org/c3ref/expanded_sql.html - * @param stmt prepared statement pointer - * @returns SQL - */ - sql(stmt: number): string; - - /** - * SQL statement iterator - * - * This function manages statement compilation by creating an async - * iterator that yields a prepared statement handle on each iteration. - * It is typically used with a `for await` loop (in an async function), - * like this: - * ```javascript - * // Compile one statement on each iteration of this loop. - * for await (const stmt of sqlite3.statements(db, sql)) { - * // Bind parameters here if using SQLite placeholders. - * - * // Execute the statement with this loop. - * while (await sqlite3.step(stmt) === SQLite.SQLITE_ROW) { - * // Collect row data here. - * } - * - * // Change bindings, reset, and execute again if desired. - * } - * ``` - * - * By default, the lifetime of a yielded prepared statement is managed - * automatically by the iterator, ending at the end of each iteration. - * {@link finalize} should *not* be called on a statement provided by - * the iterator unless the `unscoped` option is set to `true` (that - * option is provided for applications that wish to manage statement - * lifetimes manually). - * - * If using the iterator manually, i.e. by calling its `next` - * method, be sure to call the `return` method if iteration - * is abandoned before completion (`for await` and other implicit - * traversals provided by Javascript do this automatically) - * to ensure that all allocated resources are released. - * @see https://www.sqlite.org/c3ref/prepare.html - * @param db database pointer - * @param sql - * @param options - */ - statements(db: number, sql: string, options?: SQLitePrepareOptions): AsyncIterable; - - /** - * Evaluate an SQL statement - * @see https://www.sqlite.org/c3ref/step.html - * @param stmt prepared statement pointer - * @returns Promise resolving to `SQLITE_ROW` or `SQLITE_DONE` - * (rejects on error) - */ - step(stmt: number): Promise; - - /** - * Register an update hook - * - * The callback is invoked whenever a row is updated, inserted, or deleted - * in a rowid table on this connection. - * @see https://www.sqlite.org/c3ref/update_hook.html - * - * updateType is one of: - * - SQLITE_DELETE: 9 - * - SQLITE_INSERT: 18 - * - SQLITE_UPDATE: 23 - * @see https://www.sqlite.org/c3ref/c_alter_table.html - * - * @param db database pointer - * @param callback - */ - update_hook( - db: number, - callback: (updateType: number, dbName: string | null, tblName: string | null, rowid: bigint) => void - ): void; - - /** - * Extract a value from `sqlite3_value` - * - * This is a convenience function that calls the appropriate `value_*` - * function based on its type. Note that if the value is a blob then as - * with `value_blob` the result may be invalid after the next SQLite call. - * - * Integer values are returned as Number if within the min/max safe - * integer bounds, otherwise they are returned as BigInt. - * @param pValue `sqlite3_value` pointer - * @returns value - */ - value(pValue: number): SQLiteCompatibleType; - - /** - * Extract a value from `sqlite3_value` - * - * The contents of the returned buffer may be invalid after the - * next SQLite call. Make a copy of the data (e.g. with `.slice()`) - * if longer retention is required. - * @see https://sqlite.org/c3ref/value_blob.html - * @param pValue `sqlite3_value` pointer - * @returns value - */ - value_blob(pValue: number): Uint8Array; - - /** - * Get blob or text size for value - * @see https://sqlite.org/c3ref/value_blob.html - * @param pValue `sqlite3_value` pointer - * @returns size - */ - value_bytes(pValue: number): number; - - /** - * Extract a value from `sqlite3_value` - * @see https://sqlite.org/c3ref/value_blob.html - * @param pValue `sqlite3_value` pointer - * @returns value - */ - value_double(pValue: number): number; - - /** - * Extract a value from `sqlite3_value` - * @see https://sqlite.org/c3ref/value_blob.html - * @param pValue `sqlite3_value` pointer - * @returns value - */ - value_int(pValue: number): number; - - /** - * Extract a value from `sqlite3_value` - * @see https://sqlite.org/c3ref/value_blob.html - * @param pValue `sqlite3_value` pointer - * @returns value - */ - value_int64(pValue: number): bigint; - - /** - * Extract a value from `sqlite3_value` - * @see https://sqlite.org/c3ref/value_blob.html - * @param pValue `sqlite3_value` pointer - * @returns value - */ - value_text(pValue: number): string; - - /** - * Get type of `sqlite3_value` - * @see https://sqlite.org/c3ref/value_blob.html - * @param pValue `sqlite3_value` pointer - * @returns enumeration value for type - */ - value_type(pValue: number): number; - - /** - * Register a new Virtual File System. - * - * @see https://www.sqlite.org/c3ref/vfs_find.html - * @param vfs VFS object - * @param makeDefault - * @returns `SQLITE_OK` (throws exception on error) - */ - 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; - export const SQLITE_PREPARE_PERSISTENT: 0x01; - export const SQLITE_PREPARE_NORMALIZED: 0x02; - export const SQLITE_PREPARE_NO_VTAB: 0x04; -} - -declare module "wa-sqlite" { - export * from "wa-sqlite/src/sqlite-constants.js"; - - /** - * @ignore - * 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; - export = ModuleFactory; -} - -/** @ignore */ -declare module "wa-sqlite/dist/wa-sqlite-async.mjs" { - function ModuleFactory(config?: object): Promise; - 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} - */ - 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} - */ - 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 overridden on - * registration by an Asyncify build. - * @param {function(): Promise} f - * @returns {number} - */ - handleAsync(f: () => 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; - cacheSize: number; - db: any; - close(): Promise; - /** - * Delete a file from IndexedDB. - * @param {string} name - */ - deleteFile(name: string): Promise; - /** - * Forcibly clear an orphaned file lock. - * @param {string} name - */ - forceClearLock(name: string): Promise; - _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; - _putBlock(store: any, file: any, index: any, blockData: any): void; - _purgeCache(store: any, file: any, size?: number): void; - _flushCache(store: any, file: any): Promise; - _sync(file: any): Promise; - /** - * 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; - } -} - -/** @ignore */ -declare module "wa-sqlite/src/examples/MemoryVFS.js" { - import * as VFS from "wa-sqlite/src/VFS.js"; - /** @ignore */ - export class MemoryVFS extends VFS.Base { - name: string; - mapNameToFile: Map; - mapIdToFile: Map; - } -} - -/** @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" { - /** - * @ignore - * 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} - */ - export function tag(sqlite3: any, db: number): (arg0: TemplateStringsArray, ...args: any[]) => Promise; -} diff --git a/apps/web/core/local-db/worker/wa-sqlite/src/wa-sqlite.mjs b/apps/web/core/local-db/worker/wa-sqlite/src/wa-sqlite.mjs deleted file mode 100644 index 7ba5e77d46..0000000000 --- a/apps/web/core/local-db/worker/wa-sqlite/src/wa-sqlite.mjs +++ /dev/null @@ -1,16 +0,0 @@ - -var Module = (() => { - var _scriptName = import.meta.url; - - return ( -function(moduleArg = {}) { - var moduleRtn; - -var Module=moduleArg;var readyPromiseResolve,readyPromiseReject;var readyPromise=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptName){scriptDirectory=_scriptName}if(scriptDirectory.startsWith("blob:")){scriptDirectory=""}else{scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}{if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=url=>fetch(url,{credentials:"same-origin"}).then(response=>{if(response.ok){return response.arrayBuffer()}return Promise.reject(new Error(response.status+" : "+response.url))})}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];var wasmBinary=Module["wasmBinary"];var wasmMemory;var ABORT=false;var EXITSTATUS;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b)}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.initialized)FS.init();FS.ignorePermissions=false;TTY.init();callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;Module["monitorRunDependencies"]?.(runDependencies)}function removeRunDependency(id){runDependencies--;Module["monitorRunDependencies"]?.(runDependencies);if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix="data:application/octet-stream;base64,";var isDataURI=filename=>filename.startsWith(dataURIPrefix);function findWasmBinary(){if(Module["locateFile"]){var f="wa-sqlite.wasm";if(!isDataURI(f)){return locateFile(f)}return f}return new URL("wa-sqlite.wasm",import.meta.url).href}var wasmBinaryFile;function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}function getBinaryPromise(binaryFile){if(!wasmBinary){return readAsync(binaryFile).then(response=>new Uint8Array(response),()=>getBinarySync(binaryFile))}return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,function(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)})})}return instantiateArrayBuffer(binaryFile,imports,callback)}function getWasmImports(){return{a:wasmImports}}function createWasm(){var info=getWasmImports();function receiveInstance(instance,module){wasmExports=instance.exports;wasmMemory=wasmExports["pa"];updateMemoryViews();wasmTable=wasmExports["hf"];addOnInit(wasmExports["qa"]);removeRunDependency("wasm-instantiate");return wasmExports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);readyPromiseReject(e)}}if(!wasmBinaryFile)wasmBinaryFile=findWasmBinary();instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return{}}var tempDouble;var tempI64;function ExitStatus(status){this.name="ExitStatus";this.message=`Program terminated with exit(${status})`;this.status=status}var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};function getValue(ptr,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":return HEAP8[ptr];case"i8":return HEAP8[ptr];case"i16":return HEAP16[ptr>>1];case"i32":return HEAP32[ptr>>2];case"i64":abort("to do getValue(i64) use WASM_BIGINT");case"float":return HEAPF32[ptr>>2];case"double":return HEAPF64[ptr>>3];case"*":return HEAPU32[ptr>>2];default:abort(`invalid type for getValue: ${type}`)}}var noExitRuntime=Module["noExitRuntime"]||true;function setValue(ptr,value,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":HEAP8[ptr]=value;break;case"i8":HEAP8[ptr]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":abort("to do setValue(i64) use WASM_BIGINT");case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;case"*":HEAPU32[ptr>>2]=value;break;default:abort(`invalid type for setValue: ${type}`)}}var stackRestore=val=>__emscripten_stack_restore(val);var stackSave=()=>_emscripten_stack_get_current();var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder:undefined;var UTF8ArrayToString=(heapOrArray,idx,maxBytesToRead)=>{var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var UTF8ToString=(ptr,maxBytesToRead)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):"";var ___assert_fail=(condition,filename,line,func)=>{abort(`Assertion failed: ${UTF8ToString(condition)}, at: `+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"])};var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:path=>{if(path==="/")return"/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:(...paths)=>PATH.normalize(paths.join("/")),join2:(l,r)=>PATH.normalize(l+"/"+r)};var initRandomFill=()=>{if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){return view=>crypto.getRandomValues(view)}else abort("initRandomDevice")};var randomFill=view=>(randomFill=initRandomFill())(view);var PATH_FS={resolve:(...args)=>{var resolvedPath="",resolvedAbsolute=false;for(var i=args.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?args[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path)}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx};function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var FS_stdin_getChar=()=>{if(!FS_stdin_getChar_buffer.length){var result=null;if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else{}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true)}return FS_stdin_getChar_buffer.shift()};var TTY={ttys:[],init(){},shutdown(){},register(dev,ops){TTY.ttys[dev]={input:[],output:[],ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close(stream){stream.tty.ops.fsync(stream.tty)},fsync(stream){stream.tty.ops.fsync(stream.tty)},read(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}},ioctl_tcgets(tty){return{c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(tty,optional_actions,data){return 0},ioctl_tiocgwinsz(tty){return[24,80]}},default_tty1_ops:{put_char(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};var zeroMemory=(address,size)=>{HEAPU8.fill(0,address,address+size);return address};var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var mmapAlloc=size=>{size=alignMemory(size,65536);var ptr=_emscripten_builtin_memalign(65536,size);if(!ptr)return 0;return zeroMemory(ptr,size)};var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}MEMFS.ops_table||={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}};var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp}return node},getFileDataAsTypedArray(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.timestamp);attr.mtime=new Date(node.timestamp);attr.ctime=new Date(node.timestamp);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){if(attr.mode!==undefined){node.mode=attr.mode}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup(parent,name){throw FS.genericErrors[44]},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){if(FS.isDir(old_node.mode)){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp},unlink(parent,name){delete parent.contents[name];parent.timestamp=Date.now()},rmdir(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.timestamp=Date.now()},readdir(node){var entries=[".",".."];for(var key of Object.keys(node.contents)){entries.push(key)}return entries},symlink(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length{var dep=!noRunDep?getUniqueRunDependency(`al ${url}`):"";readAsync(url).then(arrayBuffer=>{onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)},err=>{if(onerror){onerror()}else{throw`Loading data file "${url}" failed.`}});if(dep)addRunDependency(dep)};var FS_createDataFile=(parent,name,fileData,canRead,canWrite,canOwn)=>{FS.createDataFile(parent,name,fileData,canRead,canWrite,canOwn)};var preloadPlugins=Module["preloadPlugins"]||[];var FS_handledByPreloadPlugin=(byteArray,fullname,finish,onerror)=>{if(typeof Browser!="undefined")Browser.init();var handled=false;preloadPlugins.forEach(plugin=>{if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true}});return handled};var FS_createPreloadedFile=(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(`cp ${fullname}`);function processData(byteArray){function finish(byteArray){preFinish?.();if(!dontCreateFile){FS_createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}onload?.();removeRunDependency(dep)}if(FS_handledByPreloadPlugin(byteArray,fullname,finish,()=>{onerror?.();removeRunDependency(dep)})){return}finish(byteArray)}addRunDependency(dep);if(typeof url=="string"){asyncLoad(url,processData,onerror)}else{processData(url)}};var FS_modeStringToFlags=str=>{var flagModes={r:0,"r+":2,w:512|64|1,"w+":512|64|2,a:1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags};var FS_getMode=(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode};var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:class{constructor(errno){this.name="ErrnoError";this.errno=errno}},genericErrors:{},filesystems:null,syncFSRequests:0,FSStream:class{constructor(){this.shared={}}get object(){return this.node}set object(val){this.node=val}get isRead(){return(this.flags&2097155)!==1}get isWrite(){return(this.flags&2097155)!==0}get isAppend(){return this.flags&1024}get flags(){return this.shared.flags}set flags(val){this.shared.flags=val}get position(){return this.shared.position}set position(val){this.shared.position=val}},FSNode:class{constructor(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.mounted=null;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.node_ops={};this.stream_ops={};this.rdev=rdev;this.readMode=292|73;this.writeMode=146}get read(){return(this.mode&this.readMode)===this.readMode}set read(val){val?this.mode|=this.readMode:this.mode&=~this.readMode}get write(){return(this.mode&this.writeMode)===this.writeMode}set write(val){val?this.mode|=this.writeMode:this.mode&=~this.writeMode}get isFolder(){return FS.isDir(this.mode)}get isDevice(){return FS.isChrdev(this.mode)}},lookupPath(path,opts={}){path=PATH_FS.resolve(path);if(!path)return{path:"",node:null};var defaults={follow_mount:true,recurse_count:0};opts=Object.assign(defaults,opts);if(opts.recurse_count>8){throw new FS.ErrnoError(32)}var parts=path.split("/").filter(p=>!!p);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath(node){var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?`${mount}/${path}`:mount+path}path=path?`${node.name}/${path}`:node.name;node=node.parent}},hashName(parentid,name){var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode(node){FS.hashRemoveNode(node)},isRoot(node){return node===node.parent},isMountpoint(node){return!!node.mounted},isFile(mode){return(mode&61440)===32768},isDir(mode){return(mode&61440)===16384},isLink(mode){return(mode&61440)===40960},isChrdev(mode){return(mode&61440)===8192},isBlkdev(mode){return(mode&61440)===24576},isFIFO(mode){return(mode&61440)===4096},isSocket(mode){return(mode&49152)===49152},flagsToPermissionString(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions(node,perms){if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup(dir){if(!FS.isDir(dir.mode))return 54;var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd(){for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStreamChecked(fd){var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}return stream},getStream:fd=>FS.streams[fd],createStream(stream,fd=-1){stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd()}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream(fd){FS.streams[fd]=null},dupStream(origStream,fd=-1){var stream=FS.createStream(origStream,fd);stream.stream_ops?.dup?.(stream);return stream},chrdev_stream_ops:{open(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;stream.stream_ops.open?.(stream)},llseek(){throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push(...m.mounts)}return mounts},syncfs(populate,callback){if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`)}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type,opts,mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup(parent,name){return parent.node_ops.lookup(parent,name)},mknod(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree(path,mode){var dirs=path.split("/");var d="";for(var i=0;iFS.currentPath,chdir(path){var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories(){FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices(){FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomLeft=randomFill(randomBuffer).byteLength}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories(){FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount(){var node=FS.createNode(proc_self,"fd",16384|511,73);node.node_ops={lookup(parent,name){var fd=+name;var stream=FS.getStreamChecked(fd);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path}};ret.parent=ret;return ret}};return node}},{},"/proc/self/fd")},createStandardStreams(input,output,error){if(input){FS.createDevice("/dev","stdin",input)}else{FS.symlink("/dev/tty","/dev/stdin")}if(output){FS.createDevice("/dev","stdout",null,output)}else{FS.symlink("/dev/tty","/dev/stdout")}if(error){FS.createDevice("/dev","stderr",null,error)}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},staticInit(){[44].forEach(code=>{FS.genericErrors[code]=new FS.ErrnoError(code);FS.genericErrors[code].stack=""});FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={MEMFS}},init(input,output,error){FS.initialized=true;input??=Module["stdin"];output??=Module["stdout"];error??=Module["stderr"];FS.createStandardStreams(input,output,error)},quit(){FS.initialized=false;for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]}setDataGetter(getter){this.getter=getter}cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true}get length(){if(!this.lengthKnown){this.cacheLength()}return this._length}get chunkSize(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=(...args)=>{FS.forceLoadFile(node);return fn(...args)}});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return{ptr,allocated:true}};node.stream_ops=stream_ops;return node}};var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return PATH.join2(dir,path)},doStat(func,path,buf){var stat=func(path);HEAP32[buf>>2]=stat.dev;HEAP32[buf+4>>2]=stat.mode;HEAPU32[buf+8>>2]=stat.nlink;HEAP32[buf+12>>2]=stat.uid;HEAP32[buf+16>>2]=stat.gid;HEAP32[buf+20>>2]=stat.rdev;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+24>>2]=tempI64[0],HEAP32[buf+28>>2]=tempI64[1];HEAP32[buf+32>>2]=4096;HEAP32[buf+36>>2]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();tempI64=[Math.floor(atime/1e3)>>>0,(tempDouble=Math.floor(atime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>2]=tempI64[0],HEAP32[buf+44>>2]=tempI64[1];HEAPU32[buf+48>>2]=atime%1e3*1e3*1e3;tempI64=[Math.floor(mtime/1e3)>>>0,(tempDouble=Math.floor(mtime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+56>>2]=tempI64[0],HEAP32[buf+60>>2]=tempI64[1];HEAPU32[buf+64>>2]=mtime%1e3*1e3*1e3;tempI64=[Math.floor(ctime/1e3)>>>0,(tempDouble=Math.floor(ctime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+72>>2]=tempI64[0],HEAP32[buf+76>>2]=tempI64[1];HEAPU32[buf+80>>2]=ctime%1e3*1e3*1e3;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+88>>2]=tempI64[0],HEAP32[buf+92>>2]=tempI64[1];return 0},doMsync(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},getStreamFromFD(fd){var stream=FS.getStreamChecked(fd);return stream},varargs:undefined,getStr(ptr){var ret=UTF8ToString(ptr);return ret}};function ___syscall_chmod(path,mode){try{path=SYSCALLS.getStr(path);FS.chmod(path,mode);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_faccessat(dirfd,path,amode,flags){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(amode&~7){return-28}var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node){return-44}var perms="";if(amode&4)perms+="r";if(amode&2)perms+="w";if(amode&1)perms+="x";if(perms&&FS.nodePermissions(node,perms)){return-2}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_fchmod(fd,mode){try{FS.fchmod(fd,mode);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_fchown32(fd,owner,group){try{FS.fchown(fd,owner,group);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function syscallGetVarargI(){var ret=HEAP32[+SYSCALLS.varargs>>2];SYSCALLS.varargs+=4;return ret}var syscallGetVarargP=syscallGetVarargI;function ___syscall_fcntl64(fd,cmd,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=syscallGetVarargI();if(arg<0){return-28}while(FS.streams[arg]){arg++}var newStream;newStream=FS.dupStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=syscallGetVarargI();stream.flags|=arg;return 0}case 12:{var arg=syscallGetVarargP();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 13:case 14:return 0}return-28}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_fstat64(fd,buf){try{var stream=SYSCALLS.getStreamFromFD(fd);return SYSCALLS.doStat(FS.stat,stream.path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var convertI32PairToI53Checked=(lo,hi)=>hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN;function ___syscall_ftruncate64(fd,length_low,length_high){var length=convertI32PairToI53Checked(length_low,length_high);try{if(isNaN(length))return 61;FS.ftruncate(fd,length);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);function ___syscall_getcwd(buf,size){try{if(size===0)return-28;var cwd=FS.cwd();var cwdLengthInBytes=lengthBytesUTF8(cwd)+1;if(sizeHEAPU32[ptr>>2]+HEAP32[ptr+4>>2]*4294967296;function ___syscall_utimensat(dirfd,path,times,flags){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path,true);var now=Date.now(),atime,mtime;if(!times){atime=now;mtime=now}else{var seconds=readI53FromI64(times);var nanoseconds=HEAP32[times+8>>2];if(nanoseconds==1073741823){atime=now}else if(nanoseconds==1073741822){atime=-1}else{atime=seconds*1e3+nanoseconds/(1e3*1e3)}times+=16;seconds=readI53FromI64(times);nanoseconds=HEAP32[times+8>>2];if(nanoseconds==1073741823){mtime=now}else if(nanoseconds==1073741822){mtime=-1}else{mtime=seconds*1e3+nanoseconds/(1e3*1e3)}}if(mtime!=-1||atime!=-1){FS.utime(path,atime,mtime)}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var __abort_js=()=>{abort("")};var __emscripten_runtime_keepalive_clear=()=>{noExitRuntime=false;runtimeKeepaliveCounter=0};var isLeapYear=year=>year%4===0&&(year%100!==0||year%400===0);var MONTH_DAYS_LEAP_CUMULATIVE=[0,31,60,91,121,152,182,213,244,274,305,335];var MONTH_DAYS_REGULAR_CUMULATIVE=[0,31,59,90,120,151,181,212,243,273,304,334];var ydayFromDate=date=>{var leap=isLeapYear(date.getFullYear());var monthDaysCumulative=leap?MONTH_DAYS_LEAP_CUMULATIVE:MONTH_DAYS_REGULAR_CUMULATIVE;var yday=monthDaysCumulative[date.getMonth()]+date.getDate()-1;return yday};function __localtime_js(time_low,time_high,tmPtr){var time=convertI32PairToI53Checked(time_low,time_high);var date=new Date(time*1e3);HEAP32[tmPtr>>2]=date.getSeconds();HEAP32[tmPtr+4>>2]=date.getMinutes();HEAP32[tmPtr+8>>2]=date.getHours();HEAP32[tmPtr+12>>2]=date.getDate();HEAP32[tmPtr+16>>2]=date.getMonth();HEAP32[tmPtr+20>>2]=date.getFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>2]=yday;HEAP32[tmPtr+36>>2]=-(date.getTimezoneOffset()*60);var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dst=(summerOffset!=winterOffset&&date.getTimezoneOffset()==Math.min(winterOffset,summerOffset))|0;HEAP32[tmPtr+32>>2]=dst}function __mmap_js(len,prot,flags,fd,offset_low,offset_high,allocated,addr){var offset=convertI32PairToI53Checked(offset_low,offset_high);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);var res=FS.mmap(stream,len,offset,prot,flags);var ptr=res.ptr;HEAP32[allocated>>2]=res.allocated;HEAPU32[addr>>2]=ptr;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function __munmap_js(addr,len,prot,flags,fd,offset_low,offset_high){var offset=convertI32PairToI53Checked(offset_low,offset_high);try{var stream=SYSCALLS.getStreamFromFD(fd);if(prot&2){SYSCALLS.doMsync(addr,stream,len,flags,offset)}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var timers={};var handleException=e=>{if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e)};var runtimeKeepaliveCounter=0;var keepRuntimeAlive=()=>noExitRuntime||runtimeKeepaliveCounter>0;var _proc_exit=code=>{EXITSTATUS=code;if(!keepRuntimeAlive()){Module["onExit"]?.(code);ABORT=true}quit_(code,new ExitStatus(code))};var exitJS=(status,implicit)=>{EXITSTATUS=status;_proc_exit(status)};var _exit=exitJS;var maybeExit=()=>{if(!keepRuntimeAlive()){try{_exit(EXITSTATUS)}catch(e){handleException(e)}}};var callUserCallback=func=>{if(ABORT){return}try{func();maybeExit()}catch(e){handleException(e)}};var _emscripten_get_now;_emscripten_get_now=()=>performance.now();var __setitimer_js=(which,timeout_ms)=>{if(timers[which]){clearTimeout(timers[which].id);delete timers[which]}if(!timeout_ms)return 0;var id=setTimeout(()=>{delete timers[which];callUserCallback(()=>__emscripten_timeout(which,_emscripten_get_now()))},timeout_ms);timers[which]={id,timeout_ms};return 0};var __tzset_js=(timezone,daylight,std_name,dst_name)=>{var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);var winterOffset=winter.getTimezoneOffset();var summerOffset=summer.getTimezoneOffset();var stdTimezoneOffset=Math.max(winterOffset,summerOffset);HEAPU32[timezone>>2]=stdTimezoneOffset*60;HEAP32[daylight>>2]=Number(winterOffset!=summerOffset);var extractZone=timezoneOffset=>{var sign=timezoneOffset>=0?"-":"+";var absOffset=Math.abs(timezoneOffset);var hours=String(Math.floor(absOffset/60)).padStart(2,"0");var minutes=String(absOffset%60).padStart(2,"0");return`UTC${sign}${hours}${minutes}`};var winterName=extractZone(winterOffset);var summerName=extractZone(summerOffset);if(summerOffsetDate.now();var getHeapMax=()=>2147483648;var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var ENV={};var getExecutableName=()=>thisProgram||"./this.program";var getEnvStrings=()=>{if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:lang,_:getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`)}getEnvStrings.strings=strings}return getEnvStrings.strings};var stringToAscii=(str,buffer)=>{for(var i=0;i{var bufSize=0;getEnvStrings().forEach((string,i)=>{var ptr=environ_buf+bufSize;HEAPU32[__environ+i*4>>2]=ptr;stringToAscii(string,ptr);bufSize+=string.length+1});return 0};var _environ_sizes_get=(penviron_count,penviron_buf_size)=>{var strings=getEnvStrings();HEAPU32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(string=>bufSize+=string.length+1);HEAPU32[penviron_buf_size>>2]=bufSize;return 0};function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_fdstat_get(fd,pbuf){try{var rightsBase=0;var rightsInheriting=0;var flags=0;{var stream=SYSCALLS.getStreamFromFD(fd);var type=stream.tty?2:FS.isDir(stream.mode)?3:FS.isLink(stream.mode)?7:4}HEAP8[pbuf]=type;HEAP16[pbuf+2>>1]=flags;tempI64=[rightsBase>>>0,(tempDouble=rightsBase,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[pbuf+8>>2]=tempI64[0],HEAP32[pbuf+12>>2]=tempI64[1];tempI64=[rightsInheriting>>>0,(tempDouble=rightsInheriting,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[pbuf+16>>2]=tempI64[0],HEAP32[pbuf+20>>2]=tempI64[1];return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){var offset=convertI32PairToI53Checked(offset_low,offset_high);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>2]=tempI64[0],HEAP32[newOffset+4>>2]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_sync(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);if(stream.stream_ops?.fsync){return stream.stream_ops.fsync(stream)}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doWritev=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var adapters_support=function(){const handleAsync=typeof Asyncify==="object"?Asyncify.handleAsync.bind(Asyncify):null;Module["handleAsync"]=handleAsync;const targets=new Map;Module["setCallback"]=(key,target)=>targets.set(key,target);Module["getCallback"]=key=>targets.get(key);Module["deleteCallback"]=key=>targets.delete(key);adapters_support=function(isAsync,key,...args){const receiver=targets.get(key);let methodName=null;const f=typeof receiver==="function"?receiver:receiver[methodName=UTF8ToString(args.shift())];if(isAsync){if(handleAsync){return handleAsync(()=>f.apply(receiver,args))}throw new Error("Synchronous WebAssembly cannot call async function")}const result=f.apply(receiver,args);if(typeof result?.then=="function"){console.error("unexpected Promise",f);throw new Error(`${methodName} unexpectedly returned a Promise`)}return result}};function _ipp(...args){return adapters_support(false,...args)}function _ipp_async(...args){return adapters_support(true,...args)}function _ippipppp(...args){return adapters_support(false,...args)}function _ippipppp_async(...args){return adapters_support(true,...args)}function _ippp(...args){return adapters_support(false,...args)}function _ippp_async(...args){return adapters_support(true,...args)}function _ipppi(...args){return adapters_support(false,...args)}function _ipppi_async(...args){return adapters_support(true,...args)}function _ipppiii(...args){return adapters_support(false,...args)}function _ipppiii_async(...args){return adapters_support(true,...args)}function _ipppiiip(...args){return adapters_support(false,...args)}function _ipppiiip_async(...args){return adapters_support(true,...args)}function _ipppip(...args){return adapters_support(false,...args)}function _ipppip_async(...args){return adapters_support(true,...args)}function _ipppj(...args){return adapters_support(false,...args)}function _ipppj_async(...args){return adapters_support(true,...args)}function _ipppp(...args){return adapters_support(false,...args)}function _ipppp_async(...args){return adapters_support(true,...args)}function _ippppi(...args){return adapters_support(false,...args)}function _ippppi_async(...args){return adapters_support(true,...args)}function _ippppij(...args){return adapters_support(false,...args)}function _ippppij_async(...args){return adapters_support(true,...args)}function _ippppip(...args){return adapters_support(false,...args)}function _ippppip_async(...args){return adapters_support(true,...args)}function _ipppppip(...args){return adapters_support(false,...args)}function _ipppppip_async(...args){return adapters_support(true,...args)}function _vppippii(...args){return adapters_support(false,...args)}function _vppippii_async(...args){return adapters_support(true,...args)}function _vppp(...args){return adapters_support(false,...args)}function _vppp_async(...args){return adapters_support(true,...args)}function _vpppip(...args){return adapters_support(false,...args)}function _vpppip_async(...args){return adapters_support(true,...args)}var uleb128Encode=(n,target)=>{if(n<128){target.push(n)}else{target.push(n%128|128,n>>7)}};var sigToWasmTypes=sig=>{var typeNames={i:"i32",j:"i64",f:"f32",d:"f64",e:"externref",p:"i32"};var type={parameters:[],results:sig[0]=="v"?[]:[typeNames[sig[0]]]};for(var i=1;i{var sigRet=sig.slice(0,1);var sigParam=sig.slice(1);var typeCodes={i:127,p:127,j:126,f:125,d:124,e:111};target.push(96);uleb128Encode(sigParam.length,target);for(var i=0;i{if(typeof WebAssembly.Function=="function"){return new WebAssembly.Function(sigToWasmTypes(sig),func)}var typeSectionBody=[1];generateFuncType(sig,typeSectionBody);var bytes=[0,97,115,109,1,0,0,0,1];uleb128Encode(typeSectionBody.length,bytes);bytes.push(...typeSectionBody);bytes.push(2,7,1,1,101,1,102,0,0,7,5,1,1,102,0,0);var module=new WebAssembly.Module(new Uint8Array(bytes));var instance=new WebAssembly.Instance(module,{e:{f:func}});var wrappedFunc=instance.exports["f"];return wrappedFunc};var wasmTable;var getWasmTableEntry=funcPtr=>wasmTable.get(funcPtr);var updateTableMap=(offset,count)=>{if(functionsInTableMap){for(var i=offset;i{if(!functionsInTableMap){functionsInTableMap=new WeakMap;updateTableMap(0,wasmTable.length)}return functionsInTableMap.get(func)||0};var freeTableIndexes=[];var getEmptyTableSlot=()=>{if(freeTableIndexes.length){return freeTableIndexes.pop()}try{wasmTable.grow(1)}catch(err){if(!(err instanceof RangeError)){throw err}throw"Unable to grow wasm table. Set ALLOW_TABLE_GROWTH."}return wasmTable.length-1};var setWasmTableEntry=(idx,func)=>wasmTable.set(idx,func);var addFunction=(func,sig)=>{var rtn=getFunctionAddress(func);if(rtn){return rtn}var ret=getEmptyTableSlot();try{setWasmTableEntry(ret,func)}catch(err){if(!(err instanceof TypeError)){throw err}var wrapped=convertJsFunctionToWasm(func,sig);setWasmTableEntry(ret,wrapped)}functionsInTableMap.set(func,ret);return ret};var getCFunc=ident=>{var func=Module["_"+ident];return func};var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer)};var stackAlloc=sz=>__emscripten_stack_alloc(sz);var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={string:str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str)}return ret},array:arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i{var numericArgs=!argTypes||argTypes.every(type=>type==="number"||type==="boolean");var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return(...args)=>ccall(ident,returnType,argTypes,args,opts)};var getTempRet0=val=>__emscripten_tempret_get();var stringToUTF16=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2}HEAP16[outPtr>>1]=0;return outPtr-startPtr};var stringToUTF32=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr};var AsciiToString=ptr=>{var str="";while(1){var ch=HEAPU8[ptr++];if(!ch)return str;str+=String.fromCharCode(ch)}};var UTF16Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf-16le"):undefined;var UTF16ToString=(ptr,maxBytesToRead)=>{var endPtr=ptr;var idx=endPtr>>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder)return UTF16Decoder.decode(HEAPU8.subarray(ptr,endPtr));var str="";for(var i=0;!(i>=maxBytesToRead/2);++i){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0)break;str+=String.fromCharCode(codeUnit)}return str};var UTF32ToString=(ptr,maxBytesToRead)=>{var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}return str};function intArrayToString(array){var ret=[];for(var i=0;i255){chr&=255}ret.push(String.fromCharCode(chr))}return ret.join("")}FS.createPreloadedFile=FS_createPreloadedFile;FS.staticInit();adapters_support();var wasmImports={a:___assert_fail,aa:___syscall_chmod,da:___syscall_faccessat,ba:___syscall_fchmod,$:___syscall_fchown32,b:___syscall_fcntl64,_:___syscall_fstat64,y:___syscall_ftruncate64,U:___syscall_getcwd,Y:___syscall_lstat64,R:___syscall_mkdirat,W:___syscall_newfstatat,P:___syscall_openat,N:___syscall_readlinkat,M:___syscall_rmdir,Z:___syscall_stat64,K:___syscall_unlinkat,J:___syscall_utimensat,F:__abort_js,E:__emscripten_runtime_keepalive_clear,w:__localtime_js,u:__mmap_js,v:__munmap_js,G:__setitimer_js,Q:__tzset_js,n:_emscripten_date_now,g:_emscripten_get_now,H:_emscripten_resize_heap,S:_environ_get,T:_environ_sizes_get,o:_fd_close,I:_fd_fdstat_get,O:_fd_read,x:_fd_seek,V:_fd_sync,L:_fd_write,na:_ipp,r:_ipp_async,ka:_ippipppp,oa:_ippipppp_async,j:_ippp,k:_ippp_async,c:_ipppi,d:_ipppi_async,ga:_ipppiii,ha:_ipppiii_async,ia:_ipppiiip,ja:_ipppiiip_async,h:_ipppip,i:_ipppip_async,z:_ipppj,A:_ipppj_async,e:_ipppp,f:_ipppp_async,ea:_ippppi,fa:_ippppi_async,B:_ippppij,C:_ippppij_async,p:_ippppip,q:_ippppip_async,la:_ipppppip,ma:_ipppppip_async,D:_proc_exit,s:_vppippii,t:_vppippii_async,l:_vppp,m:_vppp_async,X:_vpppip,ca:_vpppip_async};var wasmExports=createWasm();var ___wasm_call_ctors=()=>(___wasm_call_ctors=wasmExports["qa"])();var _sqlite3_status64=Module["_sqlite3_status64"]=(a0,a1,a2,a3)=>(_sqlite3_status64=Module["_sqlite3_status64"]=wasmExports["ra"])(a0,a1,a2,a3);var _sqlite3_status=Module["_sqlite3_status"]=(a0,a1,a2,a3)=>(_sqlite3_status=Module["_sqlite3_status"]=wasmExports["sa"])(a0,a1,a2,a3);var _sqlite3_db_status=Module["_sqlite3_db_status"]=(a0,a1,a2,a3,a4)=>(_sqlite3_db_status=Module["_sqlite3_db_status"]=wasmExports["ta"])(a0,a1,a2,a3,a4);var _sqlite3_msize=Module["_sqlite3_msize"]=a0=>(_sqlite3_msize=Module["_sqlite3_msize"]=wasmExports["ua"])(a0);var _sqlite3_vfs_find=Module["_sqlite3_vfs_find"]=a0=>(_sqlite3_vfs_find=Module["_sqlite3_vfs_find"]=wasmExports["va"])(a0);var _sqlite3_vfs_register=Module["_sqlite3_vfs_register"]=(a0,a1)=>(_sqlite3_vfs_register=Module["_sqlite3_vfs_register"]=wasmExports["wa"])(a0,a1);var _sqlite3_vfs_unregister=Module["_sqlite3_vfs_unregister"]=a0=>(_sqlite3_vfs_unregister=Module["_sqlite3_vfs_unregister"]=wasmExports["xa"])(a0);var _sqlite3_release_memory=Module["_sqlite3_release_memory"]=a0=>(_sqlite3_release_memory=Module["_sqlite3_release_memory"]=wasmExports["ya"])(a0);var _sqlite3_soft_heap_limit64=Module["_sqlite3_soft_heap_limit64"]=(a0,a1)=>(_sqlite3_soft_heap_limit64=Module["_sqlite3_soft_heap_limit64"]=wasmExports["za"])(a0,a1);var _sqlite3_memory_used=Module["_sqlite3_memory_used"]=()=>(_sqlite3_memory_used=Module["_sqlite3_memory_used"]=wasmExports["Aa"])();var _sqlite3_hard_heap_limit64=Module["_sqlite3_hard_heap_limit64"]=(a0,a1)=>(_sqlite3_hard_heap_limit64=Module["_sqlite3_hard_heap_limit64"]=wasmExports["Ba"])(a0,a1);var _sqlite3_memory_highwater=Module["_sqlite3_memory_highwater"]=a0=>(_sqlite3_memory_highwater=Module["_sqlite3_memory_highwater"]=wasmExports["Ca"])(a0);var _sqlite3_malloc=Module["_sqlite3_malloc"]=a0=>(_sqlite3_malloc=Module["_sqlite3_malloc"]=wasmExports["Da"])(a0);var _sqlite3_malloc64=Module["_sqlite3_malloc64"]=(a0,a1)=>(_sqlite3_malloc64=Module["_sqlite3_malloc64"]=wasmExports["Ea"])(a0,a1);var _sqlite3_free=Module["_sqlite3_free"]=a0=>(_sqlite3_free=Module["_sqlite3_free"]=wasmExports["Fa"])(a0);var _sqlite3_realloc=Module["_sqlite3_realloc"]=(a0,a1)=>(_sqlite3_realloc=Module["_sqlite3_realloc"]=wasmExports["Ga"])(a0,a1);var _sqlite3_realloc64=Module["_sqlite3_realloc64"]=(a0,a1,a2)=>(_sqlite3_realloc64=Module["_sqlite3_realloc64"]=wasmExports["Ha"])(a0,a1,a2);var _sqlite3_str_vappendf=Module["_sqlite3_str_vappendf"]=(a0,a1,a2)=>(_sqlite3_str_vappendf=Module["_sqlite3_str_vappendf"]=wasmExports["Ia"])(a0,a1,a2);var _sqlite3_str_append=Module["_sqlite3_str_append"]=(a0,a1,a2)=>(_sqlite3_str_append=Module["_sqlite3_str_append"]=wasmExports["Ja"])(a0,a1,a2);var _sqlite3_str_appendchar=Module["_sqlite3_str_appendchar"]=(a0,a1,a2)=>(_sqlite3_str_appendchar=Module["_sqlite3_str_appendchar"]=wasmExports["Ka"])(a0,a1,a2);var _sqlite3_str_appendall=Module["_sqlite3_str_appendall"]=(a0,a1)=>(_sqlite3_str_appendall=Module["_sqlite3_str_appendall"]=wasmExports["La"])(a0,a1);var _sqlite3_str_appendf=Module["_sqlite3_str_appendf"]=(a0,a1,a2)=>(_sqlite3_str_appendf=Module["_sqlite3_str_appendf"]=wasmExports["Ma"])(a0,a1,a2);var _sqlite3_str_finish=Module["_sqlite3_str_finish"]=a0=>(_sqlite3_str_finish=Module["_sqlite3_str_finish"]=wasmExports["Na"])(a0);var _sqlite3_str_errcode=Module["_sqlite3_str_errcode"]=a0=>(_sqlite3_str_errcode=Module["_sqlite3_str_errcode"]=wasmExports["Oa"])(a0);var _sqlite3_str_length=Module["_sqlite3_str_length"]=a0=>(_sqlite3_str_length=Module["_sqlite3_str_length"]=wasmExports["Pa"])(a0);var _sqlite3_str_value=Module["_sqlite3_str_value"]=a0=>(_sqlite3_str_value=Module["_sqlite3_str_value"]=wasmExports["Qa"])(a0);var _sqlite3_str_reset=Module["_sqlite3_str_reset"]=a0=>(_sqlite3_str_reset=Module["_sqlite3_str_reset"]=wasmExports["Ra"])(a0);var _sqlite3_str_new=Module["_sqlite3_str_new"]=a0=>(_sqlite3_str_new=Module["_sqlite3_str_new"]=wasmExports["Sa"])(a0);var _sqlite3_vmprintf=Module["_sqlite3_vmprintf"]=(a0,a1)=>(_sqlite3_vmprintf=Module["_sqlite3_vmprintf"]=wasmExports["Ta"])(a0,a1);var _sqlite3_mprintf=Module["_sqlite3_mprintf"]=(a0,a1)=>(_sqlite3_mprintf=Module["_sqlite3_mprintf"]=wasmExports["Ua"])(a0,a1);var _sqlite3_vsnprintf=Module["_sqlite3_vsnprintf"]=(a0,a1,a2,a3)=>(_sqlite3_vsnprintf=Module["_sqlite3_vsnprintf"]=wasmExports["Va"])(a0,a1,a2,a3);var _sqlite3_snprintf=Module["_sqlite3_snprintf"]=(a0,a1,a2,a3)=>(_sqlite3_snprintf=Module["_sqlite3_snprintf"]=wasmExports["Wa"])(a0,a1,a2,a3);var _sqlite3_log=Module["_sqlite3_log"]=(a0,a1,a2)=>(_sqlite3_log=Module["_sqlite3_log"]=wasmExports["Xa"])(a0,a1,a2);var _sqlite3_randomness=Module["_sqlite3_randomness"]=(a0,a1)=>(_sqlite3_randomness=Module["_sqlite3_randomness"]=wasmExports["Ya"])(a0,a1);var _sqlite3_stricmp=Module["_sqlite3_stricmp"]=(a0,a1)=>(_sqlite3_stricmp=Module["_sqlite3_stricmp"]=wasmExports["Za"])(a0,a1);var _sqlite3_strnicmp=Module["_sqlite3_strnicmp"]=(a0,a1,a2)=>(_sqlite3_strnicmp=Module["_sqlite3_strnicmp"]=wasmExports["_a"])(a0,a1,a2);var _sqlite3_os_init=Module["_sqlite3_os_init"]=()=>(_sqlite3_os_init=Module["_sqlite3_os_init"]=wasmExports["$a"])();var _sqlite3_os_end=Module["_sqlite3_os_end"]=()=>(_sqlite3_os_end=Module["_sqlite3_os_end"]=wasmExports["ab"])();var _sqlite3_serialize=Module["_sqlite3_serialize"]=(a0,a1,a2,a3)=>(_sqlite3_serialize=Module["_sqlite3_serialize"]=wasmExports["bb"])(a0,a1,a2,a3);var _sqlite3_prepare_v2=Module["_sqlite3_prepare_v2"]=(a0,a1,a2,a3,a4)=>(_sqlite3_prepare_v2=Module["_sqlite3_prepare_v2"]=wasmExports["cb"])(a0,a1,a2,a3,a4);var _sqlite3_step=Module["_sqlite3_step"]=a0=>(_sqlite3_step=Module["_sqlite3_step"]=wasmExports["db"])(a0);var _sqlite3_column_int64=Module["_sqlite3_column_int64"]=(a0,a1)=>(_sqlite3_column_int64=Module["_sqlite3_column_int64"]=wasmExports["eb"])(a0,a1);var _sqlite3_reset=Module["_sqlite3_reset"]=a0=>(_sqlite3_reset=Module["_sqlite3_reset"]=wasmExports["fb"])(a0);var _sqlite3_exec=Module["_sqlite3_exec"]=(a0,a1,a2,a3,a4)=>(_sqlite3_exec=Module["_sqlite3_exec"]=wasmExports["gb"])(a0,a1,a2,a3,a4);var _sqlite3_column_int=Module["_sqlite3_column_int"]=(a0,a1)=>(_sqlite3_column_int=Module["_sqlite3_column_int"]=wasmExports["hb"])(a0,a1);var _sqlite3_finalize=Module["_sqlite3_finalize"]=a0=>(_sqlite3_finalize=Module["_sqlite3_finalize"]=wasmExports["ib"])(a0);var _sqlite3_deserialize=Module["_sqlite3_deserialize"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(_sqlite3_deserialize=Module["_sqlite3_deserialize"]=wasmExports["jb"])(a0,a1,a2,a3,a4,a5,a6,a7);var _sqlite3_database_file_object=Module["_sqlite3_database_file_object"]=a0=>(_sqlite3_database_file_object=Module["_sqlite3_database_file_object"]=wasmExports["kb"])(a0);var _sqlite3_backup_init=Module["_sqlite3_backup_init"]=(a0,a1,a2,a3)=>(_sqlite3_backup_init=Module["_sqlite3_backup_init"]=wasmExports["lb"])(a0,a1,a2,a3);var _sqlite3_backup_step=Module["_sqlite3_backup_step"]=(a0,a1)=>(_sqlite3_backup_step=Module["_sqlite3_backup_step"]=wasmExports["mb"])(a0,a1);var _sqlite3_backup_finish=Module["_sqlite3_backup_finish"]=a0=>(_sqlite3_backup_finish=Module["_sqlite3_backup_finish"]=wasmExports["nb"])(a0);var _sqlite3_backup_remaining=Module["_sqlite3_backup_remaining"]=a0=>(_sqlite3_backup_remaining=Module["_sqlite3_backup_remaining"]=wasmExports["ob"])(a0);var _sqlite3_backup_pagecount=Module["_sqlite3_backup_pagecount"]=a0=>(_sqlite3_backup_pagecount=Module["_sqlite3_backup_pagecount"]=wasmExports["pb"])(a0);var _sqlite3_clear_bindings=Module["_sqlite3_clear_bindings"]=a0=>(_sqlite3_clear_bindings=Module["_sqlite3_clear_bindings"]=wasmExports["qb"])(a0);var _sqlite3_value_blob=Module["_sqlite3_value_blob"]=a0=>(_sqlite3_value_blob=Module["_sqlite3_value_blob"]=wasmExports["rb"])(a0);var _sqlite3_value_text=Module["_sqlite3_value_text"]=a0=>(_sqlite3_value_text=Module["_sqlite3_value_text"]=wasmExports["sb"])(a0);var _sqlite3_value_bytes=Module["_sqlite3_value_bytes"]=a0=>(_sqlite3_value_bytes=Module["_sqlite3_value_bytes"]=wasmExports["tb"])(a0);var _sqlite3_value_bytes16=Module["_sqlite3_value_bytes16"]=a0=>(_sqlite3_value_bytes16=Module["_sqlite3_value_bytes16"]=wasmExports["ub"])(a0);var _sqlite3_value_double=Module["_sqlite3_value_double"]=a0=>(_sqlite3_value_double=Module["_sqlite3_value_double"]=wasmExports["vb"])(a0);var _sqlite3_value_int=Module["_sqlite3_value_int"]=a0=>(_sqlite3_value_int=Module["_sqlite3_value_int"]=wasmExports["wb"])(a0);var _sqlite3_value_int64=Module["_sqlite3_value_int64"]=a0=>(_sqlite3_value_int64=Module["_sqlite3_value_int64"]=wasmExports["xb"])(a0);var _sqlite3_value_subtype=Module["_sqlite3_value_subtype"]=a0=>(_sqlite3_value_subtype=Module["_sqlite3_value_subtype"]=wasmExports["yb"])(a0);var _sqlite3_value_pointer=Module["_sqlite3_value_pointer"]=(a0,a1)=>(_sqlite3_value_pointer=Module["_sqlite3_value_pointer"]=wasmExports["zb"])(a0,a1);var _sqlite3_value_text16=Module["_sqlite3_value_text16"]=a0=>(_sqlite3_value_text16=Module["_sqlite3_value_text16"]=wasmExports["Ab"])(a0);var _sqlite3_value_text16be=Module["_sqlite3_value_text16be"]=a0=>(_sqlite3_value_text16be=Module["_sqlite3_value_text16be"]=wasmExports["Bb"])(a0);var _sqlite3_value_text16le=Module["_sqlite3_value_text16le"]=a0=>(_sqlite3_value_text16le=Module["_sqlite3_value_text16le"]=wasmExports["Cb"])(a0);var _sqlite3_value_type=Module["_sqlite3_value_type"]=a0=>(_sqlite3_value_type=Module["_sqlite3_value_type"]=wasmExports["Db"])(a0);var _sqlite3_value_encoding=Module["_sqlite3_value_encoding"]=a0=>(_sqlite3_value_encoding=Module["_sqlite3_value_encoding"]=wasmExports["Eb"])(a0);var _sqlite3_value_nochange=Module["_sqlite3_value_nochange"]=a0=>(_sqlite3_value_nochange=Module["_sqlite3_value_nochange"]=wasmExports["Fb"])(a0);var _sqlite3_value_frombind=Module["_sqlite3_value_frombind"]=a0=>(_sqlite3_value_frombind=Module["_sqlite3_value_frombind"]=wasmExports["Gb"])(a0);var _sqlite3_value_dup=Module["_sqlite3_value_dup"]=a0=>(_sqlite3_value_dup=Module["_sqlite3_value_dup"]=wasmExports["Hb"])(a0);var _sqlite3_value_free=Module["_sqlite3_value_free"]=a0=>(_sqlite3_value_free=Module["_sqlite3_value_free"]=wasmExports["Ib"])(a0);var _sqlite3_result_blob=Module["_sqlite3_result_blob"]=(a0,a1,a2,a3)=>(_sqlite3_result_blob=Module["_sqlite3_result_blob"]=wasmExports["Jb"])(a0,a1,a2,a3);var _sqlite3_result_blob64=Module["_sqlite3_result_blob64"]=(a0,a1,a2,a3,a4)=>(_sqlite3_result_blob64=Module["_sqlite3_result_blob64"]=wasmExports["Kb"])(a0,a1,a2,a3,a4);var _sqlite3_result_double=Module["_sqlite3_result_double"]=(a0,a1)=>(_sqlite3_result_double=Module["_sqlite3_result_double"]=wasmExports["Lb"])(a0,a1);var _sqlite3_result_error=Module["_sqlite3_result_error"]=(a0,a1,a2)=>(_sqlite3_result_error=Module["_sqlite3_result_error"]=wasmExports["Mb"])(a0,a1,a2);var _sqlite3_result_error16=Module["_sqlite3_result_error16"]=(a0,a1,a2)=>(_sqlite3_result_error16=Module["_sqlite3_result_error16"]=wasmExports["Nb"])(a0,a1,a2);var _sqlite3_result_int=Module["_sqlite3_result_int"]=(a0,a1)=>(_sqlite3_result_int=Module["_sqlite3_result_int"]=wasmExports["Ob"])(a0,a1);var _sqlite3_result_int64=Module["_sqlite3_result_int64"]=(a0,a1,a2)=>(_sqlite3_result_int64=Module["_sqlite3_result_int64"]=wasmExports["Pb"])(a0,a1,a2);var _sqlite3_result_null=Module["_sqlite3_result_null"]=a0=>(_sqlite3_result_null=Module["_sqlite3_result_null"]=wasmExports["Qb"])(a0);var _sqlite3_result_pointer=Module["_sqlite3_result_pointer"]=(a0,a1,a2,a3)=>(_sqlite3_result_pointer=Module["_sqlite3_result_pointer"]=wasmExports["Rb"])(a0,a1,a2,a3);var _sqlite3_result_subtype=Module["_sqlite3_result_subtype"]=(a0,a1)=>(_sqlite3_result_subtype=Module["_sqlite3_result_subtype"]=wasmExports["Sb"])(a0,a1);var _sqlite3_result_text=Module["_sqlite3_result_text"]=(a0,a1,a2,a3)=>(_sqlite3_result_text=Module["_sqlite3_result_text"]=wasmExports["Tb"])(a0,a1,a2,a3);var _sqlite3_result_text64=Module["_sqlite3_result_text64"]=(a0,a1,a2,a3,a4,a5)=>(_sqlite3_result_text64=Module["_sqlite3_result_text64"]=wasmExports["Ub"])(a0,a1,a2,a3,a4,a5);var _sqlite3_result_text16=Module["_sqlite3_result_text16"]=(a0,a1,a2,a3)=>(_sqlite3_result_text16=Module["_sqlite3_result_text16"]=wasmExports["Vb"])(a0,a1,a2,a3);var _sqlite3_result_text16be=Module["_sqlite3_result_text16be"]=(a0,a1,a2,a3)=>(_sqlite3_result_text16be=Module["_sqlite3_result_text16be"]=wasmExports["Wb"])(a0,a1,a2,a3);var _sqlite3_result_text16le=Module["_sqlite3_result_text16le"]=(a0,a1,a2,a3)=>(_sqlite3_result_text16le=Module["_sqlite3_result_text16le"]=wasmExports["Xb"])(a0,a1,a2,a3);var _sqlite3_result_value=Module["_sqlite3_result_value"]=(a0,a1)=>(_sqlite3_result_value=Module["_sqlite3_result_value"]=wasmExports["Yb"])(a0,a1);var _sqlite3_result_error_toobig=Module["_sqlite3_result_error_toobig"]=a0=>(_sqlite3_result_error_toobig=Module["_sqlite3_result_error_toobig"]=wasmExports["Zb"])(a0);var _sqlite3_result_zeroblob=Module["_sqlite3_result_zeroblob"]=(a0,a1)=>(_sqlite3_result_zeroblob=Module["_sqlite3_result_zeroblob"]=wasmExports["_b"])(a0,a1);var _sqlite3_result_zeroblob64=Module["_sqlite3_result_zeroblob64"]=(a0,a1,a2)=>(_sqlite3_result_zeroblob64=Module["_sqlite3_result_zeroblob64"]=wasmExports["$b"])(a0,a1,a2);var _sqlite3_result_error_code=Module["_sqlite3_result_error_code"]=(a0,a1)=>(_sqlite3_result_error_code=Module["_sqlite3_result_error_code"]=wasmExports["ac"])(a0,a1);var _sqlite3_result_error_nomem=Module["_sqlite3_result_error_nomem"]=a0=>(_sqlite3_result_error_nomem=Module["_sqlite3_result_error_nomem"]=wasmExports["bc"])(a0);var _sqlite3_user_data=Module["_sqlite3_user_data"]=a0=>(_sqlite3_user_data=Module["_sqlite3_user_data"]=wasmExports["cc"])(a0);var _sqlite3_context_db_handle=Module["_sqlite3_context_db_handle"]=a0=>(_sqlite3_context_db_handle=Module["_sqlite3_context_db_handle"]=wasmExports["dc"])(a0);var _sqlite3_vtab_nochange=Module["_sqlite3_vtab_nochange"]=a0=>(_sqlite3_vtab_nochange=Module["_sqlite3_vtab_nochange"]=wasmExports["ec"])(a0);var _sqlite3_vtab_in_first=Module["_sqlite3_vtab_in_first"]=(a0,a1)=>(_sqlite3_vtab_in_first=Module["_sqlite3_vtab_in_first"]=wasmExports["fc"])(a0,a1);var _sqlite3_vtab_in_next=Module["_sqlite3_vtab_in_next"]=(a0,a1)=>(_sqlite3_vtab_in_next=Module["_sqlite3_vtab_in_next"]=wasmExports["gc"])(a0,a1);var _sqlite3_aggregate_context=Module["_sqlite3_aggregate_context"]=(a0,a1)=>(_sqlite3_aggregate_context=Module["_sqlite3_aggregate_context"]=wasmExports["hc"])(a0,a1);var _sqlite3_get_auxdata=Module["_sqlite3_get_auxdata"]=(a0,a1)=>(_sqlite3_get_auxdata=Module["_sqlite3_get_auxdata"]=wasmExports["ic"])(a0,a1);var _sqlite3_set_auxdata=Module["_sqlite3_set_auxdata"]=(a0,a1,a2,a3)=>(_sqlite3_set_auxdata=Module["_sqlite3_set_auxdata"]=wasmExports["jc"])(a0,a1,a2,a3);var _sqlite3_column_count=Module["_sqlite3_column_count"]=a0=>(_sqlite3_column_count=Module["_sqlite3_column_count"]=wasmExports["kc"])(a0);var _sqlite3_data_count=Module["_sqlite3_data_count"]=a0=>(_sqlite3_data_count=Module["_sqlite3_data_count"]=wasmExports["lc"])(a0);var _sqlite3_column_blob=Module["_sqlite3_column_blob"]=(a0,a1)=>(_sqlite3_column_blob=Module["_sqlite3_column_blob"]=wasmExports["mc"])(a0,a1);var _sqlite3_column_bytes=Module["_sqlite3_column_bytes"]=(a0,a1)=>(_sqlite3_column_bytes=Module["_sqlite3_column_bytes"]=wasmExports["nc"])(a0,a1);var _sqlite3_column_bytes16=Module["_sqlite3_column_bytes16"]=(a0,a1)=>(_sqlite3_column_bytes16=Module["_sqlite3_column_bytes16"]=wasmExports["oc"])(a0,a1);var _sqlite3_column_double=Module["_sqlite3_column_double"]=(a0,a1)=>(_sqlite3_column_double=Module["_sqlite3_column_double"]=wasmExports["pc"])(a0,a1);var _sqlite3_column_text=Module["_sqlite3_column_text"]=(a0,a1)=>(_sqlite3_column_text=Module["_sqlite3_column_text"]=wasmExports["qc"])(a0,a1);var _sqlite3_column_value=Module["_sqlite3_column_value"]=(a0,a1)=>(_sqlite3_column_value=Module["_sqlite3_column_value"]=wasmExports["rc"])(a0,a1);var _sqlite3_column_text16=Module["_sqlite3_column_text16"]=(a0,a1)=>(_sqlite3_column_text16=Module["_sqlite3_column_text16"]=wasmExports["sc"])(a0,a1);var _sqlite3_column_type=Module["_sqlite3_column_type"]=(a0,a1)=>(_sqlite3_column_type=Module["_sqlite3_column_type"]=wasmExports["tc"])(a0,a1);var _sqlite3_column_name=Module["_sqlite3_column_name"]=(a0,a1)=>(_sqlite3_column_name=Module["_sqlite3_column_name"]=wasmExports["uc"])(a0,a1);var _sqlite3_column_name16=Module["_sqlite3_column_name16"]=(a0,a1)=>(_sqlite3_column_name16=Module["_sqlite3_column_name16"]=wasmExports["vc"])(a0,a1);var _sqlite3_bind_blob=Module["_sqlite3_bind_blob"]=(a0,a1,a2,a3,a4)=>(_sqlite3_bind_blob=Module["_sqlite3_bind_blob"]=wasmExports["wc"])(a0,a1,a2,a3,a4);var _sqlite3_bind_blob64=Module["_sqlite3_bind_blob64"]=(a0,a1,a2,a3,a4,a5)=>(_sqlite3_bind_blob64=Module["_sqlite3_bind_blob64"]=wasmExports["xc"])(a0,a1,a2,a3,a4,a5);var _sqlite3_bind_double=Module["_sqlite3_bind_double"]=(a0,a1,a2)=>(_sqlite3_bind_double=Module["_sqlite3_bind_double"]=wasmExports["yc"])(a0,a1,a2);var _sqlite3_bind_int=Module["_sqlite3_bind_int"]=(a0,a1,a2)=>(_sqlite3_bind_int=Module["_sqlite3_bind_int"]=wasmExports["zc"])(a0,a1,a2);var _sqlite3_bind_int64=Module["_sqlite3_bind_int64"]=(a0,a1,a2,a3)=>(_sqlite3_bind_int64=Module["_sqlite3_bind_int64"]=wasmExports["Ac"])(a0,a1,a2,a3);var _sqlite3_bind_null=Module["_sqlite3_bind_null"]=(a0,a1)=>(_sqlite3_bind_null=Module["_sqlite3_bind_null"]=wasmExports["Bc"])(a0,a1);var _sqlite3_bind_pointer=Module["_sqlite3_bind_pointer"]=(a0,a1,a2,a3,a4)=>(_sqlite3_bind_pointer=Module["_sqlite3_bind_pointer"]=wasmExports["Cc"])(a0,a1,a2,a3,a4);var _sqlite3_bind_text=Module["_sqlite3_bind_text"]=(a0,a1,a2,a3,a4)=>(_sqlite3_bind_text=Module["_sqlite3_bind_text"]=wasmExports["Dc"])(a0,a1,a2,a3,a4);var _sqlite3_bind_text64=Module["_sqlite3_bind_text64"]=(a0,a1,a2,a3,a4,a5,a6)=>(_sqlite3_bind_text64=Module["_sqlite3_bind_text64"]=wasmExports["Ec"])(a0,a1,a2,a3,a4,a5,a6);var _sqlite3_bind_text16=Module["_sqlite3_bind_text16"]=(a0,a1,a2,a3,a4)=>(_sqlite3_bind_text16=Module["_sqlite3_bind_text16"]=wasmExports["Fc"])(a0,a1,a2,a3,a4);var _sqlite3_bind_value=Module["_sqlite3_bind_value"]=(a0,a1,a2)=>(_sqlite3_bind_value=Module["_sqlite3_bind_value"]=wasmExports["Gc"])(a0,a1,a2);var _sqlite3_bind_zeroblob=Module["_sqlite3_bind_zeroblob"]=(a0,a1,a2)=>(_sqlite3_bind_zeroblob=Module["_sqlite3_bind_zeroblob"]=wasmExports["Hc"])(a0,a1,a2);var _sqlite3_bind_zeroblob64=Module["_sqlite3_bind_zeroblob64"]=(a0,a1,a2,a3)=>(_sqlite3_bind_zeroblob64=Module["_sqlite3_bind_zeroblob64"]=wasmExports["Ic"])(a0,a1,a2,a3);var _sqlite3_bind_parameter_count=Module["_sqlite3_bind_parameter_count"]=a0=>(_sqlite3_bind_parameter_count=Module["_sqlite3_bind_parameter_count"]=wasmExports["Jc"])(a0);var _sqlite3_bind_parameter_name=Module["_sqlite3_bind_parameter_name"]=(a0,a1)=>(_sqlite3_bind_parameter_name=Module["_sqlite3_bind_parameter_name"]=wasmExports["Kc"])(a0,a1);var _sqlite3_bind_parameter_index=Module["_sqlite3_bind_parameter_index"]=(a0,a1)=>(_sqlite3_bind_parameter_index=Module["_sqlite3_bind_parameter_index"]=wasmExports["Lc"])(a0,a1);var _sqlite3_db_handle=Module["_sqlite3_db_handle"]=a0=>(_sqlite3_db_handle=Module["_sqlite3_db_handle"]=wasmExports["Mc"])(a0);var _sqlite3_stmt_readonly=Module["_sqlite3_stmt_readonly"]=a0=>(_sqlite3_stmt_readonly=Module["_sqlite3_stmt_readonly"]=wasmExports["Nc"])(a0);var _sqlite3_stmt_isexplain=Module["_sqlite3_stmt_isexplain"]=a0=>(_sqlite3_stmt_isexplain=Module["_sqlite3_stmt_isexplain"]=wasmExports["Oc"])(a0);var _sqlite3_stmt_explain=Module["_sqlite3_stmt_explain"]=(a0,a1)=>(_sqlite3_stmt_explain=Module["_sqlite3_stmt_explain"]=wasmExports["Pc"])(a0,a1);var _sqlite3_stmt_busy=Module["_sqlite3_stmt_busy"]=a0=>(_sqlite3_stmt_busy=Module["_sqlite3_stmt_busy"]=wasmExports["Qc"])(a0);var _sqlite3_next_stmt=Module["_sqlite3_next_stmt"]=(a0,a1)=>(_sqlite3_next_stmt=Module["_sqlite3_next_stmt"]=wasmExports["Rc"])(a0,a1);var _sqlite3_stmt_status=Module["_sqlite3_stmt_status"]=(a0,a1,a2)=>(_sqlite3_stmt_status=Module["_sqlite3_stmt_status"]=wasmExports["Sc"])(a0,a1,a2);var _sqlite3_sql=Module["_sqlite3_sql"]=a0=>(_sqlite3_sql=Module["_sqlite3_sql"]=wasmExports["Tc"])(a0);var _sqlite3_expanded_sql=Module["_sqlite3_expanded_sql"]=a0=>(_sqlite3_expanded_sql=Module["_sqlite3_expanded_sql"]=wasmExports["Uc"])(a0);var _sqlite3_value_numeric_type=Module["_sqlite3_value_numeric_type"]=a0=>(_sqlite3_value_numeric_type=Module["_sqlite3_value_numeric_type"]=wasmExports["Vc"])(a0);var _sqlite3_blob_open=Module["_sqlite3_blob_open"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(_sqlite3_blob_open=Module["_sqlite3_blob_open"]=wasmExports["Wc"])(a0,a1,a2,a3,a4,a5,a6,a7);var _sqlite3_blob_close=Module["_sqlite3_blob_close"]=a0=>(_sqlite3_blob_close=Module["_sqlite3_blob_close"]=wasmExports["Xc"])(a0);var _sqlite3_blob_read=Module["_sqlite3_blob_read"]=(a0,a1,a2,a3)=>(_sqlite3_blob_read=Module["_sqlite3_blob_read"]=wasmExports["Yc"])(a0,a1,a2,a3);var _sqlite3_blob_write=Module["_sqlite3_blob_write"]=(a0,a1,a2,a3)=>(_sqlite3_blob_write=Module["_sqlite3_blob_write"]=wasmExports["Zc"])(a0,a1,a2,a3);var _sqlite3_blob_bytes=Module["_sqlite3_blob_bytes"]=a0=>(_sqlite3_blob_bytes=Module["_sqlite3_blob_bytes"]=wasmExports["_c"])(a0);var _sqlite3_blob_reopen=Module["_sqlite3_blob_reopen"]=(a0,a1,a2)=>(_sqlite3_blob_reopen=Module["_sqlite3_blob_reopen"]=wasmExports["$c"])(a0,a1,a2);var _sqlite3_set_authorizer=Module["_sqlite3_set_authorizer"]=(a0,a1,a2)=>(_sqlite3_set_authorizer=Module["_sqlite3_set_authorizer"]=wasmExports["ad"])(a0,a1,a2);var _sqlite3_strglob=Module["_sqlite3_strglob"]=(a0,a1)=>(_sqlite3_strglob=Module["_sqlite3_strglob"]=wasmExports["bd"])(a0,a1);var _sqlite3_strlike=Module["_sqlite3_strlike"]=(a0,a1,a2)=>(_sqlite3_strlike=Module["_sqlite3_strlike"]=wasmExports["cd"])(a0,a1,a2);var _sqlite3_errmsg=Module["_sqlite3_errmsg"]=a0=>(_sqlite3_errmsg=Module["_sqlite3_errmsg"]=wasmExports["dd"])(a0);var _sqlite3_auto_extension=Module["_sqlite3_auto_extension"]=a0=>(_sqlite3_auto_extension=Module["_sqlite3_auto_extension"]=wasmExports["ed"])(a0);var _sqlite3_cancel_auto_extension=Module["_sqlite3_cancel_auto_extension"]=a0=>(_sqlite3_cancel_auto_extension=Module["_sqlite3_cancel_auto_extension"]=wasmExports["fd"])(a0);var _sqlite3_reset_auto_extension=Module["_sqlite3_reset_auto_extension"]=()=>(_sqlite3_reset_auto_extension=Module["_sqlite3_reset_auto_extension"]=wasmExports["gd"])();var _sqlite3_prepare=Module["_sqlite3_prepare"]=(a0,a1,a2,a3,a4)=>(_sqlite3_prepare=Module["_sqlite3_prepare"]=wasmExports["hd"])(a0,a1,a2,a3,a4);var _sqlite3_prepare_v3=Module["_sqlite3_prepare_v3"]=(a0,a1,a2,a3,a4,a5)=>(_sqlite3_prepare_v3=Module["_sqlite3_prepare_v3"]=wasmExports["id"])(a0,a1,a2,a3,a4,a5);var _sqlite3_prepare16=Module["_sqlite3_prepare16"]=(a0,a1,a2,a3,a4)=>(_sqlite3_prepare16=Module["_sqlite3_prepare16"]=wasmExports["jd"])(a0,a1,a2,a3,a4);var _sqlite3_prepare16_v2=Module["_sqlite3_prepare16_v2"]=(a0,a1,a2,a3,a4)=>(_sqlite3_prepare16_v2=Module["_sqlite3_prepare16_v2"]=wasmExports["kd"])(a0,a1,a2,a3,a4);var _sqlite3_prepare16_v3=Module["_sqlite3_prepare16_v3"]=(a0,a1,a2,a3,a4,a5)=>(_sqlite3_prepare16_v3=Module["_sqlite3_prepare16_v3"]=wasmExports["ld"])(a0,a1,a2,a3,a4,a5);var _sqlite3_get_table=Module["_sqlite3_get_table"]=(a0,a1,a2,a3,a4,a5)=>(_sqlite3_get_table=Module["_sqlite3_get_table"]=wasmExports["md"])(a0,a1,a2,a3,a4,a5);var _sqlite3_free_table=Module["_sqlite3_free_table"]=a0=>(_sqlite3_free_table=Module["_sqlite3_free_table"]=wasmExports["nd"])(a0);var _sqlite3_create_module=Module["_sqlite3_create_module"]=(a0,a1,a2,a3)=>(_sqlite3_create_module=Module["_sqlite3_create_module"]=wasmExports["od"])(a0,a1,a2,a3);var _sqlite3_create_module_v2=Module["_sqlite3_create_module_v2"]=(a0,a1,a2,a3,a4)=>(_sqlite3_create_module_v2=Module["_sqlite3_create_module_v2"]=wasmExports["pd"])(a0,a1,a2,a3,a4);var _sqlite3_drop_modules=Module["_sqlite3_drop_modules"]=(a0,a1)=>(_sqlite3_drop_modules=Module["_sqlite3_drop_modules"]=wasmExports["qd"])(a0,a1);var _sqlite3_declare_vtab=Module["_sqlite3_declare_vtab"]=(a0,a1)=>(_sqlite3_declare_vtab=Module["_sqlite3_declare_vtab"]=wasmExports["rd"])(a0,a1);var _sqlite3_vtab_on_conflict=Module["_sqlite3_vtab_on_conflict"]=a0=>(_sqlite3_vtab_on_conflict=Module["_sqlite3_vtab_on_conflict"]=wasmExports["sd"])(a0);var _sqlite3_vtab_config=Module["_sqlite3_vtab_config"]=(a0,a1,a2)=>(_sqlite3_vtab_config=Module["_sqlite3_vtab_config"]=wasmExports["td"])(a0,a1,a2);var _sqlite3_vtab_collation=Module["_sqlite3_vtab_collation"]=(a0,a1)=>(_sqlite3_vtab_collation=Module["_sqlite3_vtab_collation"]=wasmExports["ud"])(a0,a1);var _sqlite3_vtab_in=Module["_sqlite3_vtab_in"]=(a0,a1,a2)=>(_sqlite3_vtab_in=Module["_sqlite3_vtab_in"]=wasmExports["vd"])(a0,a1,a2);var _sqlite3_vtab_rhs_value=Module["_sqlite3_vtab_rhs_value"]=(a0,a1,a2)=>(_sqlite3_vtab_rhs_value=Module["_sqlite3_vtab_rhs_value"]=wasmExports["wd"])(a0,a1,a2);var _sqlite3_vtab_distinct=Module["_sqlite3_vtab_distinct"]=a0=>(_sqlite3_vtab_distinct=Module["_sqlite3_vtab_distinct"]=wasmExports["xd"])(a0);var _sqlite3_keyword_name=Module["_sqlite3_keyword_name"]=(a0,a1,a2)=>(_sqlite3_keyword_name=Module["_sqlite3_keyword_name"]=wasmExports["yd"])(a0,a1,a2);var _sqlite3_keyword_count=Module["_sqlite3_keyword_count"]=()=>(_sqlite3_keyword_count=Module["_sqlite3_keyword_count"]=wasmExports["zd"])();var _sqlite3_keyword_check=Module["_sqlite3_keyword_check"]=(a0,a1)=>(_sqlite3_keyword_check=Module["_sqlite3_keyword_check"]=wasmExports["Ad"])(a0,a1);var _sqlite3_complete=Module["_sqlite3_complete"]=a0=>(_sqlite3_complete=Module["_sqlite3_complete"]=wasmExports["Bd"])(a0);var _sqlite3_complete16=Module["_sqlite3_complete16"]=a0=>(_sqlite3_complete16=Module["_sqlite3_complete16"]=wasmExports["Cd"])(a0);var _sqlite3_libversion=Module["_sqlite3_libversion"]=()=>(_sqlite3_libversion=Module["_sqlite3_libversion"]=wasmExports["Dd"])();var _sqlite3_libversion_number=Module["_sqlite3_libversion_number"]=()=>(_sqlite3_libversion_number=Module["_sqlite3_libversion_number"]=wasmExports["Ed"])();var _sqlite3_threadsafe=Module["_sqlite3_threadsafe"]=()=>(_sqlite3_threadsafe=Module["_sqlite3_threadsafe"]=wasmExports["Fd"])();var _sqlite3_initialize=Module["_sqlite3_initialize"]=()=>(_sqlite3_initialize=Module["_sqlite3_initialize"]=wasmExports["Gd"])();var _sqlite3_shutdown=Module["_sqlite3_shutdown"]=()=>(_sqlite3_shutdown=Module["_sqlite3_shutdown"]=wasmExports["Hd"])();var _sqlite3_config=Module["_sqlite3_config"]=(a0,a1)=>(_sqlite3_config=Module["_sqlite3_config"]=wasmExports["Id"])(a0,a1);var _sqlite3_db_mutex=Module["_sqlite3_db_mutex"]=a0=>(_sqlite3_db_mutex=Module["_sqlite3_db_mutex"]=wasmExports["Jd"])(a0);var _sqlite3_db_release_memory=Module["_sqlite3_db_release_memory"]=a0=>(_sqlite3_db_release_memory=Module["_sqlite3_db_release_memory"]=wasmExports["Kd"])(a0);var _sqlite3_db_cacheflush=Module["_sqlite3_db_cacheflush"]=a0=>(_sqlite3_db_cacheflush=Module["_sqlite3_db_cacheflush"]=wasmExports["Ld"])(a0);var _sqlite3_db_config=Module["_sqlite3_db_config"]=(a0,a1,a2)=>(_sqlite3_db_config=Module["_sqlite3_db_config"]=wasmExports["Md"])(a0,a1,a2);var _sqlite3_last_insert_rowid=Module["_sqlite3_last_insert_rowid"]=a0=>(_sqlite3_last_insert_rowid=Module["_sqlite3_last_insert_rowid"]=wasmExports["Nd"])(a0);var _sqlite3_set_last_insert_rowid=Module["_sqlite3_set_last_insert_rowid"]=(a0,a1,a2)=>(_sqlite3_set_last_insert_rowid=Module["_sqlite3_set_last_insert_rowid"]=wasmExports["Od"])(a0,a1,a2);var _sqlite3_changes64=Module["_sqlite3_changes64"]=a0=>(_sqlite3_changes64=Module["_sqlite3_changes64"]=wasmExports["Pd"])(a0);var _sqlite3_changes=Module["_sqlite3_changes"]=a0=>(_sqlite3_changes=Module["_sqlite3_changes"]=wasmExports["Qd"])(a0);var _sqlite3_total_changes64=Module["_sqlite3_total_changes64"]=a0=>(_sqlite3_total_changes64=Module["_sqlite3_total_changes64"]=wasmExports["Rd"])(a0);var _sqlite3_total_changes=Module["_sqlite3_total_changes"]=a0=>(_sqlite3_total_changes=Module["_sqlite3_total_changes"]=wasmExports["Sd"])(a0);var _sqlite3_txn_state=Module["_sqlite3_txn_state"]=(a0,a1)=>(_sqlite3_txn_state=Module["_sqlite3_txn_state"]=wasmExports["Td"])(a0,a1);var _sqlite3_close=Module["_sqlite3_close"]=a0=>(_sqlite3_close=Module["_sqlite3_close"]=wasmExports["Ud"])(a0);var _sqlite3_close_v2=Module["_sqlite3_close_v2"]=a0=>(_sqlite3_close_v2=Module["_sqlite3_close_v2"]=wasmExports["Vd"])(a0);var _sqlite3_busy_handler=Module["_sqlite3_busy_handler"]=(a0,a1,a2)=>(_sqlite3_busy_handler=Module["_sqlite3_busy_handler"]=wasmExports["Wd"])(a0,a1,a2);var _sqlite3_progress_handler=Module["_sqlite3_progress_handler"]=(a0,a1,a2,a3)=>(_sqlite3_progress_handler=Module["_sqlite3_progress_handler"]=wasmExports["Xd"])(a0,a1,a2,a3);var _sqlite3_busy_timeout=Module["_sqlite3_busy_timeout"]=(a0,a1)=>(_sqlite3_busy_timeout=Module["_sqlite3_busy_timeout"]=wasmExports["Yd"])(a0,a1);var _sqlite3_interrupt=Module["_sqlite3_interrupt"]=a0=>(_sqlite3_interrupt=Module["_sqlite3_interrupt"]=wasmExports["Zd"])(a0);var _sqlite3_is_interrupted=Module["_sqlite3_is_interrupted"]=a0=>(_sqlite3_is_interrupted=Module["_sqlite3_is_interrupted"]=wasmExports["_d"])(a0);var _sqlite3_create_function=Module["_sqlite3_create_function"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(_sqlite3_create_function=Module["_sqlite3_create_function"]=wasmExports["$d"])(a0,a1,a2,a3,a4,a5,a6,a7);var _sqlite3_create_function_v2=Module["_sqlite3_create_function_v2"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(_sqlite3_create_function_v2=Module["_sqlite3_create_function_v2"]=wasmExports["ae"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);var _sqlite3_create_window_function=Module["_sqlite3_create_window_function"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9)=>(_sqlite3_create_window_function=Module["_sqlite3_create_window_function"]=wasmExports["be"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9);var _sqlite3_create_function16=Module["_sqlite3_create_function16"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(_sqlite3_create_function16=Module["_sqlite3_create_function16"]=wasmExports["ce"])(a0,a1,a2,a3,a4,a5,a6,a7);var _sqlite3_overload_function=Module["_sqlite3_overload_function"]=(a0,a1,a2)=>(_sqlite3_overload_function=Module["_sqlite3_overload_function"]=wasmExports["de"])(a0,a1,a2);var _sqlite3_trace_v2=Module["_sqlite3_trace_v2"]=(a0,a1,a2,a3)=>(_sqlite3_trace_v2=Module["_sqlite3_trace_v2"]=wasmExports["ee"])(a0,a1,a2,a3);var _sqlite3_commit_hook=Module["_sqlite3_commit_hook"]=(a0,a1,a2)=>(_sqlite3_commit_hook=Module["_sqlite3_commit_hook"]=wasmExports["fe"])(a0,a1,a2);var _sqlite3_update_hook=Module["_sqlite3_update_hook"]=(a0,a1,a2)=>(_sqlite3_update_hook=Module["_sqlite3_update_hook"]=wasmExports["ge"])(a0,a1,a2);var _sqlite3_rollback_hook=Module["_sqlite3_rollback_hook"]=(a0,a1,a2)=>(_sqlite3_rollback_hook=Module["_sqlite3_rollback_hook"]=wasmExports["he"])(a0,a1,a2);var _sqlite3_autovacuum_pages=Module["_sqlite3_autovacuum_pages"]=(a0,a1,a2,a3)=>(_sqlite3_autovacuum_pages=Module["_sqlite3_autovacuum_pages"]=wasmExports["ie"])(a0,a1,a2,a3);var _sqlite3_wal_autocheckpoint=Module["_sqlite3_wal_autocheckpoint"]=(a0,a1)=>(_sqlite3_wal_autocheckpoint=Module["_sqlite3_wal_autocheckpoint"]=wasmExports["je"])(a0,a1);var _sqlite3_wal_hook=Module["_sqlite3_wal_hook"]=(a0,a1,a2)=>(_sqlite3_wal_hook=Module["_sqlite3_wal_hook"]=wasmExports["ke"])(a0,a1,a2);var _sqlite3_wal_checkpoint_v2=Module["_sqlite3_wal_checkpoint_v2"]=(a0,a1,a2,a3,a4)=>(_sqlite3_wal_checkpoint_v2=Module["_sqlite3_wal_checkpoint_v2"]=wasmExports["le"])(a0,a1,a2,a3,a4);var _sqlite3_wal_checkpoint=Module["_sqlite3_wal_checkpoint"]=(a0,a1)=>(_sqlite3_wal_checkpoint=Module["_sqlite3_wal_checkpoint"]=wasmExports["me"])(a0,a1);var _sqlite3_error_offset=Module["_sqlite3_error_offset"]=a0=>(_sqlite3_error_offset=Module["_sqlite3_error_offset"]=wasmExports["ne"])(a0);var _sqlite3_errmsg16=Module["_sqlite3_errmsg16"]=a0=>(_sqlite3_errmsg16=Module["_sqlite3_errmsg16"]=wasmExports["oe"])(a0);var _sqlite3_errcode=Module["_sqlite3_errcode"]=a0=>(_sqlite3_errcode=Module["_sqlite3_errcode"]=wasmExports["pe"])(a0);var _sqlite3_extended_errcode=Module["_sqlite3_extended_errcode"]=a0=>(_sqlite3_extended_errcode=Module["_sqlite3_extended_errcode"]=wasmExports["qe"])(a0);var _sqlite3_system_errno=Module["_sqlite3_system_errno"]=a0=>(_sqlite3_system_errno=Module["_sqlite3_system_errno"]=wasmExports["re"])(a0);var _sqlite3_errstr=Module["_sqlite3_errstr"]=a0=>(_sqlite3_errstr=Module["_sqlite3_errstr"]=wasmExports["se"])(a0);var _sqlite3_limit=Module["_sqlite3_limit"]=(a0,a1,a2)=>(_sqlite3_limit=Module["_sqlite3_limit"]=wasmExports["te"])(a0,a1,a2);var _sqlite3_open=Module["_sqlite3_open"]=(a0,a1)=>(_sqlite3_open=Module["_sqlite3_open"]=wasmExports["ue"])(a0,a1);var _sqlite3_open_v2=Module["_sqlite3_open_v2"]=(a0,a1,a2,a3)=>(_sqlite3_open_v2=Module["_sqlite3_open_v2"]=wasmExports["ve"])(a0,a1,a2,a3);var _sqlite3_open16=Module["_sqlite3_open16"]=(a0,a1)=>(_sqlite3_open16=Module["_sqlite3_open16"]=wasmExports["we"])(a0,a1);var _sqlite3_create_collation=Module["_sqlite3_create_collation"]=(a0,a1,a2,a3,a4)=>(_sqlite3_create_collation=Module["_sqlite3_create_collation"]=wasmExports["xe"])(a0,a1,a2,a3,a4);var _sqlite3_create_collation_v2=Module["_sqlite3_create_collation_v2"]=(a0,a1,a2,a3,a4,a5)=>(_sqlite3_create_collation_v2=Module["_sqlite3_create_collation_v2"]=wasmExports["ye"])(a0,a1,a2,a3,a4,a5);var _sqlite3_create_collation16=Module["_sqlite3_create_collation16"]=(a0,a1,a2,a3,a4)=>(_sqlite3_create_collation16=Module["_sqlite3_create_collation16"]=wasmExports["ze"])(a0,a1,a2,a3,a4);var _sqlite3_collation_needed=Module["_sqlite3_collation_needed"]=(a0,a1,a2)=>(_sqlite3_collation_needed=Module["_sqlite3_collation_needed"]=wasmExports["Ae"])(a0,a1,a2);var _sqlite3_collation_needed16=Module["_sqlite3_collation_needed16"]=(a0,a1,a2)=>(_sqlite3_collation_needed16=Module["_sqlite3_collation_needed16"]=wasmExports["Be"])(a0,a1,a2);var _sqlite3_get_clientdata=Module["_sqlite3_get_clientdata"]=(a0,a1)=>(_sqlite3_get_clientdata=Module["_sqlite3_get_clientdata"]=wasmExports["Ce"])(a0,a1);var _sqlite3_set_clientdata=Module["_sqlite3_set_clientdata"]=(a0,a1,a2,a3)=>(_sqlite3_set_clientdata=Module["_sqlite3_set_clientdata"]=wasmExports["De"])(a0,a1,a2,a3);var _sqlite3_get_autocommit=Module["_sqlite3_get_autocommit"]=a0=>(_sqlite3_get_autocommit=Module["_sqlite3_get_autocommit"]=wasmExports["Ee"])(a0);var _sqlite3_table_column_metadata=Module["_sqlite3_table_column_metadata"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(_sqlite3_table_column_metadata=Module["_sqlite3_table_column_metadata"]=wasmExports["Fe"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);var _sqlite3_sleep=Module["_sqlite3_sleep"]=a0=>(_sqlite3_sleep=Module["_sqlite3_sleep"]=wasmExports["Ge"])(a0);var _sqlite3_extended_result_codes=Module["_sqlite3_extended_result_codes"]=(a0,a1)=>(_sqlite3_extended_result_codes=Module["_sqlite3_extended_result_codes"]=wasmExports["He"])(a0,a1);var _sqlite3_file_control=Module["_sqlite3_file_control"]=(a0,a1,a2,a3)=>(_sqlite3_file_control=Module["_sqlite3_file_control"]=wasmExports["Ie"])(a0,a1,a2,a3);var _sqlite3_test_control=Module["_sqlite3_test_control"]=(a0,a1)=>(_sqlite3_test_control=Module["_sqlite3_test_control"]=wasmExports["Je"])(a0,a1);var _sqlite3_create_filename=Module["_sqlite3_create_filename"]=(a0,a1,a2,a3,a4)=>(_sqlite3_create_filename=Module["_sqlite3_create_filename"]=wasmExports["Ke"])(a0,a1,a2,a3,a4);var _sqlite3_free_filename=Module["_sqlite3_free_filename"]=a0=>(_sqlite3_free_filename=Module["_sqlite3_free_filename"]=wasmExports["Le"])(a0);var _sqlite3_uri_parameter=Module["_sqlite3_uri_parameter"]=(a0,a1)=>(_sqlite3_uri_parameter=Module["_sqlite3_uri_parameter"]=wasmExports["Me"])(a0,a1);var _sqlite3_uri_key=Module["_sqlite3_uri_key"]=(a0,a1)=>(_sqlite3_uri_key=Module["_sqlite3_uri_key"]=wasmExports["Ne"])(a0,a1);var _sqlite3_uri_boolean=Module["_sqlite3_uri_boolean"]=(a0,a1,a2)=>(_sqlite3_uri_boolean=Module["_sqlite3_uri_boolean"]=wasmExports["Oe"])(a0,a1,a2);var _sqlite3_uri_int64=Module["_sqlite3_uri_int64"]=(a0,a1,a2,a3)=>(_sqlite3_uri_int64=Module["_sqlite3_uri_int64"]=wasmExports["Pe"])(a0,a1,a2,a3);var _sqlite3_filename_database=Module["_sqlite3_filename_database"]=a0=>(_sqlite3_filename_database=Module["_sqlite3_filename_database"]=wasmExports["Qe"])(a0);var _sqlite3_filename_journal=Module["_sqlite3_filename_journal"]=a0=>(_sqlite3_filename_journal=Module["_sqlite3_filename_journal"]=wasmExports["Re"])(a0);var _sqlite3_filename_wal=Module["_sqlite3_filename_wal"]=a0=>(_sqlite3_filename_wal=Module["_sqlite3_filename_wal"]=wasmExports["Se"])(a0);var _sqlite3_db_name=Module["_sqlite3_db_name"]=(a0,a1)=>(_sqlite3_db_name=Module["_sqlite3_db_name"]=wasmExports["Te"])(a0,a1);var _sqlite3_db_filename=Module["_sqlite3_db_filename"]=(a0,a1)=>(_sqlite3_db_filename=Module["_sqlite3_db_filename"]=wasmExports["Ue"])(a0,a1);var _sqlite3_db_readonly=Module["_sqlite3_db_readonly"]=(a0,a1)=>(_sqlite3_db_readonly=Module["_sqlite3_db_readonly"]=wasmExports["Ve"])(a0,a1);var _sqlite3_compileoption_used=Module["_sqlite3_compileoption_used"]=a0=>(_sqlite3_compileoption_used=Module["_sqlite3_compileoption_used"]=wasmExports["We"])(a0);var _sqlite3_compileoption_get=Module["_sqlite3_compileoption_get"]=a0=>(_sqlite3_compileoption_get=Module["_sqlite3_compileoption_get"]=wasmExports["Xe"])(a0);var _sqlite3_sourceid=Module["_sqlite3_sourceid"]=()=>(_sqlite3_sourceid=Module["_sqlite3_sourceid"]=wasmExports["Ye"])();var _malloc=Module["_malloc"]=a0=>(_malloc=Module["_malloc"]=wasmExports["Ze"])(a0);var _free=Module["_free"]=a0=>(_free=Module["_free"]=wasmExports["_e"])(a0);var _RegisterExtensionFunctions=Module["_RegisterExtensionFunctions"]=a0=>(_RegisterExtensionFunctions=Module["_RegisterExtensionFunctions"]=wasmExports["$e"])(a0);var _getSqliteFree=Module["_getSqliteFree"]=()=>(_getSqliteFree=Module["_getSqliteFree"]=wasmExports["af"])();var _main=Module["_main"]=(a0,a1)=>(_main=Module["_main"]=wasmExports["bf"])(a0,a1);var _libauthorizer_set_authorizer=Module["_libauthorizer_set_authorizer"]=(a0,a1,a2)=>(_libauthorizer_set_authorizer=Module["_libauthorizer_set_authorizer"]=wasmExports["cf"])(a0,a1,a2);var _libfunction_create_function=Module["_libfunction_create_function"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(_libfunction_create_function=Module["_libfunction_create_function"]=wasmExports["df"])(a0,a1,a2,a3,a4,a5,a6,a7);var _libhook_update_hook=Module["_libhook_update_hook"]=(a0,a1,a2)=>(_libhook_update_hook=Module["_libhook_update_hook"]=wasmExports["ef"])(a0,a1,a2);var _libprogress_progress_handler=Module["_libprogress_progress_handler"]=(a0,a1,a2,a3)=>(_libprogress_progress_handler=Module["_libprogress_progress_handler"]=wasmExports["ff"])(a0,a1,a2,a3);var _libvfs_vfs_register=Module["_libvfs_vfs_register"]=(a0,a1,a2,a3,a4,a5)=>(_libvfs_vfs_register=Module["_libvfs_vfs_register"]=wasmExports["gf"])(a0,a1,a2,a3,a4,a5);var _emscripten_builtin_memalign=(a0,a1)=>(_emscripten_builtin_memalign=wasmExports["jf"])(a0,a1);var __emscripten_timeout=(a0,a1)=>(__emscripten_timeout=wasmExports["kf"])(a0,a1);var __emscripten_tempret_get=()=>(__emscripten_tempret_get=wasmExports["lf"])();var __emscripten_stack_restore=a0=>(__emscripten_stack_restore=wasmExports["mf"])(a0);var __emscripten_stack_alloc=a0=>(__emscripten_stack_alloc=wasmExports["nf"])(a0);var _emscripten_stack_get_current=()=>(_emscripten_stack_get_current=wasmExports["of"])();var _sqlite3_version=Module["_sqlite3_version"]=5472;Module["getTempRet0"]=getTempRet0;Module["ccall"]=ccall;Module["cwrap"]=cwrap;Module["addFunction"]=addFunction;Module["setValue"]=setValue;Module["getValue"]=getValue;Module["UTF8ToString"]=UTF8ToString;Module["stringToUTF8"]=stringToUTF8;Module["lengthBytesUTF8"]=lengthBytesUTF8;Module["intArrayFromString"]=intArrayFromString;Module["intArrayToString"]=intArrayToString;Module["AsciiToString"]=AsciiToString;Module["UTF16ToString"]=UTF16ToString;Module["stringToUTF16"]=stringToUTF16;Module["UTF32ToString"]=UTF32ToString;Module["stringToUTF32"]=stringToUTF32;Module["writeArrayToMemory"]=writeArrayToMemory;var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function callMain(){var entryFunction=_main;var argc=0;var argv=0;try{var ret=entryFunction(argc,argv);exitJS(ret,true);return ret}catch(e){return handleException(e)}}function run(){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();readyPromiseResolve(Module);Module["onRuntimeInitialized"]?.();if(shouldRunNow)callMain();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(()=>{setTimeout(()=>Module["setStatus"](""),1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}var shouldRunNow=true;if(Module["noInitialRun"])shouldRunNow=false;run();(function(){const AsyncFunction=Object.getPrototypeOf(async function(){}).constructor;let pAsyncFlags=0;Module["set_authorizer"]=function(db,xAuthorizer,pApp){if(pAsyncFlags){Module["deleteCallback"](pAsyncFlags);Module["_sqlite3_free"](pAsyncFlags);pAsyncFlags=0}pAsyncFlags=Module["_sqlite3_malloc"](4);setValue(pAsyncFlags,xAuthorizer instanceof AsyncFunction?1:0,"i32");const result=ccall("libauthorizer_set_authorizer","number",["number","number","number"],[db,xAuthorizer?1:0,pAsyncFlags]);if(!result&&xAuthorizer){Module["setCallback"](pAsyncFlags,(_,iAction,p3,p4,p5,p6)=>xAuthorizer(pApp,iAction,p3,p4,p5,p6))}return result}})();(function(){const AsyncFunction=Object.getPrototypeOf(async function(){}).constructor;const FUNC_METHODS=["xFunc","xStep","xFinal"];const mapFunctionNameToKey=new Map;Module["create_function"]=function(db,zFunctionName,nArg,eTextRep,pApp,xFunc,xStep,xFinal){const pAsyncFlags=Module["_sqlite3_malloc"](4);const target={xFunc,xStep,xFinal};setValue(pAsyncFlags,FUNC_METHODS.reduce((mask,method,i)=>{if(target[method]instanceof AsyncFunction){return mask|1<xUpdateHook(iUpdateType,dbName,tblName,lo32,hi32))}}})();(function(){const AsyncFunction=Object.getPrototypeOf(async function(){}).constructor;let pAsyncFlags=0;Module["progress_handler"]=function(db,nOps,xProgress,pApp){if(pAsyncFlags){Module["deleteCallback"](pAsyncFlags);Module["_sqlite3_free"](pAsyncFlags);pAsyncFlags=0}pAsyncFlags=Module["_sqlite3_malloc"](4);setValue(pAsyncFlags,xProgress instanceof AsyncFunction?1:0,"i32");ccall("libprogress_progress_handler","number",["number","number","number","number"],[db,nOps,xProgress?1:0,pAsyncFlags]);if(xProgress){Module["setCallback"](pAsyncFlags,_=>xProgress(pApp))}}})();(function(){const VFS_METHODS=["xOpen","xDelete","xAccess","xFullPathname","xRandomness","xSleep","xCurrentTime","xGetLastError","xCurrentTimeInt64","xClose","xRead","xWrite","xTruncate","xSync","xFileSize","xLock","xUnlock","xCheckReservedLock","xFileControl","xSectorSize","xDeviceCharacteristics","xShmMap","xShmLock","xShmBarrier","xShmUnmap"];const mapVFSNameToKey=new Map;Module["vfs_register"]=function(vfs,makeDefault){let methodMask=0;let asyncMask=0;VFS_METHODS.forEach((method,i)=>{if(vfs[method]){methodMask|=1<>, config = {} ): Promise { - if (getIssuesShouldFallbackToServer(queries) || this.serviceType !== EIssueServiceType.ISSUES) { - return await this.getIssuesFromServer(workspaceSlug, projectId, queries, config); - } - const { persistence } = await import("@/local-db/storage.sqlite"); - const response = await persistence.getIssues(workspaceSlug, projectId, queries, config); - return response as TIssuesResponse; + return this.getIssuesFromServer(workspaceSlug, projectId, queries, config); } async getDeletedIssues(workspaceSlug: string, projectId: string, queries?: any): Promise { @@ -115,11 +109,6 @@ export class IssueService extends APIService { params: queries, }) .then(async (response) => { - // skip issue update when the service type is epic - if (response.data && this.serviceType === EIssueServiceType.ISSUES) { - const { updateIssue } = await import("@/local-db/utils/load-issues"); - updateIssue({ ...response.data, is_local_update: 1 }); - } // add is_epic flag when the service type is epic if (response.data && this.serviceType === EIssueServiceType.EPICS) { response.data.is_epic = true; @@ -135,13 +124,7 @@ export class IssueService extends APIService { return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/list/`, { params: { issues: issueIds.join(",") }, }) - .then(async (response) => { - if (response?.data && Array.isArray(response?.data) && this.serviceType === EIssueServiceType.ISSUES) { - const { addIssuesBulk } = await import("@/local-db/utils/load-issues"); - addIssuesBulk(response.data); - } - return response?.data; - }) + .then(async (response) => response?.data) .catch((error) => { throw error?.response?.data; }); @@ -243,10 +226,6 @@ export class IssueService extends APIService { } async deleteIssue(workspaceSlug: string, projectId: string, issuesId: string): Promise { - if (this.serviceType === EIssueServiceType.ISSUES) { - const { deleteIssueFromLocal } = await import("@/local-db/utils/load-issues"); - deleteIssueFromLocal(issuesId); - } return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/${this.serviceType}/${issuesId}/`) .then((response) => response?.data) .catch((error) => { @@ -353,13 +332,7 @@ export class IssueService extends APIService { async bulkOperations(workspaceSlug: string, projectId: string, data: TBulkOperationsPayload): Promise { return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/bulk-operation-issues/`, data) - .then(async (response) => { - if (this.serviceType === EIssueServiceType.ISSUES) { - const { persistence } = await import("@/local-db/storage.sqlite"); - persistence.syncIssues(projectId); - } - return response?.data; - }) + .then(async (response) => response?.data) .catch((error) => { throw error?.response?.data; }); @@ -373,13 +346,7 @@ export class IssueService extends APIService { } ): Promise { return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/bulk-delete-issues/`, data) - .then(async (response) => { - if (this.serviceType === EIssueServiceType.ISSUES) { - const { persistence } = await import("@/local-db/storage.sqlite"); - persistence.syncIssues(projectId); - } - return response?.data; - }) + .then(async (response) => response?.data) .catch((error) => { throw error?.response?.data; }); @@ -395,13 +362,7 @@ export class IssueService extends APIService { archived_at: string; }> { return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/bulk-archive-issues/`, data) - .then(async (response) => { - if (this.serviceType === EIssueServiceType.ISSUES) { - const { persistence } = await import("@/local-db/storage.sqlite"); - persistence.syncIssues(projectId); - } - return response?.data; - }) + .then(async (response) => response?.data) .catch((error) => { throw error?.response?.data; }); @@ -479,11 +440,6 @@ export class IssueService extends APIService { params: queries, }) .then(async (response) => { - // skip issue update when the service type is epic - if (response.data && this.serviceType === EIssueServiceType.ISSUES) { - const { updateIssue } = await import("@/local-db/utils/load-issues"); - updateIssue({ ...response.data, is_local_update: 1 }); - } // add is_epic flag when the service type is epic if (response.data && this.serviceType === EIssueServiceType.EPICS) { response.data.is_epic = true; diff --git a/apps/web/core/store/cycle.store.ts b/apps/web/core/store/cycle.store.ts index 3495834caa..e39ad44125 100644 --- a/apps/web/core/store/cycle.store.ts +++ b/apps/web/core/store/cycle.store.ts @@ -15,7 +15,6 @@ import type { DistributionUpdates } from "@plane/utils"; import { orderCycles, shouldFilterCycle, getDate, updateDistribution } from "@plane/utils"; // helpers // services -import { syncIssuesWithDeletedCycles } from "@/local-db/utils/load-workspace"; import { CycleService } from "@/services/cycle.service"; import { CycleArchiveService } from "@/services/cycle_archive.service"; import { IssueService } from "@/services/issue"; @@ -618,7 +617,6 @@ export class CycleStore implements ICycleStore { delete this.cycleMap[cycleId]; delete this.activeCycleIdMap[cycleId]; if (this.rootStore.favorite.entityMap[cycleId]) this.rootStore.favorite.removeFavoriteFromStore(cycleId); - syncIssuesWithDeletedCycles([cycleId]); }); }); diff --git a/apps/web/core/store/inbox/inbox-issue.store.ts b/apps/web/core/store/inbox/inbox-issue.store.ts index c555a09024..5c099a6688 100644 --- a/apps/web/core/store/inbox/inbox-issue.store.ts +++ b/apps/web/core/store/inbox/inbox-issue.store.ts @@ -9,8 +9,6 @@ import type { } from "@plane/types"; import { EInboxIssueStatus } from "@plane/types"; // helpers -// local db -import { addIssueToPersistanceLayer } from "@/local-db/utils/utils"; // services import { InboxIssueService } from "@/services/inbox"; import { IssueService } from "@/services/issue"; @@ -109,7 +107,6 @@ export class InboxIssueStore implements IInboxIssueStore { if (status === EInboxIssueStatus.ACCEPTED) { const updatedIssue = { ...this.issue, ...inboxIssue.issue }; this.store.issue.issues.addIssue([updatedIssue]); - await addIssueToPersistanceLayer(updatedIssue); } } catch { runInAction(() => set(this, "status", previousData.status)); diff --git a/apps/web/core/store/issue/cycle/filter.store.ts b/apps/web/core/store/issue/cycle/filter.store.ts index 27b8d176e6..c5234b9826 100644 --- a/apps/web/core/store/issue/cycle/filter.store.ts +++ b/apps/web/core/store/issue/cycle/filter.store.ts @@ -243,7 +243,7 @@ export class CycleIssuesFilter extends IssueFilterHelperStore implements ICycleI }); if (this.getShouldClearIssues(updatedDisplayFilters)) { - this.rootIssueStore.cycleIssues.clear(true, true); // clear issues for local store when some filters like layout changes + this.rootIssueStore.cycleIssues.clear(true); // clear issues for local store when some filters like layout changes } if (this.getShouldReFetchIssues(updatedDisplayFilters)) { diff --git a/apps/web/core/store/issue/cycle/issue.store.ts b/apps/web/core/store/issue/cycle/issue.store.ts index 0b739b4891..00f7309e4e 100644 --- a/apps/web/core/store/issue/cycle/issue.store.ts +++ b/apps/web/core/store/issue/cycle/issue.store.ts @@ -15,7 +15,6 @@ import type { import { getDistributionPathsPostUpdate } from "@plane/utils"; //local import { storage } from "@/lib/local-storage"; -import { persistence } from "@/local-db/storage.sqlite"; import type { IBaseIssuesStore } from "../helpers/base-issues.store"; import { BaseIssuesStore } from "../helpers/base-issues.store"; // @@ -190,8 +189,7 @@ export class CycleIssues extends BaseIssuesStore implements ICycleIssues { // set loader and clear store runInAction(() => { this.setLoader(loadType); - this.clear(!isExistingPaginationOptions, false); // clear while fetching from server. - if (!this.groupBy) this.clear(!isExistingPaginationOptions, true); // clear while using local to have the no load effect. + this.clear(!isExistingPaginationOptions); // clear while fetching from server. }); // get params from pagination options @@ -315,7 +313,6 @@ export class CycleIssues extends BaseIssuesStore implements ICycleIssues { ); // call fetch issues if (this.paginationOptions) { - await persistence.syncIssues(projectId.toString()); await this.fetchIssues(workspaceSlug, projectId, "mutation", this.paginationOptions, cycleId); } diff --git a/apps/web/core/store/issue/helpers/base-issues.store.ts b/apps/web/core/store/issue/helpers/base-issues.store.ts index f9e0f7207c..b0d6b3bf79 100644 --- a/apps/web/core/store/issue/helpers/base-issues.store.ts +++ b/apps/web/core/store/issue/helpers/base-issues.store.ts @@ -23,9 +23,7 @@ import type { import { EIssueServiceType, EIssueLayoutTypes } from "@plane/types"; // helpers import { convertToISODateString } from "@plane/utils"; -// local-db -import { SPECIAL_ORDER_BY } from "@/local-db/utils/query-constructor"; -import { updatePersistentLayer } from "@/local-db/utils/utils"; +// plane web imports import { workItemSortWithOrderByExtended } from "@/plane-web/store/issue/helpers/base-issue.store"; // services import { CycleService } from "@/services/cycle.service"; @@ -60,7 +58,7 @@ export interface IBaseIssuesStore { //actions removeIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise; - clear(shouldClearPaginationOptions?: boolean, clearForLocal?: boolean): void; + clear(shouldClearPaginationOptions?: boolean): void; // helper methods getIssueIds: (groupId?: string, subGroupId?: string) => string[] | undefined; issuesSortWithOrderBy(issueIds: string[], key: Partial): string[]; @@ -281,13 +279,7 @@ export abstract class BaseIssuesStore implements IBaseIssuesStore { const orderBy = displayFilters.order_by; // Temporary code to fix no load order by - if ( - this.rootIssueStore.rootStore.user.localDBEnabled && - this.rootIssueStore.rootStore.router.projectId && - layout !== EIssueLayoutTypes.SPREADSHEET && - orderBy && - Object.keys(SPECIAL_ORDER_BY).includes(orderBy) - ) { + if (this.rootIssueStore.rootStore.router.projectId && layout !== EIssueLayoutTypes.SPREADSHEET && orderBy) { return "sort_order"; } @@ -483,7 +475,7 @@ export abstract class BaseIssuesStore implements IBaseIssuesStore { // Update all the GroupIds to this Store's groupedIssueIds and update Individual group issue counts runInAction(() => { - this.clear(shouldClearPaginationOptions, true); + this.clear(shouldClearPaginationOptions); this.updateGroupedIssueIds(groupedIssues, groupedIssueCount); this.loader[getGroupKey()] = undefined; }); @@ -549,8 +541,6 @@ export abstract class BaseIssuesStore implements IBaseIssuesStore { // If shouldUpdateList is true, call fetchParentStats shouldUpdateList && (await this.fetchParentStats(workspaceSlug, projectId)); - updatePersistentLayer(response.id); - return response; } @@ -1162,22 +1152,17 @@ export abstract class BaseIssuesStore implements IBaseIssuesStore { /** * Method called to clear out the current store */ - clear(shouldClearPaginationOptions = true, clearForLocal = false) { - if ( - (this.rootIssueStore.rootStore.user?.localDBEnabled && clearForLocal) || - (!this.rootIssueStore.rootStore.user?.localDBEnabled && !clearForLocal) - ) { - runInAction(() => { - this.groupedIssueIds = undefined; - this.issuePaginationData = {}; - this.groupedIssueCount = {}; - if (shouldClearPaginationOptions) { - this.paginationOptions = undefined; - } - }); - this.controller.abort(); - this.controller = new AbortController(); - } + clear(shouldClearPaginationOptions = true) { + runInAction(() => { + this.groupedIssueIds = undefined; + this.issuePaginationData = {}; + this.groupedIssueCount = {}; + if (shouldClearPaginationOptions) { + this.paginationOptions = undefined; + } + }); + this.controller.abort(); + this.controller = new AbortController(); } /** diff --git a/apps/web/core/store/issue/issue-details/issue.store.ts b/apps/web/core/store/issue/issue-details/issue.store.ts index a5c7eb5174..3533038bac 100644 --- a/apps/web/core/store/issue/issue-details/issue.store.ts +++ b/apps/web/core/store/issue/issue-details/issue.store.ts @@ -3,8 +3,6 @@ import { computedFn } from "mobx-utils"; // types import type { TIssue, TIssueServiceType } from "@plane/types"; import { EIssueServiceType } from "@plane/types"; -// local -import { persistence } from "@/local-db/storage.sqlite"; // services import { IssueArchiveService, WorkspaceDraftService, IssueService } from "@/services/issue"; // types @@ -32,7 +30,6 @@ export interface IIssueStoreActions { export interface IIssueStore extends IIssueStoreActions { getIsFetchingIssueDetails: (issueId: string | undefined) => boolean; - getIsLocalDBIssueDescription: (issueId: string | undefined) => boolean; // helper methods getIssueById: (issueId: string) => TIssue | undefined; getIssueIdByIdentifier: (issueIdentifier: string) => string | undefined; @@ -40,7 +37,6 @@ export interface IIssueStore extends IIssueStoreActions { export class IssueStore implements IIssueStore { fetchingIssueDetails: string | undefined = undefined; - localDBIssueDescription: string | undefined = undefined; // root store rootIssueDetailStore: IIssueDetail; // services @@ -53,7 +49,6 @@ export class IssueStore implements IIssueStore { constructor(rootStore: IIssueDetail, serviceType: TIssueServiceType) { makeObservable(this, { fetchingIssueDetails: observable.ref, - localDBIssueDescription: observable.ref, }); // root store this.rootIssueDetailStore = rootStore; @@ -71,12 +66,6 @@ export class IssueStore implements IIssueStore { return this.fetchingIssueDetails === issueId; }); - getIsLocalDBIssueDescription = computedFn((issueId: string | undefined) => { - if (!issueId) return false; - - return this.localDBIssueDescription === issueId; - }); - // helper methods getIssueById = computedFn((issueId: string) => { if (!issueId) return undefined; @@ -94,26 +83,12 @@ export class IssueStore implements IIssueStore { expand: "issue_reactions,issue_attachments,issue_link,parent", }; - let issue: TIssue | undefined; - - // fetch issue from local db - if (this.serviceType === EIssueServiceType.ISSUES) { - issue = await persistence.getIssue(issueId); - } - this.fetchingIssueDetails = issueId; - - if (issue) { - this.addIssueToStore(issue); - this.localDBIssueDescription = issueId; - } - - issue = await this.issueService.retrieve(workspaceSlug, projectId, issueId, query); + const issue = await this.issueService.retrieve(workspaceSlug, projectId, issueId, query); if (!issue) throw new Error("Work item not found"); const issuePayload = this.addIssueToStore(issue); - this.localDBIssueDescription = undefined; this.rootIssueDetailStore.rootIssueStore.issues.addIssue([issuePayload]); diff --git a/apps/web/core/store/issue/issue-details/sub_issues.store.ts b/apps/web/core/store/issue/issue-details/sub_issues.store.ts index dd3aeaebff..18a833d19c 100644 --- a/apps/web/core/store/issue/issue-details/sub_issues.store.ts +++ b/apps/web/core/store/issue/issue-details/sub_issues.store.ts @@ -11,9 +11,7 @@ import type { TIssueServiceType, TLoader, } from "@plane/types"; -import { EIssueServiceType } from "@plane/types"; // services -import { updatePersistentLayer } from "@/local-db/utils/utils"; import { IssueService } from "@/services/issue"; // store import type { IIssueDetail } from "./root.store"; @@ -198,10 +196,6 @@ export class IssueSubIssuesStore implements IIssueSubIssuesStore { this.subIssues[parentIssueId].length ); - if (this.serviceType === EIssueServiceType.ISSUES) { - updatePersistentLayer([parentIssueId, ...issueIds]); - } - return; }; @@ -298,10 +292,6 @@ export class IssueSubIssuesStore implements IIssueSubIssuesStore { ); }); - if (this.serviceType === EIssueServiceType.ISSUES) { - updatePersistentLayer([parentIssueId]); - } - return; }; @@ -335,10 +325,6 @@ export class IssueSubIssuesStore implements IIssueSubIssuesStore { ); }); - if (this.serviceType === EIssueServiceType.ISSUES) { - updatePersistentLayer([parentIssueId]); - } - return; }; diff --git a/apps/web/core/store/issue/issue.store.ts b/apps/web/core/store/issue/issue.store.ts index d7cd0e6e71..8d6e9b7ab0 100644 --- a/apps/web/core/store/issue/issue.store.ts +++ b/apps/web/core/store/issue/issue.store.ts @@ -1,4 +1,4 @@ -import { clone, set, update } from "lodash-es"; +import { set, update } from "lodash-es"; import { action, makeObservable, observable, runInAction } from "mobx"; import { computedFn } from "mobx-utils"; // types @@ -7,8 +7,6 @@ import type { TIssue } from "@plane/types"; import { getCurrentDateTimeInISO } from "@plane/utils"; import { rootStore } from "@/lib/store-context"; // services -import { deleteIssueFromLocal } from "@/local-db/utils/load-issues"; -import { updatePersistentLayer } from "@/local-db/utils/utils"; import { IssueService } from "@/services/issue"; export type IIssueStore = { @@ -103,17 +101,12 @@ export class IssueStore implements IIssueStore { */ updateIssue = (issueId: string, issue: Partial) => { if (!issue || !issueId || !this.issuesMap[issueId]) return; - const issueBeforeUpdate = clone(this.issuesMap[issueId]); runInAction(() => { set(this.issuesMap, [issueId, "updated_at"], getCurrentDateTimeInISO()); Object.keys(issue).forEach((key) => { set(this.issuesMap, [issueId, key], issue[key as keyof TIssue]); }); }); - - if (!issueBeforeUpdate.is_epic) { - updatePersistentLayer(issueId); - } }; /** @@ -126,7 +119,6 @@ export class IssueStore implements IIssueStore { runInAction(() => { delete this.issuesMap[issueId]; }); - deleteIssueFromLocal(issueId); }; // helper methods diff --git a/apps/web/core/store/issue/module/filter.store.ts b/apps/web/core/store/issue/module/filter.store.ts index b82186fa11..42d18c8f51 100644 --- a/apps/web/core/store/issue/module/filter.store.ts +++ b/apps/web/core/store/issue/module/filter.store.ts @@ -248,7 +248,7 @@ export class ModuleIssuesFilter extends IssueFilterHelperStore implements IModul }); if (this.getShouldClearIssues(updatedDisplayFilters)) { - this.rootIssueStore.moduleIssues.clear(true, true); // clear issues for local store when some filters like layout changes + this.rootIssueStore.moduleIssues.clear(true); // clear issues for local store when some filters like layout changes } if (this.getShouldReFetchIssues(updatedDisplayFilters)) { diff --git a/apps/web/core/store/issue/module/issue.store.ts b/apps/web/core/store/issue/module/issue.store.ts index 8caf6b9af5..540d0aa940 100644 --- a/apps/web/core/store/issue/module/issue.store.ts +++ b/apps/web/core/store/issue/module/issue.store.ts @@ -137,8 +137,7 @@ export class ModuleIssues extends BaseIssuesStore implements IModuleIssues { // set loader and clear store runInAction(() => { this.setLoader(loadType); - this.clear(!isExistingPaginationOptions, false); // clear while fetching from server. - if (!this.groupBy) this.clear(!isExistingPaginationOptions, true); // clear while using local to have the no load effect. + this.clear(!isExistingPaginationOptions); // clear while fetching from server. }); // get params from pagination options diff --git a/apps/web/core/store/issue/project-views/filter.store.ts b/apps/web/core/store/issue/project-views/filter.store.ts index 08a1ea2194..ca7f9e6099 100644 --- a/apps/web/core/store/issue/project-views/filter.store.ts +++ b/apps/web/core/store/issue/project-views/filter.store.ts @@ -257,7 +257,7 @@ export class ProjectViewIssuesFilter extends IssueFilterHelperStore implements I }); if (this.getShouldClearIssues(updatedDisplayFilters)) { - this.rootIssueStore.projectIssues.clear(true, true); // clear issues for local store when some filters like layout changes + this.rootIssueStore.projectIssues.clear(true); // clear issues for local store when some filters like layout changes } if (this.getShouldReFetchIssues(updatedDisplayFilters)) { diff --git a/apps/web/core/store/issue/project-views/issue.store.ts b/apps/web/core/store/issue/project-views/issue.store.ts index d4e52df99c..2d80462645 100644 --- a/apps/web/core/store/issue/project-views/issue.store.ts +++ b/apps/web/core/store/issue/project-views/issue.store.ts @@ -94,8 +94,7 @@ export class ProjectViewIssues extends BaseIssuesStore implements IProjectViewIs // set loader and clear store runInAction(() => { this.setLoader(loadType); - this.clear(!isExistingPaginationOptions, false); // clear while fetching from server. - if (!this.groupBy) this.clear(!isExistingPaginationOptions, true); // clear while using local to have the no load effect. + this.clear(!isExistingPaginationOptions); // clear while fetching from server. }); // get params from pagination options diff --git a/apps/web/core/store/issue/project/filter.store.ts b/apps/web/core/store/issue/project/filter.store.ts index 9c1a662302..28af59adfd 100644 --- a/apps/web/core/store/issue/project/filter.store.ts +++ b/apps/web/core/store/issue/project/filter.store.ts @@ -231,7 +231,7 @@ export class ProjectIssuesFilter extends IssueFilterHelperStore implements IProj }); if (this.getShouldClearIssues(updatedDisplayFilters)) { - this.rootIssueStore.projectIssues.clear(true, true); // clear issues for local store when some filters like layout changes + this.rootIssueStore.projectIssues.clear(true); // clear issues for local store when some filters like layout changes } if (this.getShouldReFetchIssues(updatedDisplayFilters)) { diff --git a/apps/web/core/store/issue/project/issue.store.ts b/apps/web/core/store/issue/project/issue.store.ts index 78a4d6b1f1..a36a583915 100644 --- a/apps/web/core/store/issue/project/issue.store.ts +++ b/apps/web/core/store/issue/project/issue.store.ts @@ -102,8 +102,7 @@ export class ProjectIssues extends BaseIssuesStore implements IProjectIssues { // set loader and clear store runInAction(() => { this.setLoader(loadType); - this.clear(!isExistingPaginationOptions, false); // clear while fetching from server. - if (!this.groupBy) this.clear(!isExistingPaginationOptions, true); // clear while using local to have the no load effect. + this.clear(!isExistingPaginationOptions); // clear while fetching from server. }); // get params from pagination options diff --git a/apps/web/core/store/issue/workspace-draft/issue.store.ts b/apps/web/core/store/issue/workspace-draft/issue.store.ts index 38dfe6a5bc..4c8033f646 100644 --- a/apps/web/core/store/issue/workspace-draft/issue.store.ts +++ b/apps/web/core/store/issue/workspace-draft/issue.store.ts @@ -17,8 +17,6 @@ import type { TBulkOperationsPayload, } from "@plane/types"; import { getCurrentDateTimeInISO, convertToISODateString } from "@plane/utils"; -// local-db -import { addIssueToPersistanceLayer } from "@/local-db/utils/utils"; // services import workspaceDraftService from "@/services/issue/workspace_draft.service"; // types @@ -350,9 +348,6 @@ export class WorkspaceDraftIssues implements IWorkspaceDraftIssues { }); } - // sync issue to local db - addIssueToPersistanceLayer({ ...payload, ...response }); - // Update draft issue count in workspaceUserInfo this.updateWorkspaceUserDraftIssueCount(workspaceSlug, -1); }); diff --git a/apps/web/core/store/label.store.ts b/apps/web/core/store/label.store.ts index a6500442f9..635143d895 100644 --- a/apps/web/core/store/label.store.ts +++ b/apps/web/core/store/label.store.ts @@ -6,7 +6,6 @@ import type { IIssueLabel, IIssueLabelTree } from "@plane/types"; // helpers import { buildTree } from "@plane/utils"; // services -import { syncIssuesWithDeletedLabels } from "@/local-db/utils/load-workspace"; import { IssueLabelService } from "@/services/issue"; // store import type { CoreRootStore } from "./root.store"; @@ -299,7 +298,6 @@ export class LabelStore implements ILabelStore { runInAction(() => { delete this.labelMap[labelId]; }); - syncIssuesWithDeletedLabels([labelId]); }); }; } diff --git a/apps/web/core/store/module.store.ts b/apps/web/core/store/module.store.ts index 415cf4d5f5..568ad261b5 100644 --- a/apps/web/core/store/module.store.ts +++ b/apps/web/core/store/module.store.ts @@ -7,7 +7,6 @@ import type { DistributionUpdates } from "@plane/utils"; import { updateDistribution, orderModules, shouldFilterModule } from "@plane/utils"; // helpers // services -import { syncIssuesWithDeletedModules } from "@/local-db/utils/load-workspace"; import { ModuleService } from "@/services/module.service"; import { ModuleArchiveService } from "@/services/module_archive.service"; import { ProjectService } from "@/services/project"; @@ -453,7 +452,6 @@ export class ModulesStore implements IModuleStore { runInAction(() => { delete this.moduleMap[moduleId]; if (this.rootStore.favorite.entityMap[moduleId]) this.rootStore.favorite.removeFavoriteFromStore(moduleId); - syncIssuesWithDeletedModules([moduleId]); }); }); }; diff --git a/apps/web/core/store/state.store.ts b/apps/web/core/store/state.store.ts index d44e20e862..9085ab0d9a 100644 --- a/apps/web/core/store/state.store.ts +++ b/apps/web/core/store/state.store.ts @@ -7,7 +7,6 @@ import type { IState } from "@plane/types"; // helpers import { sortStates } from "@plane/utils"; // plane web -import { syncIssuesWithDeletedStates } from "@/local-db/utils/load-workspace"; import { ProjectStateService } from "@/plane-web/services/project/project-state.service"; import type { RootStore } from "@/plane-web/store/root.store"; @@ -248,7 +247,6 @@ export class StateStore implements IStateStore { await this.stateService.deleteState(workspaceSlug, projectId, stateId).then(() => { runInAction(() => { delete this.stateMap[stateId]; - syncIssuesWithDeletedStates([stateId]); }); }); }; diff --git a/apps/web/core/store/user/index.ts b/apps/web/core/store/user/index.ts index cb62582881..1656b0d4ab 100644 --- a/apps/web/core/store/user/index.ts +++ b/apps/web/core/store/user/index.ts @@ -3,8 +3,6 @@ import { action, makeObservable, observable, runInAction, computed } from "mobx" // plane imports import { EUserPermissions, API_BASE_URL } from "@plane/constants"; import type { IUser, TUserPermissions } from "@plane/types"; -// local -import { persistence } from "@/local-db/storage.sqlite"; // plane web imports import type { RootStore } from "@/plane-web/store/root.store"; import type { IUserPermissionStore } from "@/plane-web/store/user/permission.store"; @@ -48,7 +46,6 @@ export interface IUserStore { reset: () => void; signOut: () => Promise; // computed - localDBEnabled: boolean; canPerformAnyCreateAction: boolean; projectsWithCreatePermissions: { [projectId: string]: number } | null; } @@ -99,8 +96,6 @@ export class UserStore implements IUserStore { // computed canPerformAnyCreateAction: computed, projectsWithCreatePermissions: computed, - - localDBEnabled: computed, }); } @@ -253,7 +248,6 @@ export class UserStore implements IUserStore { */ signOut = async (): Promise => { await this.authService.signOut(API_BASE_URL); - await persistence.clearStorage(true); this.store.resetOnSignOut(); }; @@ -296,8 +290,4 @@ export class UserStore implements IUserStore { const filteredProjects = this.fetchProjectsWithCreatePermissions(); return filteredProjects ? Object.keys(filteredProjects).length > 0 : false; } - - get localDBEnabled() { - return this.userSettings.canUseLocalDB; - } } diff --git a/apps/web/core/store/user/settings.store.ts b/apps/web/core/store/user/settings.store.ts index 1dceea1b10..ae89f03299 100644 --- a/apps/web/core/store/user/settings.store.ts +++ b/apps/web/core/store/user/settings.store.ts @@ -14,7 +14,6 @@ export interface IUserSettingsStore { isLoading: boolean; error: TError | undefined; data: IUserSettings; - canUseLocalDB: boolean; sidebarCollapsed: boolean; isScrolled: boolean; // actions @@ -42,7 +41,6 @@ export class UserSettingsStore implements IUserSettingsStore { invites: undefined, }, }; - canUseLocalDB: boolean = false; // services userService: UserService; @@ -52,7 +50,6 @@ export class UserSettingsStore implements IUserSettingsStore { isLoading: observable.ref, error: observable, data: observable, - canUseLocalDB: observable.ref, sidebarCollapsed: observable.ref, isScrolled: observable.ref, // actions diff --git a/packages/utils/src/work-item/base.ts b/packages/utils/src/work-item/base.ts index 8a746ec90b..d2ded2dfa8 100644 --- a/packages/utils/src/work-item/base.ts +++ b/packages/utils/src/work-item/base.ts @@ -266,7 +266,6 @@ export const getComputedDisplayFilters = ( defaultValues?: IIssueDisplayFilterOptions ): IIssueDisplayFilterOptions => { const filters = !isEmpty(displayFilters) ? displayFilters : defaultValues; - return { calendar: { show_weekends: filters?.calendar?.show_weekends || false, @@ -307,20 +306,6 @@ export const getComputedDisplayProperties = ( issue_type: displayProperties?.issue_type ?? true, }); -/** - * This is to check if the issues list api should fall back to server or use local db - * @param queries - * @returns - */ -export const getIssuesShouldFallbackToServer = (queries: any) => { - // If there is expand query and is not grouped then fallback to server - if (!isEmpty(queries.expand as string) && !queries.group_by) return true; - // If query has mentions then fallback to server - if (!isEmpty(queries.mentions)) return true; - - return false; -}; - export const generateWorkItemLink = ({ workspaceSlug, projectId, @@ -339,8 +324,8 @@ export const generateWorkItemLink = ({ isEpic?: boolean; }): string => { const archiveIssueLink = `/${workspaceSlug}/projects/${projectId}/archives/issues/${issueId}`; - const epicLink = `/${workspaceSlug}/projects/${projectId}/epics/${issueId}`; const workItemLink = `/${workspaceSlug}/browse/${projectIdentifier}-${sequenceId}/`; + const epicLink = workItemLink; return isArchived ? archiveIssueLink : isEpic ? epicLink : workItemLink; };