diff --git a/Cargo.lock b/Cargo.lock index 17a1d956d..f774018b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4233,6 +4233,7 @@ dependencies = [ name = "turso_node" version = "0.2.0-pre.3" dependencies = [ + "chrono", "napi", "napi-build", "napi-derive", @@ -4335,10 +4336,10 @@ name = "turso_sync_js" version = "0.2.0-pre.3" dependencies = [ "genawaiter", - "http", "napi", "napi-build", "napi-derive", + "tracing", "tracing-subscriber", "turso_core", "turso_node", diff --git a/Cargo.toml b/Cargo.toml index aff912890..cad11bee3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,6 @@ members = [ "perf/throughput/rusqlite", "perf/encryption" ] - exclude = [ "perf/latency/limbo", ] @@ -62,7 +61,7 @@ limbo_percentile = { path = "extensions/percentile", version = "0.2.0-pre.3" } limbo_regexp = { path = "extensions/regexp", version = "0.2.0-pre.3" } turso_sqlite3_parser = { path = "vendored/sqlite3-parser", version = "0.2.0-pre.3" } limbo_uuid = { path = "extensions/uuid", version = "0.2.0-pre.3" } -turso_parser = { path = "parser", version = "0.2.0-pre.3" } +turso_parser = { path = "parser", version = "0.2.0-pre.3" } sql_generation = { path = "sql_generation" } strum = { version = "0.26", features = ["derive"] } strum_macros = "0.26" diff --git a/bindings/javascript/Cargo.toml b/bindings/javascript/Cargo.toml index 1b5001839..dcd2ba441 100644 --- a/bindings/javascript/Cargo.toml +++ b/bindings/javascript/Cargo.toml @@ -16,6 +16,7 @@ napi = { version = "3.1.3", default-features = false, features = ["napi6"] } napi-derive = { version = "3.1.1", default-features = true } tracing-subscriber = { workspace = true, features = ["env-filter"] } tracing.workspace = true +chrono = { workspace = true, default-features = false, features = ["clock"] } [features] encryption = ["turso_core/encryption"] diff --git a/bindings/javascript/examples/browser/package-lock.json b/bindings/javascript/examples/browser/package-lock.json new file mode 100644 index 000000000..24eade16e --- /dev/null +++ b/bindings/javascript/examples/browser/package-lock.json @@ -0,0 +1,335 @@ +{ + "name": "wasm", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "wasm", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@tursodatabase/database-browser": "../../packages/browser" + }, + "devDependencies": { + "vite": "^7.1.4" + } + }, + "../../packages/browser": { + "name": "@tursodatabase/database-browser", + "version": "0.1.5", + "license": "MIT", + "dependencies": { + "@napi-rs/wasm-runtime": "^1.0.3", + "@tursodatabase/database-browser-common": "^0.1.5", + "@tursodatabase/database-common": "^0.1.5" + }, + "devDependencies": { + "@napi-rs/cli": "^3.1.5", + "@vitest/browser": "^3.2.4", + "playwright": "^1.55.0", + "typescript": "^5.9.2", + "vitest": "^3.2.4" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.9", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.50.0", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.50.0", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tursodatabase/database-browser": { + "resolved": "../../packages/browser", + "link": true + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.25.9", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.9", + "@esbuild/android-arm": "0.25.9", + "@esbuild/android-arm64": "0.25.9", + "@esbuild/android-x64": "0.25.9", + "@esbuild/darwin-arm64": "0.25.9", + "@esbuild/darwin-x64": "0.25.9", + "@esbuild/freebsd-arm64": "0.25.9", + "@esbuild/freebsd-x64": "0.25.9", + "@esbuild/linux-arm": "0.25.9", + "@esbuild/linux-arm64": "0.25.9", + "@esbuild/linux-ia32": "0.25.9", + "@esbuild/linux-loong64": "0.25.9", + "@esbuild/linux-mips64el": "0.25.9", + "@esbuild/linux-ppc64": "0.25.9", + "@esbuild/linux-riscv64": "0.25.9", + "@esbuild/linux-s390x": "0.25.9", + "@esbuild/linux-x64": "0.25.9", + "@esbuild/netbsd-arm64": "0.25.9", + "@esbuild/netbsd-x64": "0.25.9", + "@esbuild/openbsd-arm64": "0.25.9", + "@esbuild/openbsd-x64": "0.25.9", + "@esbuild/openharmony-arm64": "0.25.9", + "@esbuild/sunos-x64": "0.25.9", + "@esbuild/win32-arm64": "0.25.9", + "@esbuild/win32-ia32": "0.25.9", + "@esbuild/win32-x64": "0.25.9" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rollup": { + "version": "4.50.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.50.0", + "@rollup/rollup-android-arm64": "4.50.0", + "@rollup/rollup-darwin-arm64": "4.50.0", + "@rollup/rollup-darwin-x64": "4.50.0", + "@rollup/rollup-freebsd-arm64": "4.50.0", + "@rollup/rollup-freebsd-x64": "4.50.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.50.0", + "@rollup/rollup-linux-arm-musleabihf": "4.50.0", + "@rollup/rollup-linux-arm64-gnu": "4.50.0", + "@rollup/rollup-linux-arm64-musl": "4.50.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.50.0", + "@rollup/rollup-linux-ppc64-gnu": "4.50.0", + "@rollup/rollup-linux-riscv64-gnu": "4.50.0", + "@rollup/rollup-linux-riscv64-musl": "4.50.0", + "@rollup/rollup-linux-s390x-gnu": "4.50.0", + "@rollup/rollup-linux-x64-gnu": "4.50.0", + "@rollup/rollup-linux-x64-musl": "4.50.0", + "@rollup/rollup-openharmony-arm64": "4.50.0", + "@rollup/rollup-win32-arm64-msvc": "4.50.0", + "@rollup/rollup-win32-ia32-msvc": "4.50.0", + "@rollup/rollup-win32-x64-msvc": "4.50.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/vite": { + "version": "7.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.14" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + } + } +} diff --git a/bindings/javascript/examples/drizzle/package-lock.json b/bindings/javascript/examples/drizzle/package-lock.json new file mode 100644 index 000000000..7867fc918 --- /dev/null +++ b/bindings/javascript/examples/drizzle/package-lock.json @@ -0,0 +1,626 @@ +{ + "name": "drizzle", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "drizzle", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@tursodatabase/database": "../../packages/native", + "better-sqlite3": "^12.2.0", + "drizzle-orm": "^0.44.3" + } + }, + "../..": { + "version": "0.1.5", + "workspaces": [ + "packages/common", + "packages/native", + "packages/browser", + "packages/browser-common", + "sync/packages/common", + "sync/packages/native", + "sync/packages/browser" + ] + }, + "../../packages/browser": { + "name": "@tursodatabase/database-browser", + "version": "0.1.5", + "extraneous": true, + "license": "MIT", + "dependencies": { + "@napi-rs/wasm-runtime": "^1.0.3", + "@tursodatabase/database-browser-common": "^0.1.5", + "@tursodatabase/database-common": "^0.1.5" + }, + "devDependencies": { + "@napi-rs/cli": "^3.1.5", + "@vitest/browser": "^3.2.4", + "playwright": "^1.55.0", + "typescript": "^5.9.2", + "vitest": "^3.2.4" + } + }, + "../../packages/browser-common": { + "name": "@tursodatabase/database-browser-common", + "version": "0.1.5", + "extraneous": true, + "license": "MIT", + "devDependencies": { + "typescript": "^5.9.2" + } + }, + "../../packages/common": { + "name": "@tursodatabase/database-common", + "version": "0.1.5", + "extraneous": true, + "license": "MIT", + "devDependencies": { + "typescript": "^5.9.2" + } + }, + "../../packages/native": { + "name": "@tursodatabase/database", + "version": "0.1.5", + "license": "MIT", + "dependencies": { + "@tursodatabase/database-common": "^0.1.5" + }, + "devDependencies": { + "@napi-rs/cli": "^3.1.5", + "@types/node": "^24.3.1", + "typescript": "^5.9.2", + "vitest": "^3.2.4" + } + }, + "../../sync/packages/browser": { + "name": "@tursodatabase/sync-browser", + "version": "0.1.5", + "extraneous": true, + "license": "MIT", + "dependencies": { + "@napi-rs/wasm-runtime": "^1.0.3", + "@tursodatabase/database-browser-common": "^0.1.5", + "@tursodatabase/database-common": "^0.1.5", + "@tursodatabase/sync-common": "^0.1.5" + }, + "devDependencies": { + "@napi-rs/cli": "^3.1.5", + "@vitest/browser": "^3.2.4", + "playwright": "^1.55.0", + "typescript": "^5.9.2", + "vitest": "^3.2.4" + } + }, + "../../sync/packages/common": { + "name": "@tursodatabase/sync-common", + "version": "0.1.5", + "extraneous": true, + "license": "MIT", + "devDependencies": { + "typescript": "^5.9.2" + } + }, + "../../sync/packages/native": { + "name": "@tursodatabase/sync", + "version": "0.1.5", + "extraneous": true, + "license": "MIT", + "dependencies": { + "@tursodatabase/database-common": "^0.1.5", + "@tursodatabase/sync-common": "^0.1.5" + }, + "devDependencies": { + "@napi-rs/cli": "^3.1.5", + "@types/node": "^24.3.1", + "typescript": "^5.9.2", + "vitest": "^3.2.4" + } + }, + "node_modules/@tursodatabase/database": { + "resolved": "../../packages/native", + "link": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/better-sqlite3": { + "version": "12.2.0", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "bindings": "^1.5.0", + "prebuild-install": "^7.1.1" + }, + "engines": { + "node": "20.x || 22.x || 23.x || 24.x" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "license": "MIT", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "license": "ISC" + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/detect-libc": { + "version": "2.0.4", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/drizzle-orm": { + "version": "0.44.4", + "license": "Apache-2.0", + "peerDependencies": { + "@aws-sdk/client-rds-data": ">=3", + "@cloudflare/workers-types": ">=4", + "@electric-sql/pglite": ">=0.2.0", + "@libsql/client": ">=0.10.0", + "@libsql/client-wasm": ">=0.10.0", + "@neondatabase/serverless": ">=0.10.0", + "@op-engineering/op-sqlite": ">=2", + "@opentelemetry/api": "^1.4.1", + "@planetscale/database": ">=1.13", + "@prisma/client": "*", + "@tidbcloud/serverless": "*", + "@types/better-sqlite3": "*", + "@types/pg": "*", + "@types/sql.js": "*", + "@upstash/redis": ">=1.34.7", + "@vercel/postgres": ">=0.8.0", + "@xata.io/client": "*", + "better-sqlite3": ">=7", + "bun-types": "*", + "expo-sqlite": ">=14.0.0", + "gel": ">=2", + "knex": "*", + "kysely": "*", + "mysql2": ">=2", + "pg": ">=8", + "postgres": ">=3", + "sql.js": ">=1", + "sqlite3": ">=5" + }, + "peerDependenciesMeta": { + "@aws-sdk/client-rds-data": { + "optional": true + }, + "@cloudflare/workers-types": { + "optional": true + }, + "@electric-sql/pglite": { + "optional": true + }, + "@libsql/client": { + "optional": true + }, + "@libsql/client-wasm": { + "optional": true + }, + "@neondatabase/serverless": { + "optional": true + }, + "@op-engineering/op-sqlite": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@prisma/client": { + "optional": true + }, + "@tidbcloud/serverless": { + "optional": true + }, + "@types/better-sqlite3": { + "optional": true + }, + "@types/pg": { + "optional": true + }, + "@types/sql.js": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/postgres": { + "optional": true + }, + "@xata.io/client": { + "optional": true + }, + "better-sqlite3": { + "optional": true + }, + "bun-types": { + "optional": true + }, + "expo-sqlite": { + "optional": true + }, + "gel": { + "optional": true + }, + "knex": { + "optional": true + }, + "kysely": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "pg": { + "optional": true + }, + "postgres": { + "optional": true + }, + "prisma": { + "optional": true + }, + "sql.js": { + "optional": true + }, + "sqlite3": { + "optional": true + } + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "license": "(MIT OR WTFPL)", + "engines": { + "node": ">=6" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "license": "MIT" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/inherits": { + "version": "2.0.4", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "license": "ISC" + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "license": "MIT" + }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/node-abi": { + "version": "3.75.0", + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/once": { + "version": "1.4.0", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pump": { + "version": "3.0.3", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.2", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tar-fs": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "license": "ISC" + } + } +} diff --git a/bindings/javascript/package-lock.json b/bindings/javascript/package-lock.json index e0bc3a671..3df161dd7 100644 --- a/bindings/javascript/package-lock.json +++ b/bindings/javascript/package-lock.json @@ -59,6 +59,13 @@ "node": ">=6.9.0" } }, + "node_modules/@drizzle-team/brocli": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@drizzle-team/brocli/-/brocli-0.10.2.tgz", + "integrity": "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/@emnapi/core": { "version": "1.4.5", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.5.tgz", @@ -87,6 +94,238 @@ "tslib": "^2.4.0" } }, + "node_modules/@esbuild-kit/core-utils": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@esbuild-kit/core-utils/-/core-utils-3.3.2.tgz", + "integrity": "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==", + "deprecated": "Merged into tsx: https://tsx.is", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.18.20", + "source-map-support": "^0.5.21" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/@esbuild-kit/esm-loader": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@esbuild-kit/esm-loader/-/esm-loader-2.6.5.tgz", + "integrity": "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==", + "deprecated": "Merged into tsx: https://tsx.is", + "dev": true, + "license": "MIT", + "dependencies": { + "@esbuild-kit/core-utils": "^3.3.2", + "get-tsconfig": "^4.7.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", + "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/linux-arm64": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", @@ -104,6 +343,278 @@ "node": ">=18" } }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", + "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", + "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", + "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@inquirer/checkbox": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.2.0.tgz", @@ -524,6 +1035,209 @@ "dev": true, "license": "MIT" }, + "node_modules/@libsql/client": { + "version": "0.15.15", + "resolved": "https://registry.npmjs.org/@libsql/client/-/client-0.15.15.tgz", + "integrity": "sha512-twC0hQxPNHPKfeOv3sNT6u2pturQjLcI+CnpTM0SjRpocEGgfiZ7DWKXLNnsothjyJmDqEsBQJ5ztq9Wlu470w==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@libsql/core": "^0.15.14", + "@libsql/hrana-client": "^0.7.0", + "js-base64": "^3.7.5", + "libsql": "^0.5.22", + "promise-limit": "^2.7.0" + } + }, + "node_modules/@libsql/core": { + "version": "0.15.15", + "resolved": "https://registry.npmjs.org/@libsql/core/-/core-0.15.15.tgz", + "integrity": "sha512-C88Z6UKl+OyuKKPwz224riz02ih/zHYI3Ho/LAcVOgjsunIRZoBw7fjRfaH9oPMmSNeQfhGklSG2il1URoOIsA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "js-base64": "^3.7.5" + } + }, + "node_modules/@libsql/darwin-arm64": { + "version": "0.5.22", + "resolved": "https://registry.npmjs.org/@libsql/darwin-arm64/-/darwin-arm64-0.5.22.tgz", + "integrity": "sha512-4B8ZlX3nIDPndfct7GNe0nI3Yw6ibocEicWdC4fvQbSs/jdq/RC2oCsoJxJ4NzXkvktX70C1J4FcmmoBy069UA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/@libsql/darwin-x64": { + "version": "0.5.22", + "resolved": "https://registry.npmjs.org/@libsql/darwin-x64/-/darwin-x64-0.5.22.tgz", + "integrity": "sha512-ny2HYWt6lFSIdNFzUFIJ04uiW6finXfMNJ7wypkAD8Pqdm6nAByO+Fdqu8t7sD0sqJGeUCiOg480icjyQ2/8VA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/@libsql/hrana-client": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@libsql/hrana-client/-/hrana-client-0.7.0.tgz", + "integrity": "sha512-OF8fFQSkbL7vJY9rfuegK1R7sPgQ6kFMkDamiEccNUvieQ+3urzfDFI616oPl8V7T9zRmnTkSjMOImYCAVRVuw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@libsql/isomorphic-fetch": "^0.3.1", + "@libsql/isomorphic-ws": "^0.1.5", + "js-base64": "^3.7.5", + "node-fetch": "^3.3.2" + } + }, + "node_modules/@libsql/isomorphic-fetch": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@libsql/isomorphic-fetch/-/isomorphic-fetch-0.3.1.tgz", + "integrity": "sha512-6kK3SUK5Uu56zPq/Las620n5aS9xJq+jMBcNSOmjhNf/MUvdyji4vrMTqD7ptY7/4/CAVEAYDeotUz60LNQHtw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@libsql/isomorphic-ws": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@libsql/isomorphic-ws/-/isomorphic-ws-0.1.5.tgz", + "integrity": "sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@types/ws": "^8.5.4", + "ws": "^8.13.0" + } + }, + "node_modules/@libsql/linux-arm-gnueabihf": { + "version": "0.5.22", + "resolved": "https://registry.npmjs.org/@libsql/linux-arm-gnueabihf/-/linux-arm-gnueabihf-0.5.22.tgz", + "integrity": "sha512-3Uo3SoDPJe/zBnyZKosziRGtszXaEtv57raWrZIahtQDsjxBVjuzYQinCm9LRCJCUT5t2r5Z5nLDPJi2CwZVoA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@libsql/linux-arm-musleabihf": { + "version": "0.5.22", + "resolved": "https://registry.npmjs.org/@libsql/linux-arm-musleabihf/-/linux-arm-musleabihf-0.5.22.tgz", + "integrity": "sha512-LCsXh07jvSojTNJptT9CowOzwITznD+YFGGW+1XxUr7fS+7/ydUrpDfsMX7UqTqjm7xG17eq86VkWJgHJfvpNg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@libsql/linux-arm64-gnu": { + "version": "0.5.22", + "resolved": "https://registry.npmjs.org/@libsql/linux-arm64-gnu/-/linux-arm64-gnu-0.5.22.tgz", + "integrity": "sha512-KSdnOMy88c9mpOFKUEzPskSaF3VLflfSUCBwas/pn1/sV3pEhtMF6H8VUCd2rsedwoukeeCSEONqX7LLnQwRMA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@libsql/linux-arm64-musl": { + "version": "0.5.22", + "resolved": "https://registry.npmjs.org/@libsql/linux-arm64-musl/-/linux-arm64-musl-0.5.22.tgz", + "integrity": "sha512-mCHSMAsDTLK5YH//lcV3eFEgiR23Ym0U9oEvgZA0667gqRZg/2px+7LshDvErEKv2XZ8ixzw3p1IrBzLQHGSsw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@libsql/linux-x64-gnu": { + "version": "0.5.22", + "resolved": "https://registry.npmjs.org/@libsql/linux-x64-gnu/-/linux-x64-gnu-0.5.22.tgz", + "integrity": "sha512-kNBHaIkSg78Y4BqAdgjcR2mBilZXs4HYkAmi58J+4GRwDQZh5fIUWbnQvB9f95DkWUIGVeenqLRFY2pcTmlsew==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@libsql/linux-x64-musl": { + "version": "0.5.22", + "resolved": "https://registry.npmjs.org/@libsql/linux-x64-musl/-/linux-x64-musl-0.5.22.tgz", + "integrity": "sha512-UZ4Xdxm4pu3pQXjvfJiyCzZop/9j/eA2JjmhMaAhe3EVLH2g11Fy4fwyUp9sT1QJYR1kpc2JLuybPM0kuXv/Tg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@libsql/win32-x64-msvc": { + "version": "0.5.22", + "resolved": "https://registry.npmjs.org/@libsql/win32-x64-msvc/-/win32-x64-msvc-0.5.22.tgz", + "integrity": "sha512-Fj0j8RnBpo43tVZUVoNK6BV/9AtDUM5S7DF3LB4qTYg1LMSZqi3yeCneUTLJD6XomQJlZzbI4mst89yspVSAnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, "node_modules/@napi-rs/cli": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-3.1.5.tgz", @@ -886,6 +1600,15 @@ "node": ">=14.0.0" } }, + "node_modules/@neon-rs/load": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@neon-rs/load/-/load-0.0.4.tgz", + "integrity": "sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/@octokit/auth-token": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz", @@ -1198,6 +1921,18 @@ "undici-types": "~7.10.0" } }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@vitest/browser": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-3.2.4.tgz", @@ -1446,6 +2181,27 @@ "node": ">=12" } }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/before-after-hook": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", @@ -1453,14 +2209,74 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/better-sqlite3": { + "version": "12.2.0", + "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.2.0.tgz", + "integrity": "sha512-eGbYq2CT+tos1fBwLQ/tkBt9J5M3JEHjku4hbvQUePCckkvVf14xWj+1m7dGoK81M/fOjFT7yM9UMeKT/+vFLQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "bindings": "^1.5.0", + "prebuild-install": "^7.1.1" + }, + "engines": { + "node": "20.x || 22.x || 23.x || 24.x" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true, - "license": "MIT", - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/cac": { "version": "6.7.14", @@ -1506,6 +2322,13 @@ "node": ">= 16" } }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true, + "license": "ISC" + }, "node_modules/cli-width": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", @@ -1568,6 +2391,18 @@ "optional": true, "peer": true }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 12" + } + }, "node_modules/debug": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", @@ -1586,6 +2421,22 @@ } } }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/deep-eql": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", @@ -1596,6 +2447,16 @@ "node": ">=6" } }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -1606,6 +2467,16 @@ "node": ">=6" } }, + "node_modules/detect-libc": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.0.tgz", + "integrity": "sha512-vEtk+OcP7VBRtQZ1EJ3bdgzSfBjgnEalLTp5zjJrS+2Z1w2KZly4SBdac/WDU3hhsNAZ9E8SC96ME4Ey8MZ7cg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/dom-accessibility-api": { "version": "0.5.16", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", @@ -1613,6 +2484,148 @@ "dev": true, "license": "MIT" }, + "node_modules/drizzle-kit": { + "version": "0.31.4", + "resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.31.4.tgz", + "integrity": "sha512-tCPWVZWZqWVx2XUsVpJRnH9Mx0ClVOf5YUHerZ5so1OKSlqww4zy1R5ksEdGRcO3tM3zj0PYN6V48TbQCL1RfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@drizzle-team/brocli": "^0.10.2", + "@esbuild-kit/esm-loader": "^2.5.5", + "esbuild": "^0.25.4", + "esbuild-register": "^3.5.0" + }, + "bin": { + "drizzle-kit": "bin.cjs" + } + }, + "node_modules/drizzle-orm": { + "version": "0.44.5", + "resolved": "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-0.44.5.tgz", + "integrity": "sha512-jBe37K7d8ZSKptdKfakQFdeljtu3P2Cbo7tJoJSVZADzIKOBo9IAJPOmMsH2bZl90bZgh8FQlD8BjxXA/zuBkQ==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "@aws-sdk/client-rds-data": ">=3", + "@cloudflare/workers-types": ">=4", + "@electric-sql/pglite": ">=0.2.0", + "@libsql/client": ">=0.10.0", + "@libsql/client-wasm": ">=0.10.0", + "@neondatabase/serverless": ">=0.10.0", + "@op-engineering/op-sqlite": ">=2", + "@opentelemetry/api": "^1.4.1", + "@planetscale/database": ">=1.13", + "@prisma/client": "*", + "@tidbcloud/serverless": "*", + "@types/better-sqlite3": "*", + "@types/pg": "*", + "@types/sql.js": "*", + "@upstash/redis": ">=1.34.7", + "@vercel/postgres": ">=0.8.0", + "@xata.io/client": "*", + "better-sqlite3": ">=7", + "bun-types": "*", + "expo-sqlite": ">=14.0.0", + "gel": ">=2", + "knex": "*", + "kysely": "*", + "mysql2": ">=2", + "pg": ">=8", + "postgres": ">=3", + "sql.js": ">=1", + "sqlite3": ">=5" + }, + "peerDependenciesMeta": { + "@aws-sdk/client-rds-data": { + "optional": true + }, + "@cloudflare/workers-types": { + "optional": true + }, + "@electric-sql/pglite": { + "optional": true + }, + "@libsql/client": { + "optional": true + }, + "@libsql/client-wasm": { + "optional": true + }, + "@neondatabase/serverless": { + "optional": true + }, + "@op-engineering/op-sqlite": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@prisma/client": { + "optional": true + }, + "@tidbcloud/serverless": { + "optional": true + }, + "@types/better-sqlite3": { + "optional": true + }, + "@types/pg": { + "optional": true + }, + "@types/sql.js": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/postgres": { + "optional": true + }, + "@xata.io/client": { + "optional": true + }, + "better-sqlite3": { + "optional": true + }, + "bun-types": { + "optional": true + }, + "expo-sqlite": { + "optional": true + }, + "gel": { + "optional": true + }, + "knex": { + "optional": true + }, + "kysely": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "pg": { + "optional": true + }, + "postgres": { + "optional": true + }, + "prisma": { + "optional": true + }, + "sql.js": { + "optional": true + }, + "sqlite3": { + "optional": true + } + } + }, "node_modules/emnapi": { "version": "1.4.5", "resolved": "https://registry.npmjs.org/emnapi/-/emnapi-1.4.5.tgz", @@ -1635,6 +2648,16 @@ "dev": true, "license": "MIT" }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/es-module-lexer": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", @@ -1695,6 +2718,386 @@ "@esbuild/win32-x64": "0.25.9" } }, + "node_modules/esbuild-register": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz", + "integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "esbuild": ">=0.12 <1" + } + }, + "node_modules/esbuild/node_modules/@esbuild/android-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", + "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/android-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", + "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/android-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", + "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/darwin-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", + "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/darwin-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", + "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", + "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", + "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", + "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", + "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-loong64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", + "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", + "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", + "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", + "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-s390x": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", + "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", + "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", + "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", + "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/sunos-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", + "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/win32-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", + "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/win32-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", + "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/win32-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", + "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true, + "license": "(MIT OR WTFPL)", + "engines": { + "node": ">=6" + } + }, "node_modules/expect-type": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", @@ -1755,6 +3158,39 @@ } } }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "license": "MIT" + }, "node_modules/find-up": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz", @@ -1786,6 +3222,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "license": "MIT" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1801,6 +3259,26 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/get-tsconfig": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", + "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true, + "license": "MIT" + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -1814,6 +3292,41 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -1824,6 +3337,15 @@ "node": ">=8" } }, + "node_modules/js-base64": { + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.8.tgz", + "integrity": "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "peer": true + }, "node_modules/js-tokens": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", @@ -1831,6 +3353,53 @@ "dev": true, "license": "MIT" }, + "node_modules/libsql": { + "version": "0.5.22", + "resolved": "https://registry.npmjs.org/libsql/-/libsql-0.5.22.tgz", + "integrity": "sha512-NscWthMQt7fpU8lqd7LXMvT9pi+KhhmTHAJWUB/Lj6MWa0MKFv0F2V4C6WKKpjCVZl0VwcDz4nOI3CyaT1DDiA==", + "cpu": [ + "x64", + "arm64", + "wasm32", + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin", + "linux", + "win32" + ], + "peer": true, + "dependencies": { + "@neon-rs/load": "^0.0.4", + "detect-libc": "2.0.2" + }, + "optionalDependencies": { + "@libsql/darwin-arm64": "0.5.22", + "@libsql/darwin-x64": "0.5.22", + "@libsql/linux-arm-gnueabihf": "0.5.22", + "@libsql/linux-arm-musleabihf": "0.5.22", + "@libsql/linux-arm64-gnu": "0.5.22", + "@libsql/linux-arm64-musl": "0.5.22", + "@libsql/linux-x64-gnu": "0.5.22", + "@libsql/linux-x64-musl": "0.5.22", + "@libsql/win32-x64-msvc": "0.5.22" + } + }, + "node_modules/libsql/node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, "node_modules/locate-path": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", @@ -1874,6 +3443,36 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true, + "license": "MIT" + }, "node_modules/mrmime": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", @@ -1920,6 +3519,80 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-abi": { + "version": "3.77.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.77.0.tgz", + "integrity": "sha512-DSmt0OEcLoK4i3NuscSbGjOf3bqiDEutejqENSplMSFA/gmB8mkED9G4pKWnPl7MDU4rSHebKPHeitpDfyH0cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -2085,6 +3758,33 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/pretty-format": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", @@ -2100,6 +3800,42 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "node_modules/promise-limit": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/promise-limit/-/promise-limit-2.7.0.tgz", + "integrity": "sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -2107,6 +3843,31 @@ "dev": true, "license": "MIT" }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/rollup": { "version": "4.50.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.1.tgz", @@ -2148,6 +3909,27 @@ "fsevents": "~2.3.2" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -2188,6 +3970,53 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/sirv": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", @@ -2209,8 +4038,6 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "license": "BSD-3-Clause", - "optional": true, - "peer": true, "engines": { "node": ">=0.10.0" } @@ -2231,8 +4058,6 @@ "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -2252,6 +4077,16 @@ "dev": true, "license": "MIT" }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -2280,6 +4115,16 @@ "node": ">=8" } }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/strip-literal": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.0.0.tgz", @@ -2293,6 +4138,36 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/tar-fs": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/terser": { "version": "5.44.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz", @@ -2404,6 +4279,19 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/typanion": { "version": "3.14.0", "resolved": "https://registry.npmjs.org/typanion/-/typanion-3.14.0.tgz", @@ -2442,6 +4330,13 @@ "dev": true, "license": "ISC" }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, "node_modules/vite": { "version": "7.1.5", "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.5.tgz", @@ -2613,6 +4508,18 @@ } } }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/why-is-node-running": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", @@ -2630,6 +4537,13 @@ "node": ">=8" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, "node_modules/ws": { "version": "8.18.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", @@ -2724,6 +4638,9 @@ "devDependencies": { "@napi-rs/cli": "^3.1.5", "@types/node": "^24.3.1", + "better-sqlite3": "^12.2.0", + "drizzle-kit": "^0.31.4", + "drizzle-orm": "^0.44.5", "typescript": "^5.9.2", "vitest": "^3.2.4" } @@ -2773,6 +4690,9 @@ "name": "@tursodatabase/sync-common", "version": "0.2.0-pre.3", "license": "MIT", + "dependencies": { + "@tursodatabase/database-common": "^0.2.0-pre.3" + }, "devDependencies": { "typescript": "^5.9.2" } diff --git a/bindings/javascript/packages/browser-common/index.ts b/bindings/javascript/packages/browser-common/index.ts index dc7c334f7..828f49306 100644 --- a/bindings/javascript/packages/browser-common/index.ts +++ b/bindings/javascript/packages/browser-common/index.ts @@ -24,46 +24,94 @@ interface BrowserImports { is_web_worker(): boolean; lookup_file(ptr: number, len: number): number; read(handle: number, ptr: number, len: number, offset: number): number; + read_async(handle: number, ptr: number, len: number, offset: number, c: number); write(handle: number, ptr: number, len: number, offset: number): number; + write_async(handle: number, ptr: number, len: number, offset: number, c: number); sync(handle: number): number; + sync_async(handle: number, c: number); truncate(handle: number, len: number): number; + truncate_async(handle: number, len: number, c: number); size(handle: number): number; } -function panic(name): never { +function panicMain(name): never { + throw new Error(`method ${name} must be invoked only from the worker thread`); +} + +function panicWorker(name): never { throw new Error(`method ${name} must be invoked only from the main thread`); } -const MainDummyImports: BrowserImports = { - is_web_worker: function (): boolean { - return false; - }, - lookup_file: function (ptr: number, len: number): number { - panic("lookup_file") - }, - read: function (handle: number, ptr: number, len: number, offset: number): number { - panic("read") - }, - write: function (handle: number, ptr: number, len: number, offset: number): number { - panic("write") - }, - sync: function (handle: number): number { - panic("sync") - }, - truncate: function (handle: number, len: number): number { - panic("truncate") - }, - size: function (handle: number): number { - panic("size") - } +let completeOpfs: any = null; + +function mainImports(worker: Worker): BrowserImports { + return { + is_web_worker(): boolean { + return false; + }, + write_async(handle, ptr, len, offset, c) { + writeFileAtWorker(worker, handle, ptr, len, offset) + .then(result => { + completeOpfs(c, result); + }, err => { + console.error('write_async', err); + completeOpfs(c, -1); + }); + }, + sync_async(handle, c) { + syncFileAtWorker(worker, handle) + .then(result => { + completeOpfs(c, result); + }, err => { + console.error('sync_async', err); + completeOpfs(c, -1); + }); + }, + read_async(handle, ptr, len, offset, c) { + readFileAtWorker(worker, handle, ptr, len, offset) + .then(result => { + completeOpfs(c, result); + }, err => { + console.error('read_async', err); + completeOpfs(c, -1); + }); + }, + truncate_async(handle, len, c) { + truncateFileAtWorker(worker, handle, len) + .then(result => { + completeOpfs(c, result); + }, err => { + console.error('truncate_async', err); + completeOpfs(c, -1); + }); + }, + lookup_file(ptr, len): number { + panicMain("lookup_file") + }, + read(handle, ptr, len, offset): number { + panicMain("read") + }, + write(handle, ptr, len, offset): number { + panicMain("write") + }, + sync(handle): number { + panicMain("sync") + }, + truncate(handle, len): number { + panicMain("truncate") + }, + size(handle): number { + panicMain("size") + } + }; }; function workerImports(opfs: OpfsDirectory, memory: WebAssembly.Memory): BrowserImports { return { - is_web_worker: function (): boolean { + is_web_worker(): boolean { return true; }, - lookup_file: function (ptr: number, len: number): number { + lookup_file(ptr, len): number { try { const handle = opfs.lookupFileHandle(getStringFromMemory(memory, ptr, len)); return handle == null ? -404 : handle; @@ -71,29 +119,28 @@ function workerImports(opfs: OpfsDirectory, memory: WebAssembly.Memory): Browser return -1; } }, - read: function (handle: number, ptr: number, len: number, offset: number): number { + read(handle, ptr, len, offset): number { try { return opfs.read(handle, getUint8ArrayFromMemory(memory, ptr, len), offset); } catch (e) { return -1; } }, - write: function (handle: number, ptr: number, len: number, offset: number): number { + write(handle, ptr, len, offset): number { try { return opfs.write(handle, getUint8ArrayFromMemory(memory, ptr, len), offset) } catch (e) { return -1; } }, - sync: function (handle: number): number { + sync(handle): number { try { - opfs.sync(handle); - return 0; + return opfs.sync(handle); } catch (e) { return -1; } }, - truncate: function (handle: number, len: number): number { + truncate(handle, len): number { try { opfs.truncate(handle, len); return 0; @@ -101,13 +148,25 @@ function workerImports(opfs: OpfsDirectory, memory: WebAssembly.Memory): Browser return -1; } }, - size: function (handle: number): number { + size(handle): number { try { return opfs.size(handle); } catch (e) { return -1; } - } + }, + read_async(handle, ptr, len, offset, completion) { + panicWorker("read_async") + }, + write_async(handle, ptr, len, offset, completion) { + panicWorker("write_async") + }, + sync_async(handle, completion) { + panicWorker("sync_async") + }, + truncate_async(handle, len, c) { + panicWorker("truncate_async") + }, } } @@ -175,10 +234,11 @@ class OpfsDirectory { throw e; } } - sync(handle: number) { + sync(handle: number): number { try { const file = this.fileByHandle.get(handle); file.flush(); + return 0; } catch (e) { console.error('sync', handle, e); throw e; @@ -187,8 +247,8 @@ class OpfsDirectory { truncate(handle: number, size: number) { try { const file = this.fileByHandle.get(handle); - const result = file.truncate(size); - return result; + file.truncate(size); + return 0; } catch (e) { console.error('truncate', handle, size, e); throw e; @@ -214,7 +274,7 @@ function waitForWorkerResponse(worker: Worker, id: number): Promise { if (msg.data.error != null) { waitReject(msg.data.error) } else { - waitResolve() + waitResolve(msg.data.result) } cleanup(); } @@ -229,6 +289,38 @@ function waitForWorkerResponse(worker: Worker, id: number): Promise { return result; } +function readFileAtWorker(worker: Worker, handle: number, ptr: number, len: number, offset: number) { + workerRequestId += 1; + const currentId = workerRequestId; + const promise = waitForWorkerResponse(worker, currentId); + worker.postMessage({ __turso__: "read_async", handle: handle, ptr: ptr, len: len, offset: offset, id: currentId }); + return promise; +} + +function writeFileAtWorker(worker: Worker, handle: number, ptr: number, len: number, offset: number) { + workerRequestId += 1; + const currentId = workerRequestId; + const promise = waitForWorkerResponse(worker, currentId); + worker.postMessage({ __turso__: "write_async", handle: handle, ptr: ptr, len: len, offset: offset, id: currentId }); + return promise; +} + +function syncFileAtWorker(worker: Worker, handle: number) { + workerRequestId += 1; + const currentId = workerRequestId; + const promise = waitForWorkerResponse(worker, currentId); + worker.postMessage({ __turso__: "sync_async", handle: handle, id: currentId }); + return promise; +} + +function truncateFileAtWorker(worker: Worker, handle: number, len: number) { + workerRequestId += 1; + const currentId = workerRequestId; + const promise = waitForWorkerResponse(worker, currentId); + worker.postMessage({ __turso__: "truncate_async", handle: handle, len: len, id: currentId }); + return promise; +} + function registerFileAtWorker(worker: Worker, path: string): Promise { workerRequestId += 1; const currentId = workerRequestId; @@ -299,12 +391,25 @@ function setupWebWorker() { self.postMessage({ id: e.data.id, error: error }); } return; + } else if (e.data.__turso__ == 'read_async') { + let result = opfs.read(e.data.handle, getUint8ArrayFromMemory(memory, e.data.ptr, e.data.len), e.data.offset); + self.postMessage({ id: e.data.id, result: result }); + } else if (e.data.__turso__ == 'write_async') { + let result = opfs.write(e.data.handle, getUint8ArrayFromMemory(memory, e.data.ptr, e.data.len), e.data.offset); + self.postMessage({ id: e.data.id, result: result }); + } else if (e.data.__turso__ == 'sync_async') { + let result = opfs.sync(e.data.handle); + self.postMessage({ id: e.data.id, result: result }); + } else if (e.data.__turso__ == 'truncate_async') { + let result = opfs.truncate(e.data.handle, e.data.len); + self.postMessage({ id: e.data.id, result: result }); } handler.handle(e) } } async function setupMainThread(wasmFile: ArrayBuffer, factory: () => Worker): Promise { + const worker = factory(); const __emnapiContext = __emnapiGetDefaultContext() const __wasi = new __WASI({ version: 'preview1', @@ -322,13 +427,13 @@ async function setupMainThread(wasmFile: ArrayBuffer, factory: () => Worker): Pr context: __emnapiContext, asyncWorkPoolSize: 1, wasi: __wasi, - onCreateWorker() { return factory() }, + onCreateWorker() { return worker; }, overwriteImports(importObject) { importObject.env = { ...importObject.env, ...importObject.napi, ...importObject.emnapi, - ...MainDummyImports, + ...mainImports(worker), memory: __sharedMemory, } return importObject @@ -340,8 +445,9 @@ async function setupMainThread(wasmFile: ArrayBuffer, factory: () => Worker): Pr } } }, - }) + }); + completeOpfs = __napiModule.exports.completeOpfs; return __napiModule; } -export { OpfsDirectory, workerImports, MainDummyImports, waitForWorkerResponse, registerFileAtWorker, unregisterFileAtWorker, isWebWorker, setupWebWorker, setupMainThread } \ No newline at end of file +export { OpfsDirectory, workerImports, mainImports as MainDummyImports, waitForWorkerResponse, registerFileAtWorker, unregisterFileAtWorker, isWebWorker, setupWebWorker, setupMainThread } \ No newline at end of file diff --git a/bindings/javascript/packages/browser/index-bundle.ts b/bindings/javascript/packages/browser/index-bundle.ts index 2b74b8114..9aff00c28 100644 --- a/bindings/javascript/packages/browser/index-bundle.ts +++ b/bindings/javascript/packages/browser/index-bundle.ts @@ -20,5 +20,5 @@ export const Database = napiModule.exports.Database export const Opfs = napiModule.exports.Opfs export const OpfsFile = napiModule.exports.OpfsFile export const Statement = napiModule.exports.Statement -export const connect = napiModule.exports.connect +export const connectDbAsync = napiModule.exports.connectDbAsync export const initThreadPool = napiModule.exports.initThreadPool diff --git a/bindings/javascript/packages/browser/index-default.ts b/bindings/javascript/packages/browser/index-default.ts index 53c70e413..844e2c91b 100644 --- a/bindings/javascript/packages/browser/index-default.ts +++ b/bindings/javascript/packages/browser/index-default.ts @@ -18,5 +18,5 @@ export const Database = napiModule.exports.Database export const Opfs = napiModule.exports.Opfs export const OpfsFile = napiModule.exports.OpfsFile export const Statement = napiModule.exports.Statement -export const connect = napiModule.exports.connect +export const connectDbAsync = napiModule.exports.connectDbAsync export const initThreadPool = napiModule.exports.initThreadPool diff --git a/bindings/javascript/packages/browser/index-turbopack-hack.ts b/bindings/javascript/packages/browser/index-turbopack-hack.ts index f43d41624..8dc807f4a 100644 --- a/bindings/javascript/packages/browser/index-turbopack-hack.ts +++ b/bindings/javascript/packages/browser/index-turbopack-hack.ts @@ -21,5 +21,5 @@ export const Database = napiModule.exports.Database export const Opfs = napiModule.exports.Opfs export const OpfsFile = napiModule.exports.OpfsFile export const Statement = napiModule.exports.Statement -export const connect = napiModule.exports.connect +export const connectDbAsync = napiModule.exports.connectDbAsync export const initThreadPool = napiModule.exports.initThreadPool diff --git a/bindings/javascript/packages/browser/index-vite-dev-hack.ts b/bindings/javascript/packages/browser/index-vite-dev-hack.ts index 6f1d42c4a..3c36191de 100644 --- a/bindings/javascript/packages/browser/index-vite-dev-hack.ts +++ b/bindings/javascript/packages/browser/index-vite-dev-hack.ts @@ -7,7 +7,7 @@ let napiModule = { Opfs: {} as any, OpfsFile: {} as any, Statement: {} as any, - connect: {} as any, + connectDbAsync: {} as any, initThreadPool: {} as any, } }; @@ -37,5 +37,5 @@ export const Database = napiModule.exports.Database export const Opfs = napiModule.exports.Opfs export const OpfsFile = napiModule.exports.OpfsFile export const Statement = napiModule.exports.Statement -export const connect = napiModule.exports.connect +export const connectDbAsync = napiModule.exports.connectDbAsync export const initThreadPool = napiModule.exports.initThreadPool diff --git a/bindings/javascript/packages/browser/promise-bundle.ts b/bindings/javascript/packages/browser/promise-bundle.ts index fc28be689..103739e67 100644 --- a/bindings/javascript/packages/browser/promise-bundle.ts +++ b/bindings/javascript/packages/browser/promise-bundle.ts @@ -1,6 +1,6 @@ import { DatabaseOpts, SqliteError, } from "@tursodatabase/database-common" -import { connect as promiseConnect, Database } from "./promise.js"; -import { connect as nativeConnect, initThreadPool, MainWorker } from "./index-bundle.js"; +import { Database, connect as promiseConnect } from "./promise.js"; +import { initThreadPool, MainWorker, connectDbAsync } from "./index-bundle.js"; /** * Creates a new database connection asynchronously. @@ -10,13 +10,19 @@ import { connect as nativeConnect, initThreadPool, MainWorker } from "./index-bu * @returns {Promise} - A promise that resolves to a Database instance. */ async function connect(path: string, opts: DatabaseOpts = {}): Promise { - return await promiseConnect(path, opts, nativeConnect, async () => { + const init = async () => { await initThreadPool(); if (MainWorker == null) { throw new Error("panic: MainWorker is not initialized"); } return MainWorker; - }); + }; + return await promiseConnect( + path, + opts, + connectDbAsync, + init + ); } export { connect, Database, SqliteError } diff --git a/bindings/javascript/packages/browser/promise-default.ts b/bindings/javascript/packages/browser/promise-default.ts index a4dc99dfb..454ded33d 100644 --- a/bindings/javascript/packages/browser/promise-default.ts +++ b/bindings/javascript/packages/browser/promise-default.ts @@ -1,6 +1,6 @@ import { DatabaseOpts, SqliteError, } from "@tursodatabase/database-common" -import { connect as promiseConnect, Database } from "./promise.js"; -import { connect as nativeConnect, initThreadPool, MainWorker } from "./index-default.js"; +import { Database, connect as promiseConnect } from "./promise.js"; +import { initThreadPool, MainWorker, connectDbAsync } from "./index-default.js"; /** * Creates a new database connection asynchronously. @@ -10,13 +10,19 @@ import { connect as nativeConnect, initThreadPool, MainWorker } from "./index-de * @returns {Promise} - A promise that resolves to a Database instance. */ async function connect(path: string, opts: DatabaseOpts = {}): Promise { - return await promiseConnect(path, opts, nativeConnect, async () => { + const init = async () => { await initThreadPool(); if (MainWorker == null) { throw new Error("panic: MainWorker is not initialized"); } return MainWorker; - }); + }; + return await promiseConnect( + path, + opts, + connectDbAsync, + init + ); } export { connect, Database, SqliteError } diff --git a/bindings/javascript/packages/browser/promise-turbopack-hack.ts b/bindings/javascript/packages/browser/promise-turbopack-hack.ts index 359e79e40..b6b4bf09b 100644 --- a/bindings/javascript/packages/browser/promise-turbopack-hack.ts +++ b/bindings/javascript/packages/browser/promise-turbopack-hack.ts @@ -1,6 +1,6 @@ import { DatabaseOpts, SqliteError, } from "@tursodatabase/database-common" -import { connect as promiseConnect, Database } from "./promise.js"; -import { connect as nativeConnect, initThreadPool, MainWorker } from "./index-turbopack-hack.js"; +import { Database, connect as promiseConnect } from "./promise.js"; +import { initThreadPool, MainWorker, connectDbAsync } from "./index-turbopack-hack.js"; /** * Creates a new database connection asynchronously. @@ -10,13 +10,19 @@ import { connect as nativeConnect, initThreadPool, MainWorker } from "./index-tu * @returns {Promise} - A promise that resolves to a Database instance. */ async function connect(path: string, opts: DatabaseOpts = {}): Promise { - return await promiseConnect(path, opts, nativeConnect, async () => { + const init = async () => { await initThreadPool(); if (MainWorker == null) { throw new Error("panic: MainWorker is not initialized"); } return MainWorker; - }); + }; + return await promiseConnect( + path, + opts, + connectDbAsync, + init + ); } export { connect, Database, SqliteError } diff --git a/bindings/javascript/packages/browser/promise-vite-dev-hack.ts b/bindings/javascript/packages/browser/promise-vite-dev-hack.ts index 9e3e59e14..5b3c4acda 100644 --- a/bindings/javascript/packages/browser/promise-vite-dev-hack.ts +++ b/bindings/javascript/packages/browser/promise-vite-dev-hack.ts @@ -1,6 +1,6 @@ import { DatabaseOpts, SqliteError, } from "@tursodatabase/database-common" -import { connect as promiseConnect, Database } from "./promise.js"; -import { connect as nativeConnect, initThreadPool, MainWorker } from "./index-vite-dev-hack.js"; +import { Database, connect as promiseConnect } from "./promise.js"; +import { initThreadPool, MainWorker, connectDbAsync } from "./index-vite-dev-hack.js"; /** * Creates a new database connection asynchronously. @@ -10,13 +10,19 @@ import { connect as nativeConnect, initThreadPool, MainWorker } from "./index-vi * @returns {Promise} - A promise that resolves to a Database instance. */ async function connect(path: string, opts: DatabaseOpts = {}): Promise { - return await promiseConnect(path, opts, nativeConnect, async () => { + const init = async () => { await initThreadPool(); if (MainWorker == null) { throw new Error("panic: MainWorker is not initialized"); } return MainWorker; - }); + }; + return await promiseConnect( + path, + opts, + connectDbAsync, + init + ); } export { connect, Database, SqliteError } diff --git a/bindings/javascript/packages/browser/promise.test.ts b/bindings/javascript/packages/browser/promise.test.ts index 7e76ec029..0f9cebff8 100644 --- a/bindings/javascript/packages/browser/promise.test.ts +++ b/bindings/javascript/packages/browser/promise.test.ts @@ -1,4 +1,4 @@ -import { expect, test, afterEach } from 'vitest' +import { expect, test } from 'vitest' import { connect } from './promise-default.js' test('in-memory db', async () => { @@ -10,6 +10,28 @@ test('in-memory db', async () => { expect(rows).toEqual([{ x: 1 }, { x: 3 }]); }) +test('on-disk db large inserts', async () => { + const path = `test-${(Math.random() * 10000) | 0}.db`; + const db1 = await connect(path); + await db1.prepare("CREATE TABLE t(x)").run(); + await db1.prepare("INSERT INTO t VALUES (randomblob(10 * 4096 + 0))").run(); + await db1.prepare("INSERT INTO t VALUES (randomblob(10 * 4096 + 1))").run(); + await db1.prepare("INSERT INTO t VALUES (randomblob(10 * 4096 + 2))").run(); + const stmt1 = db1.prepare("SELECT length(x) as l FROM t"); + expect(stmt1.columns()).toEqual([{ name: "l", column: null, database: null, table: null, type: null }]); + const rows1 = await stmt1.all(); + expect(rows1).toEqual([{ l: 10 * 4096 }, { l: 10 * 4096 + 1 }, { l: 10 * 4096 + 2 }]); + + await db1.exec("BEGIN"); + await db1.exec("INSERT INTO t VALUES (1)"); + await db1.exec("ROLLBACK"); + + const rows2 = await db1.prepare("SELECT length(x) as l FROM t").all(); + expect(rows2).toEqual([{ l: 10 * 4096 }, { l: 10 * 4096 + 1 }, { l: 10 * 4096 + 2 }]); + + await db1.prepare("PRAGMA wal_checkpoint(TRUNCATE)").run(); +}) + test('on-disk db', async () => { const path = `test-${(Math.random() * 10000) | 0}.db`; const db1 = await connect(path); @@ -19,8 +41,8 @@ test('on-disk db', async () => { expect(stmt1.columns()).toEqual([{ name: "x", column: null, database: null, table: null, type: null }]); const rows1 = await stmt1.all([1]); expect(rows1).toEqual([{ x: 1 }, { x: 3 }]); - await db1.close(); stmt1.close(); + await db1.close(); const db2 = await connect(path); const stmt2 = db2.prepare("SELECT * FROM t WHERE x % 2 = ?"); @@ -30,23 +52,24 @@ test('on-disk db', async () => { db2.close(); }) -test('attach', async () => { - const path1 = `test-${(Math.random() * 10000) | 0}.db`; - const path2 = `test-${(Math.random() * 10000) | 0}.db`; - const db1 = await connect(path1); - await db1.exec("CREATE TABLE t(x)"); - await db1.exec("INSERT INTO t VALUES (1), (2), (3)"); - const db2 = await connect(path2); - await db2.exec("CREATE TABLE q(x)"); - await db2.exec("INSERT INTO q VALUES (4), (5), (6)"); +// attach is not supported in browser for now +// test('attach', async () => { +// const path1 = `test-${(Math.random() * 10000) | 0}.db`; +// const path2 = `test-${(Math.random() * 10000) | 0}.db`; +// const db1 = await connect(path1); +// await db1.exec("CREATE TABLE t(x)"); +// await db1.exec("INSERT INTO t VALUES (1), (2), (3)"); +// const db2 = await connect(path2); +// await db2.exec("CREATE TABLE q(x)"); +// await db2.exec("INSERT INTO q VALUES (4), (5), (6)"); - await db1.exec(`ATTACH '${path2}' as secondary`); +// await db1.exec(`ATTACH '${path2}' as secondary`); - const stmt = db1.prepare("SELECT * FROM t UNION ALL SELECT * FROM secondary.q"); - expect(stmt.columns()).toEqual([{ name: "x", column: null, database: null, table: null, type: null }]); - const rows = await stmt.all([1]); - expect(rows).toEqual([{ x: 1 }, { x: 2 }, { x: 3 }, { x: 4 }, { x: 5 }, { x: 6 }]); -}) +// const stmt = db1.prepare("SELECT * FROM t UNION ALL SELECT * FROM secondary.q"); +// expect(stmt.columns()).toEqual([{ name: "x", column: null, database: null, table: null, type: null }]); +// const rows = await stmt.all([1]); +// expect(rows).toEqual([{ x: 1 }, { x: 2 }, { x: 3 }, { x: 4 }, { x: 5 }, { x: 6 }]); +// }) test('blobs', async () => { const db = await connect(":memory:"); diff --git a/bindings/javascript/packages/common/async-lock.ts b/bindings/javascript/packages/common/async-lock.ts new file mode 100644 index 000000000..cf69a8f39 --- /dev/null +++ b/bindings/javascript/packages/common/async-lock.ts @@ -0,0 +1,29 @@ +export class AsyncLock { + locked: boolean; + queue: any[]; + constructor() { + this.locked = false; + this.queue = [] + } + async acquire() { + if (!this.locked) { + this.locked = true; + return Promise.resolve(); + } else { + const block = new Promise(resolve => { this.queue.push(resolve) }); + return block; + } + } + release() { + if (this.locked == false) { + throw new Error("invalid state: lock was already unlocked"); + } + const item = this.queue.shift(); + if (item != null) { + this.locked = true; + item(); + } else { + this.locked = false; + } + } +} \ No newline at end of file diff --git a/bindings/javascript/packages/common/compat.ts b/bindings/javascript/packages/common/compat.ts index d7bd493bb..be8c46d56 100644 --- a/bindings/javascript/packages/common/compat.ts +++ b/bindings/javascript/packages/common/compat.ts @@ -192,7 +192,12 @@ class Database { } try { - this.db.batchSync(sql); + let stmt = this.prepare(sql); + try { + stmt.run(); + } finally { + stmt.close(); + } } catch (err) { throw convertError(err); } @@ -408,6 +413,10 @@ class Statement { throw convertError(err); } } + + close() { + this.stmt.finalize(); + } } export { Database, Statement } \ No newline at end of file diff --git a/bindings/javascript/packages/common/index.ts b/bindings/javascript/packages/common/index.ts index 35e092d03..40a44b573 100644 --- a/bindings/javascript/packages/common/index.ts +++ b/bindings/javascript/packages/common/index.ts @@ -2,5 +2,6 @@ import { NativeDatabase, NativeStatement, DatabaseOpts } from "./types.js"; import { Database as DatabaseCompat, Statement as StatementCompat } from "./compat.js"; import { Database as DatabasePromise, Statement as StatementPromise } from "./promise.js"; import { SqliteError } from "./sqlite-error.js"; +import { AsyncLock } from "./async-lock.js"; -export { DatabaseCompat, StatementCompat, DatabasePromise, StatementPromise, NativeDatabase, NativeStatement, SqliteError, DatabaseOpts } +export { DatabaseCompat, StatementCompat, DatabasePromise, StatementPromise, NativeDatabase, NativeStatement, SqliteError, DatabaseOpts, AsyncLock } diff --git a/bindings/javascript/packages/common/promise.ts b/bindings/javascript/packages/common/promise.ts index e81795833..3009b2fcb 100644 --- a/bindings/javascript/packages/common/promise.ts +++ b/bindings/javascript/packages/common/promise.ts @@ -1,3 +1,4 @@ +import { AsyncLock } from "./async-lock.js"; import { bindParams } from "./bind.js"; import { SqliteError } from "./sqlite-error.js"; import { NativeDatabase, NativeStatement, STEP_IO, STEP_ROW, STEP_DONE, DatabaseOpts } from "./types.js"; @@ -32,6 +33,7 @@ class Database { db: NativeDatabase; memory: boolean; open: boolean; + execLock: AsyncLock; private _inTransaction: boolean = false; /** * Creates a new database connection. If the database file pointed to by `path` does not exists, it will be created. @@ -57,6 +59,7 @@ class Database { initialize(db: NativeDatabase, name, readonly) { this.db = db; this.memory = db.memory; + this.execLock = new AsyncLock(); Object.defineProperties(this, { inTransaction: { get: () => this._inTransaction, @@ -195,10 +198,11 @@ class Database { throw new TypeError("The database connection is not open"); } + const stmt = this.prepare(sql); try { - await this.db.batchAsync(sql); - } catch (err) { - throw convertError(err); + await stmt.run(); + } finally { + stmt.close(); } } @@ -297,25 +301,30 @@ class Statement { this.stmt.reset(); bindParams(this.stmt, bindParameters); - while (true) { - const stepResult = await this.stmt.stepAsync(); - if (stepResult === STEP_IO) { - await this.db.db.ioLoopAsync(); - continue; - } - if (stepResult === STEP_DONE) { - break; - } - if (stepResult === STEP_ROW) { - // For run(), we don't need the row data, just continue - continue; + await this.db.execLock.acquire(); + try { + while (true) { + const stepResult = await this.stmt.stepSync(); + if (stepResult === STEP_IO) { + await this.db.db.ioLoopAsync(); + continue; + } + if (stepResult === STEP_DONE) { + break; + } + if (stepResult === STEP_ROW) { + // For run(), we don't need the row data, just continue + continue; + } } + + const lastInsertRowid = this.db.db.lastInsertRowid(); + const changes = this.db.db.totalChanges() === totalChangesBefore ? 0 : this.db.db.changes(); + + return { changes, lastInsertRowid }; + } finally { + this.db.execLock.release(); } - - const lastInsertRowid = this.db.db.lastInsertRowid(); - const changes = this.db.db.totalChanges() === totalChangesBefore ? 0 : this.db.db.changes(); - - return { changes, lastInsertRowid }; } /** @@ -327,18 +336,23 @@ class Statement { this.stmt.reset(); bindParams(this.stmt, bindParameters); - while (true) { - const stepResult = await this.stmt.stepAsync(); - if (stepResult === STEP_IO) { - await this.db.db.ioLoopAsync(); - continue; - } - if (stepResult === STEP_DONE) { - return undefined; - } - if (stepResult === STEP_ROW) { - return this.stmt.row(); + await this.db.execLock.acquire(); + try { + while (true) { + const stepResult = await this.stmt.stepSync(); + if (stepResult === STEP_IO) { + await this.db.db.ioLoopAsync(); + continue; + } + if (stepResult === STEP_DONE) { + return undefined; + } + if (stepResult === STEP_ROW) { + return this.stmt.row(); + } } + } finally { + this.db.execLock.release(); } } @@ -351,18 +365,23 @@ class Statement { this.stmt.reset(); bindParams(this.stmt, bindParameters); - while (true) { - const stepResult = await this.stmt.stepAsync(); - if (stepResult === STEP_IO) { - await this.db.db.ioLoopAsync(); - continue; - } - if (stepResult === STEP_DONE) { - break; - } - if (stepResult === STEP_ROW) { - yield this.stmt.row(); + await this.db.execLock.acquire(); + try { + while (true) { + const stepResult = await this.stmt.stepSync(); + if (stepResult === STEP_IO) { + await this.db.db.ioLoopAsync(); + continue; + } + if (stepResult === STEP_DONE) { + break; + } + if (stepResult === STEP_ROW) { + yield this.stmt.row(); + } } + } finally { + this.db.execLock.release(); } } @@ -376,20 +395,26 @@ class Statement { bindParams(this.stmt, bindParameters); const rows: any[] = []; - while (true) { - const stepResult = await this.stmt.stepAsync(); - if (stepResult === STEP_IO) { - await this.db.db.ioLoopAsync(); - continue; - } - if (stepResult === STEP_DONE) { - break; - } - if (stepResult === STEP_ROW) { - rows.push(this.stmt.row()); + await this.db.execLock.acquire(); + try { + while (true) { + const stepResult = await this.stmt.stepSync(); + if (stepResult === STEP_IO) { + await this.db.db.ioLoopAsync(); + continue; + } + if (stepResult === STEP_DONE) { + break; + } + if (stepResult === STEP_ROW) { + rows.push(this.stmt.row()); + } } + return rows; + } + finally { + this.db.execLock.release(); } - return rows; } /** diff --git a/bindings/javascript/packages/native/index.d.ts b/bindings/javascript/packages/native/index.d.ts index 8654b88d2..cfd72609e 100644 --- a/bindings/javascript/packages/native/index.d.ts +++ b/bindings/javascript/packages/native/index.d.ts @@ -15,26 +15,6 @@ export declare class Database { get path(): string /** Returns whether the database connection is open. */ get open(): boolean - /** - * Executes a batch of SQL statements on main thread - * - * # Arguments - * - * * `sql` - The SQL statements to execute. - * - * # Returns - */ - batchSync(sql: string): void - /** - * Executes a batch of SQL statements outside of main thread - * - * # Arguments - * - * * `sql` - The SQL statements to execute. - * - * # Returns - */ - batchAsync(sql: string): Promise /** * Prepares a statement for execution. * diff --git a/bindings/javascript/packages/native/package.json b/bindings/javascript/packages/native/package.json index 81b8e092c..56888f616 100644 --- a/bindings/javascript/packages/native/package.json +++ b/bindings/javascript/packages/native/package.json @@ -22,6 +22,9 @@ "devDependencies": { "@napi-rs/cli": "^3.1.5", "@types/node": "^24.3.1", + "better-sqlite3": "^12.2.0", + "drizzle-kit": "^0.31.4", + "drizzle-orm": "^0.44.5", "typescript": "^5.9.2", "vitest": "^3.2.4" }, diff --git a/bindings/javascript/packages/native/promise.test.ts b/bindings/javascript/packages/native/promise.test.ts index d75e3728e..a554154cd 100644 --- a/bindings/javascript/packages/native/promise.test.ts +++ b/bindings/javascript/packages/native/promise.test.ts @@ -1,8 +1,28 @@ import { unlinkSync } from "node:fs"; import { expect, test } from 'vitest' import { connect } from './promise.js' +import { sql } from 'drizzle-orm'; +import { drizzle } from 'drizzle-orm/better-sqlite3'; -test('in-memory db', async () => { +test('drizzle-orm', async () => { + const path = `test-${(Math.random() * 10000) | 0}.db`; + try { + const conn = await connect(path); + const db = drizzle(conn); + await db.run('CREATE TABLE t(x, y)'); + let tasks = []; + for (let i = 0; i < 1234; i++) { + tasks.push(db.run(sql`INSERT INTO t VALUES (${i}, randomblob(${i} * 5))`)) + } + await Promise.all(tasks); + expect(await db.all("SELECT COUNT(*) as cnt FROM t")).toEqual([{ cnt: 1234 }]) + } finally { + unlinkSync(path); + unlinkSync(`${path}-wal`); + } +}) + +test('in-memory-db-async', async () => { const db = await connect(":memory:"); await db.exec("CREATE TABLE t(x)"); await db.exec("INSERT INTO t VALUES (1), (2), (3)"); diff --git a/bindings/javascript/perf/package-lock.json b/bindings/javascript/perf/package-lock.json index bf737b714..7ec8c6bdf 100644 --- a/bindings/javascript/perf/package-lock.json +++ b/bindings/javascript/perf/package-lock.json @@ -20,10 +20,10 @@ }, "../packages/native": { "name": "@tursodatabase/database", - "version": "0.1.5-pre.3", + "version": "0.2.0-pre.3", "license": "MIT", "dependencies": { - "@tursodatabase/database-common": "^0.1.5-pre.3" + "@tursodatabase/database-common": "^0.2.0-pre.3" }, "devDependencies": { "@napi-rs/cli": "^3.1.5", diff --git a/bindings/javascript/perf/perf-turso.js b/bindings/javascript/perf/perf-turso.js index 092730265..91c2b7d2a 100644 --- a/bindings/javascript/perf/perf-turso.js +++ b/bindings/javascript/perf/perf-turso.js @@ -1,26 +1,26 @@ import { run, bench, group, baseline } from 'mitata'; -import { Database } from '@tursodatabase/database/compat'; +import { Database } from '@tursodatabase/database'; const db = new Database(':memory:'); -db.exec("CREATE TABLE users (id INTEGER, name TEXT, email TEXT)"); -db.exec("INSERT INTO users (id, name, email) VALUES (1, 'Alice', 'alice@example.org')"); +await db.exec("CREATE TABLE users (id INTEGER, name TEXT, email TEXT)"); +await db.exec("INSERT INTO users (id, name, email) VALUES (1, 'Alice', 'alice@example.org')"); const stmtSelect = db.prepare("SELECT * FROM users WHERE id = ?"); const rawStmtSelect = db.prepare("SELECT * FROM users WHERE id = ?").raw(); const stmtInsert = db.prepare("INSERT INTO users (id, name, email) VALUES (?, ?, ?)"); -bench('Statement.get() with bind parameters [expanded]', () => { - stmtSelect.get(1); +bench('Statement.get() with bind parameters [expanded]', async () => { + await stmtSelect.get(1); }); -bench('Statement.get() with bind parameters [raw]', () => { - rawStmtSelect.get(1); +bench('Statement.get() with bind parameters [raw]', async () => { + await rawStmtSelect.get(1); }); -bench('Statement.run() with bind parameters', () => { - stmtInsert.run([1, 'foobar', 'foobar@example.com']); +bench('Statement.run() with bind parameters', async () => { + await stmtInsert.run([1, 'foobar', 'foobar@example.com']); }); await run({ diff --git a/bindings/javascript/src/browser.rs b/bindings/javascript/src/browser.rs index 92c818b4c..16b071ec8 100644 --- a/bindings/javascript/src/browser.rs +++ b/bindings/javascript/src/browser.rs @@ -1,10 +1,10 @@ -use std::sync::Arc; +use std::{cell::RefCell, collections::HashMap, sync::Arc}; use napi::bindgen_prelude::*; use napi_derive::napi; -use turso_core::{storage::database::DatabaseFile, Clock, File, Instant, IO}; +use turso_core::{Clock, Completion, File, Instant, MemoryIO, IO}; -use crate::{init_tracing, is_memory, Database, DatabaseOpts}; +use crate::{is_memory, Database, DatabaseOpts}; pub struct NoopTask; @@ -29,11 +29,11 @@ pub fn init_thread_pool() -> napi::Result> { pub struct ConnectTask { path: String, io: Arc, + opts: Option, } pub struct ConnectResult { - db: Arc, - conn: Arc, + db: Database, } unsafe impl Send for ConnectResult {} @@ -43,79 +43,108 @@ impl Task for ConnectTask { type JsValue = Database; fn compute(&mut self) -> Result { - let file = self - .io - .open_file(&self.path, turso_core::OpenFlags::Create, false) - .map_err(|e| Error::new(Status::GenericFailure, format!("Failed to open file: {e}")))?; - - let db_file = Arc::new(DatabaseFile::new(file)); - let db = turso_core::Database::open(self.io.clone(), &self.path, db_file, false, true) - .map_err(|e| { - Error::new( - Status::GenericFailure, - format!("Failed to open database: {e}"), - ) - })?; - - let conn = db - .connect() - .map_err(|e| Error::new(Status::GenericFailure, format!("Failed to connect: {e}")))?; - - Ok(ConnectResult { db, conn }) + let db = Database::new_io(self.path.clone(), self.io.clone(), self.opts.clone())?; + Ok(ConnectResult { db }) } fn resolve(&mut self, _: Env, result: Self::Output) -> Result { - Ok(Database::create( - Some(result.db), - self.io.clone(), - result.conn, - self.path.clone(), - )) + Ok(result.db) } } -#[napi] -// we offload connect to the web-worker because: -// 1. browser main-thread do not support Atomic.wait operations -// 2. turso-db use blocking IO [io.wait_for_completion(c)] in few places during initialization path -// -// so, we offload connect to the worker thread -pub fn connect(path: String, opts: Option) -> Result> { - if let Some(opts) = opts { - init_tracing(opts.tracing); - } - let task = if is_memory(&path) { - ConnectTask { - io: Arc::new(turso_core::MemoryIO::new()), - path, - } - } else { - let io = Arc::new(Opfs::new()?); - ConnectTask { io, path } - }; - Ok(AsyncTask::new(task)) -} #[napi] #[derive(Clone)] -pub struct Opfs; +pub struct Opfs { + inner: Arc, +} + +pub struct OpfsInner { + completion_no: RefCell, + completions: RefCell>, +} + +thread_local! { + static OPFS: Arc = Arc::new(Opfs::default()); +} #[napi] #[derive(Clone)] struct OpfsFile { handle: i32, + opfs: Opfs, +} + +unsafe impl Send for Opfs {} +unsafe impl Sync for Opfs {} + +#[napi] +// we offload connect to the web-worker because +// turso-db use blocking IO [io.wait_for_completion(c)] in few places during initialization path +pub fn connect_db_async( + path: String, + opts: Option, +) -> Result> { + let io: Arc = if is_memory(&path) { + Arc::new(MemoryIO::new()) + } else { + // we must create OPFS IO on the main thread + opfs() + }; + let task = ConnectTask { path, io, opts }; + Ok(AsyncTask::new(task)) } #[napi] +pub fn complete_opfs(completion_no: u32, result: i32) { + OPFS.with(|opfs| opfs.complete(completion_no, result)) +} + +pub fn opfs() -> Arc { + OPFS.with(|opfs| opfs.clone()) +} + impl Opfs { - #[napi(constructor)] - pub fn new() -> napi::Result { - Ok(Self) + pub fn complete(&self, completion_no: u32, result: i32) { + let completion = { + let mut completions = self.inner.completions.borrow_mut(); + completions.remove(&completion_no).unwrap() + }; + completion.complete(result); + } + + fn register_completion(&self, c: Completion) -> u32 { + let inner = &self.inner; + *inner.completion_no.borrow_mut() += 1; + let completion_no = *inner.completion_no.borrow(); + tracing::debug!( + "register completion: {} {:?}", + completion_no, + Arc::as_ptr(inner) + ); + inner.completions.borrow_mut().insert(completion_no, c); + completion_no } } impl Clock for Opfs { fn now(&self) -> Instant { - Instant { secs: 0, micros: 0 } // TODO + let now = chrono::Local::now(); + Instant { + secs: now.timestamp(), + micros: now.timestamp_subsec_micros(), + } + } +} + +impl Default for Opfs { + fn default() -> Self { + Self { + #[allow(clippy::arc_with_non_send_sync)] + inner: Arc::new(OpfsInner { + completion_no: RefCell::new(0), + completions: RefCell::new(HashMap::new()), + }), + } } } @@ -127,6 +156,13 @@ extern "C" { fn sync(handle: i32) -> i32; fn truncate(handle: i32, length: usize) -> i32; fn size(handle: i32) -> i32; + + fn write_async(handle: i32, buffer: *const u8, buffer_len: usize, offset: i32, c: u32); + fn sync_async(handle: i32, c: u32); + fn read_async(handle: i32, buffer: *mut u8, buffer_len: usize, offset: i32, c: u32); + fn truncate_async(handle: i32, length: usize, c: u32); + // fn size_async(handle: i32) -> i32; + fn is_web_worker() -> bool; } @@ -144,7 +180,12 @@ impl IO for Opfs { tracing::info!("open_file: {}", path); let result = unsafe { lookup_file(path.as_ptr(), path.len()) }; if result >= 0 { - Ok(Arc::new(OpfsFile { handle: result })) + Ok(Arc::new(OpfsFile { + handle: result, + opfs: Opfs { + inner: self.inner.clone(), + }, + })) } else if result == -404 { Err(turso_core::LimboError::InternalError(format!( "unexpected path {path}: files must be created in advance for OPFS IO" @@ -175,17 +216,32 @@ impl File for OpfsFile { pos: u64, c: turso_core::Completion, ) -> turso_core::Result { - assert!( - is_web_worker_safe(), - "opfs must be used only from web worker for now" + let web_worker = is_web_worker_safe(); + tracing::debug!( + "pread({}, is_web_worker={}): pos={}", + self.handle, + web_worker, + pos ); - tracing::debug!("pread({}): pos={}", self.handle, pos); let handle = self.handle; let read_c = c.as_read(); let buffer = read_c.buf_arc(); let buffer = buffer.as_mut_slice(); - let result = unsafe { read(handle, buffer.as_mut_ptr(), buffer.len(), pos as i32) }; - c.complete(result as i32); + if web_worker { + let result = unsafe { read(handle, buffer.as_mut_ptr(), buffer.len(), pos as i32) }; + c.complete(result as i32); + } else { + let completion_no = self.opfs.register_completion(c.clone()); + unsafe { + read_async( + handle, + buffer.as_mut_ptr(), + buffer.len(), + pos as i32, + completion_no, + ) + }; + } Ok(c) } @@ -195,27 +251,44 @@ impl File for OpfsFile { buffer: Arc, c: turso_core::Completion, ) -> turso_core::Result { - assert!( - is_web_worker_safe(), - "opfs must be used only from web worker for now" + let web_worker = is_web_worker_safe(); + tracing::debug!( + "pwrite({}, is_web_worker={}): pos={}", + self.handle, + web_worker, + pos ); - tracing::debug!("pwrite({}): pos={}", self.handle, pos); let handle = self.handle; let buffer = buffer.as_slice(); - let result = unsafe { write(handle, buffer.as_ptr(), buffer.len(), pos as i32) }; - c.complete(result as i32); + if web_worker { + let result = unsafe { write(handle, buffer.as_ptr(), buffer.len(), pos as i32) }; + c.complete(result as i32); + } else { + let completion_no = self.opfs.register_completion(c.clone()); + unsafe { + write_async( + handle, + buffer.as_ptr(), + buffer.len(), + pos as i32, + completion_no, + ) + }; + } Ok(c) } fn sync(&self, c: turso_core::Completion) -> turso_core::Result { - assert!( - is_web_worker_safe(), - "opfs must be used only from web worker for now" - ); - tracing::debug!("sync({})", self.handle); + let web_worker = is_web_worker_safe(); + tracing::debug!("sync({}, is_web_worker={})", self.handle, web_worker); let handle = self.handle; - let result = unsafe { sync(handle) }; - c.complete(result as i32); + if web_worker { + let result = unsafe { sync(handle) }; + c.complete(result as i32); + } else { + let completion_no = self.opfs.register_completion(c.clone()); + unsafe { sync_async(handle, completion_no) }; + } Ok(c) } @@ -224,14 +297,21 @@ impl File for OpfsFile { len: u64, c: turso_core::Completion, ) -> turso_core::Result { - assert!( - is_web_worker_safe(), - "opfs must be used only from web worker for now" + let web_worker = is_web_worker_safe(); + tracing::debug!( + "truncate({}, is_web_worker={}): len={}", + self.handle, + web_worker, + len ); - tracing::debug!("truncate({}): len={}", self.handle, len); let handle = self.handle; - let result = unsafe { truncate(handle, len as usize) }; - c.complete(result as i32); + if web_worker { + let result = unsafe { truncate(handle, len as usize) }; + c.complete(result as i32); + } else { + let completion_no = self.opfs.register_completion(c.clone()); + unsafe { truncate_async(handle, len as usize, completion_no) }; + } Ok(c) } diff --git a/bindings/javascript/src/lib.rs b/bindings/javascript/src/lib.rs index d479f101d..df4724e6e 100644 --- a/bindings/javascript/src/lib.rs +++ b/bindings/javascript/src/lib.rs @@ -60,6 +60,8 @@ pub(crate) fn init_tracing(level_filter: Option) { return; }; let level_filter = match level_filter.as_ref() { + "error" => LevelFilter::ERROR, + "warn" => LevelFilter::WARN, "info" => LevelFilter::INFO, "debug" => LevelFilter::DEBUG, "trace" => LevelFilter::TRACE, @@ -76,10 +78,6 @@ pub(crate) fn init_tracing(level_filter: Option) { } pub enum DbTask { - Batch { - conn: Arc, - sql: String, - }, Step { stmt: Arc>>, }, @@ -93,10 +91,6 @@ impl Task for DbTask { fn compute(&mut self) -> Result { match self { - DbTask::Batch { conn, sql } => { - batch_sync(conn, sql)?; - Ok(0) - } DbTask::Step { stmt } => step_sync(stmt), } } @@ -107,20 +101,11 @@ impl Task for DbTask { } #[napi(object)] +#[derive(Clone)] pub struct DatabaseOpts { pub tracing: Option, } -fn batch_sync(conn: &Arc, sql: &str) -> napi::Result<()> { - conn.prepare_execute_batch(sql).map_err(|e| { - Error::new( - Status::GenericFailure, - format!("Failed to execute batch: {e}"), - ) - })?; - Ok(()) -} - fn step_sync(stmt: &Arc>>) -> napi::Result { let mut stmt_ref = stmt.borrow_mut(); let stmt = stmt_ref @@ -152,21 +137,38 @@ impl Database { /// # Arguments /// * `path` - The path to the database file. #[napi(constructor)] + pub fn new_napi(path: String, opts: Option) -> Result { + Self::new(path, opts) + } + pub fn new(path: String, opts: Option) -> Result { - if let Some(opts) = opts { - init_tracing(opts.tracing); - } let io: Arc = if is_memory(&path) { Arc::new(turso_core::MemoryIO::new()) } else { - Arc::new(turso_core::PlatformIO::new().map_err(|e| { - Error::new(Status::GenericFailure, format!("Failed to create IO: {e}")) - })?) + #[cfg(not(feature = "browser"))] + { + Arc::new(turso_core::PlatformIO::new().map_err(|e| { + Error::new(Status::GenericFailure, format!("Failed to create IO: {e}")) + })?) + } + #[cfg(feature = "browser")] + { + return Err(napi::Error::new( + napi::Status::GenericFailure, + "FS-backed db must be initialized through connectDbAsync function in the browser", + )); + } }; + Self::new_io(path, io, opts) + } - #[cfg(feature = "browser")] - if !is_memory(&path) { - return Err(Error::new(Status::GenericFailure, "sync constructor is not supported for FS-backed databases in the WASM. Use async connect(...) method instead".to_string())); + pub fn new_io( + path: String, + io: Arc, + opts: Option, + ) -> Result { + if let Some(opts) = opts { + init_tracing(opts.tracing); } let file = io @@ -233,33 +235,6 @@ impl Database { self.is_open.get() } - /// Executes a batch of SQL statements on main thread - /// - /// # Arguments - /// - /// * `sql` - The SQL statements to execute. - /// - /// # Returns - #[napi] - pub fn batch_sync(&self, sql: String) -> Result<()> { - batch_sync(&self.conn()?, &sql) - } - - /// Executes a batch of SQL statements outside of main thread - /// - /// # Arguments - /// - /// * `sql` - The SQL statements to execute. - /// - /// # Returns - #[napi(ts_return_type = "Promise")] - pub fn batch_async(&self, sql: String) -> Result> { - Ok(AsyncTask::new(DbTask::Batch { - conn: self.conn()?.clone(), - sql, - })) - } - /// Prepares a statement for execution. /// /// # Arguments @@ -325,8 +300,8 @@ impl Database { #[napi] pub fn close(&mut self) -> Result<()> { self.is_open.set(false); - let _ = self._db.take(); let _ = self.conn.take().unwrap(); + let _ = self._db.take(); Ok(()) } @@ -621,7 +596,12 @@ impl Statement { /// Finalizes the statement. #[napi] pub fn finalize(&self) -> Result<()> { - self.stmt.borrow_mut().take(); + match self.stmt.try_borrow_mut() { + Ok(mut stmt) => { + stmt.take(); + } + Err(err) => tracing::error!("borrow error: {:?}", err), + } Ok(()) } } diff --git a/bindings/javascript/sync/Cargo.toml b/bindings/javascript/sync/Cargo.toml index 2f3f3d177..1057c4e8f 100644 --- a/bindings/javascript/sync/Cargo.toml +++ b/bindings/javascript/sync/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true crate-type = ["cdylib"] [dependencies] -http = "1.3.1" napi = { version = "3.1.3", default-features = false, features = ["napi6"] } napi-derive = { version = "3.1.1", default-features = true } turso_sync_engine = { workspace = true } @@ -18,9 +17,10 @@ turso_core = { workspace = true } turso_node = { workspace = true } genawaiter = { version = "0.99.1", default-features = false } tracing-subscriber = { workspace = true } +tracing.workspace = true [build-dependencies] napi-build = "2.2.3" [features] -browser = ["turso_node/browser"] \ No newline at end of file +browser = ["turso_node/browser"] diff --git a/bindings/javascript/sync/packages/browser/package.json b/bindings/javascript/sync/packages/browser/package.json index a7d33c2ce..e09740154 100644 --- a/bindings/javascript/sync/packages/browser/package.json +++ b/bindings/javascript/sync/packages/browser/package.json @@ -42,7 +42,7 @@ "tsc-build": "npm exec tsc && cp sync.wasm32-wasi.wasm ./dist/sync.wasm32-wasi.wasm && WASM_FILE=sync.wasm32-wasi.wasm JS_FILE=./dist/wasm-inline.js node ../../../scripts/inline-wasm-base64.js && npm run bundle", "bundle": "vite build", "build": "npm run napi-build && npm run tsc-build", - "test": "VITE_TURSO_DB_URL=http://b--a--a.localhost:10000 CI=1 vitest --browser=chromium --run && VITE_TURSO_DB_URL=http://b--a--a.localhost:10000 CI=1 vitest --browser=firefox --run" + "test": "VITE_TURSO_DB_URL=http://f--a--a.localhost:10000 CI=1 vitest --testTimeout 30000 --browser=chromium --run && VITE_TURSO_DB_URL=http://f--a--a.localhost:10000 CI=1 vitest --testTimeout 30000 --browser=firefox --run" }, "napi": { "binaryName": "sync", diff --git a/bindings/javascript/sync/packages/browser/promise.test.ts b/bindings/javascript/sync/packages/browser/promise.test.ts index e30163af0..ff271d0e6 100644 --- a/bindings/javascript/sync/packages/browser/promise.test.ts +++ b/bindings/javascript/sync/packages/browser/promise.test.ts @@ -260,6 +260,130 @@ test('persistence-pull-push', async () => { expect(rows2.sort(localeCompare)).toEqual(expected.sort(localeCompare)) }) +test('pull-push-concurrent', async () => { + { + const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL, longPollTimeoutMs: 5000 }); + await db.exec("CREATE TABLE IF NOT EXISTS q(x TEXT PRIMARY KEY, y)"); + await db.exec("DELETE FROM q"); + await db.push(); + await db.close(); + } + let pullResolve = null; + const pullFinish = new Promise(resolve => pullResolve = resolve); + let pushResolve = null; + const pushFinish = new Promise(resolve => pushResolve = resolve); + let stopPull = false; + let stopPush = false; + const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL }); + let pull = async () => { + try { + await db.pull(); + } catch (e) { + console.error('pull', e); + } finally { + if (!stopPull) { + setTimeout(pull, 0); + } else { + pullResolve() + } + } + } + let push = async () => { + try { + if ((await db.stats()).operations > 0) { + await db.push(); + } + } catch (e) { + console.error('push', e); + } finally { + if (!stopPush) { + setTimeout(push, 0); + } else { + pushResolve(); + } + } + } + setTimeout(pull, 0); + setTimeout(push, 0); + for (let i = 0; i < 1000; i++) { + await db.exec(`INSERT INTO q VALUES ('k${i}', 'v${i}')`); + } + await new Promise(resolve => setTimeout(resolve, 1000)); + stopPush = true; + await pushFinish; + stopPull = true; + await pullFinish; + console.info(await db.stats()); +}) + +test('concurrent-updates', { timeout: 60000 }, async () => { + { + const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL, longPollTimeoutMs: 10 }); + await db.exec("CREATE TABLE IF NOT EXISTS three(x TEXT PRIMARY KEY, y, z)"); + await db.exec("DELETE FROM three"); + await db.push(); + await db.close(); + } + let stop = false; + const dbs = []; + for (let i = 0; i < 8; i++) { + dbs.push(await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL })); + } + async function pull(db, i) { + try { + console.info('pull', i); + await db.pull(); + } catch (e) { + console.error('pull', i, e); + } finally { + if (!stop) { + setTimeout(async () => await pull(db, i), 0); + } + } + } + async function push(db, i) { + try { + console.info('push', i); + await db.push(); + } catch (e) { + console.error('push', i, e); + } finally { + if (!stop) { + setTimeout(async () => await push(db, i), 0); + } + } + } + for (let i = 0; i < dbs.length; i++) { + setTimeout(async () => await pull(dbs[i], i), 0) + setTimeout(async () => await push(dbs[i], i), 0) + } + for (let i = 0; i < 1000; i++) { + try { + const tasks = []; + for (let s = 0; s < dbs.length; s++) { + tasks.push(dbs[s].exec(`INSERT INTO three VALUES ('${s}', 0, randomblob(128)) ON CONFLICT DO UPDATE SET y = y + 1, z = randomblob(128)`)); + } + await Promise.all(tasks); + } catch (e) { + // ignore + } + await new Promise(resolve => setTimeout(resolve, 1)); + } + stop = true; + await Promise.all(dbs.map(db => db.push())); + await Promise.all(dbs.map(db => db.pull())); + let results = []; + for (let i = 0; i < dbs.length; i++) { + results.push(await dbs[i].prepare('SELECT x, y FROM three').all()); + } + for (let i = 0; i < dbs.length; i++) { + expect(results[i]).toEqual(results[0]); + for (let s = 0; s < dbs.length; s++) { + expect(results[i][s].y).toBeGreaterThan(500); + } + } +}) + test('transform', async () => { { const db = await connect({ diff --git a/bindings/javascript/sync/packages/browser/promise.ts b/bindings/javascript/sync/packages/browser/promise.ts index 3f43b81b6..b12680598 100644 --- a/bindings/javascript/sync/packages/browser/promise.ts +++ b/bindings/javascript/sync/packages/browser/promise.ts @@ -1,6 +1,6 @@ import { registerFileAtWorker, unregisterFileAtWorker } from "@tursodatabase/database-browser-common" import { DatabasePromise, DatabaseOpts, NativeDatabase } from "@tursodatabase/database-common" -import { ProtocolIo, run, SyncOpts, RunOpts, memoryIO, SyncEngineStats } from "@tursodatabase/sync-common"; +import { ProtocolIo, run, SyncOpts, RunOpts, memoryIO, SyncEngineStats, SyncEngineGuards } from "@tursodatabase/sync-common"; let BrowserIo: ProtocolIo = { async read(path: string): Promise { @@ -24,6 +24,7 @@ class Database extends DatabasePromise { io: ProtocolIo; worker: Worker | null; fsPath: string | null; + guards: SyncEngineGuards; constructor(db: NativeDatabase, io: ProtocolIo, worker: Worker | null, runOpts: RunOpts, engine: any, fsPath: string | null, opts: DatabaseOpts = {}) { super(db, opts) this.io = io; @@ -31,18 +32,21 @@ class Database extends DatabasePromise { this.runOpts = runOpts; this.engine = engine; this.fsPath = fsPath; + this.guards = new SyncEngineGuards(); } async sync() { - await run(this.runOpts, this.io, this.engine, this.engine.sync()); + await this.push(); + await this.pull(); } async pull() { - await run(this.runOpts, this.io, this.engine, this.engine.pull()); + const changes = await this.guards.wait(async () => await run(this.runOpts, this.io, this.engine, this.engine.wait())); + await this.guards.apply(async () => await run(this.runOpts, this.io, this.engine, this.engine.apply(changes))); } async push() { - await run(this.runOpts, this.io, this.engine, this.engine.push()); + await this.guards.push(async () => await run(this.runOpts, this.io, this.engine, this.engine.push())); } async checkpoint() { - await run(this.runOpts, this.io, this.engine, this.engine.checkpoint()); + await this.guards.checkpoint(async () => await run(this.runOpts, this.io, this.engine, this.engine.checkpoint())); } async stats(): Promise { return (await run(this.runOpts, this.io, this.engine, this.engine.stats())); @@ -76,7 +80,8 @@ async function connect(opts: SyncOpts, connect: (any) => any, init: () => Promis tablesIgnore: opts.tablesIgnore, useTransform: opts.transform != null, tracing: opts.tracing, - protocolVersion: 1 + protocolVersion: 1, + longPollTimeoutMs: opts.longPollTimeoutMs }); const runOpts: RunOpts = { url: opts.url, diff --git a/bindings/javascript/sync/packages/common/index.ts b/bindings/javascript/sync/packages/common/index.ts index 822a8c24f..7e9af0bea 100644 --- a/bindings/javascript/sync/packages/common/index.ts +++ b/bindings/javascript/sync/packages/common/index.ts @@ -1,5 +1,5 @@ -import { run, memoryIO } from "./run.js" +import { run, memoryIO, SyncEngineGuards } from "./run.js" import { SyncOpts, ProtocolIo, RunOpts, DatabaseRowMutation, DatabaseRowStatement, DatabaseRowTransformResult, SyncEngineStats } from "./types.js" -export { run, memoryIO, } +export { run, memoryIO, SyncEngineGuards } export type { SyncOpts, ProtocolIo, RunOpts, DatabaseRowMutation, DatabaseRowStatement, DatabaseRowTransformResult, SyncEngineStats } \ No newline at end of file diff --git a/bindings/javascript/sync/packages/common/package.json b/bindings/javascript/sync/packages/common/package.json index 44e04bd38..dc962ad31 100644 --- a/bindings/javascript/sync/packages/common/package.json +++ b/bindings/javascript/sync/packages/common/package.json @@ -21,5 +21,8 @@ "tsc-build": "npm exec tsc", "build": "npm run tsc-build", "test": "echo 'no tests'" + }, + "dependencies": { + "@tursodatabase/database-common": "^0.2.0-pre.3" } } diff --git a/bindings/javascript/sync/packages/common/run.ts b/bindings/javascript/sync/packages/common/run.ts index f26333d4b..f80606db8 100644 --- a/bindings/javascript/sync/packages/common/run.ts +++ b/bindings/javascript/sync/packages/common/run.ts @@ -1,6 +1,7 @@ "use strict"; import { GeneratorResponse, ProtocolIo, RunOpts } from "./types.js"; +import { AsyncLock } from "@tursodatabase/database-common"; const GENERATOR_RESUME_IO = 0; const GENERATOR_RESUME_DONE = 1; @@ -114,6 +115,10 @@ export async function run(opts: RunOpts, io: ProtocolIo, engine: any, generator: if (type == 'SyncEngineStats') { return rest; } + if (type == 'SyncEngineChanges') { + //@ts-ignore + return rest.changes; + } for (let request = engine.protocolIo(); request != null; request = engine.protocolIo()) { tasks.push(trackPromise(process(opts, io, request))); } @@ -124,4 +129,67 @@ export async function run(opts: RunOpts, io: ProtocolIo, engine: any, generator: tasks = tasks.filter(t => !t.finished); } return generator.take(); +} + + + +export class SyncEngineGuards { + waitLock: AsyncLock; + pushLock: AsyncLock; + pullLock: AsyncLock; + checkpointLock: AsyncLock; + constructor() { + this.waitLock = new AsyncLock(); + this.pushLock = new AsyncLock(); + this.pullLock = new AsyncLock(); + this.checkpointLock = new AsyncLock(); + } + async wait(f: () => Promise): Promise { + try { + await this.waitLock.acquire(); + return await f(); + } finally { + this.waitLock.release(); + } + } + async push(f: () => Promise) { + try { + await this.pushLock.acquire(); + await this.pullLock.acquire(); + await this.checkpointLock.acquire(); + return await f(); + } finally { + this.pushLock.release(); + this.pullLock.release(); + this.checkpointLock.release(); + } + } + async apply(f: () => Promise) { + try { + await this.waitLock.acquire(); + await this.pushLock.acquire(); + await this.pullLock.acquire(); + await this.checkpointLock.acquire(); + return await f(); + } finally { + this.waitLock.release(); + this.pushLock.release(); + this.pullLock.release(); + this.checkpointLock.release(); + } + } + async checkpoint(f: () => Promise) { + try { + await this.waitLock.acquire(); + await this.pushLock.acquire(); + await this.pullLock.acquire(); + await this.checkpointLock.acquire(); + return await f(); + } finally { + this.waitLock.release(); + this.pushLock.release(); + this.pullLock.release(); + this.checkpointLock.release(); + } + } } \ No newline at end of file diff --git a/bindings/javascript/sync/packages/common/tsconfig.json b/bindings/javascript/sync/packages/common/tsconfig.json index 9bc14edd3..2e4046e8a 100644 --- a/bindings/javascript/sync/packages/common/tsconfig.json +++ b/bindings/javascript/sync/packages/common/tsconfig.json @@ -3,8 +3,9 @@ "skipLibCheck": true, "declaration": true, "declarationMap": true, - "module": "esnext", + "module": "nodenext", "target": "esnext", + "moduleResolution": "nodenext", "outDir": "dist/", "lib": [ "es2020", diff --git a/bindings/javascript/sync/packages/common/types.ts b/bindings/javascript/sync/packages/common/types.ts index 49b140103..8391825cf 100644 --- a/bindings/javascript/sync/packages/common/types.ts +++ b/bindings/javascript/sync/packages/common/types.ts @@ -36,6 +36,7 @@ export interface SyncOpts { encryptionKey?: string; tablesIgnore?: string[], transform?: Transform, + longPollTimeoutMs?: number, tracing?: string, } @@ -53,4 +54,4 @@ export interface SyncEngineStats { revision: string | null; } -export type GeneratorResponse = { type: 'IO' } | { type: 'Done' } | ({ type: 'SyncEngineStats' } & SyncEngineStats) \ No newline at end of file +export type GeneratorResponse = { type: 'IO' } | { type: 'Done' } | ({ type: 'SyncEngineStats' } & SyncEngineStats) | { type: 'SyncEngineChanges', changes: any } \ No newline at end of file diff --git a/bindings/javascript/sync/packages/native/index.d.ts b/bindings/javascript/sync/packages/native/index.d.ts index 3ff5f0390..af73101f3 100644 --- a/bindings/javascript/sync/packages/native/index.d.ts +++ b/bindings/javascript/sync/packages/native/index.d.ts @@ -15,26 +15,6 @@ export declare class Database { get path(): string /** Returns whether the database connection is open. */ get open(): boolean - /** - * Executes a batch of SQL statements on main thread - * - * # Arguments - * - * * `sql` - The SQL statements to execute. - * - * # Returns - */ - batchSync(sql: string): void - /** - * Executes a batch of SQL statements outside of main thread - * - * # Arguments - * - * * `sql` - The SQL statements to execute. - * - * # Returns - */ - batchAsync(sql: string): Promise /** * Prepares a statement for execution. * @@ -178,15 +158,19 @@ export declare class SyncEngine { /** Runs the I/O loop asynchronously, returning a Promise. */ ioLoopAsync(): Promise protocolIo(): JsProtocolRequestBytes | null - sync(): GeneratorHolder push(): GeneratorHolder stats(): GeneratorHolder - pull(): GeneratorHolder + wait(): GeneratorHolder + apply(changes: SyncEngineChanges): GeneratorHolder checkpoint(): GeneratorHolder open(): Database close(): void } +export declare class SyncEngineChanges { + +} + export declare const enum DatabaseChangeTypeJs { Insert = 0, Update = 1, @@ -220,7 +204,8 @@ export type DatabaseRowTransformResultJs = export type GeneratorResponse = | { type: 'IO' } | { type: 'Done' } - | { type: 'SyncEngineStats', operations: number, mainWal: number, revertWal: number, lastPullUnixTime: number, lastPushUnixTime?: number } + | { type: 'SyncEngineStats', operations: number, mainWal: number, revertWal: number, lastPullUnixTime: number, lastPushUnixTime?: number, revision?: string } + | { type: 'SyncEngineChanges', changes: SyncEngineChanges } export type JsProtocolRequest = | { type: 'Http', method: string, path: string, body?: Array, headers: Array<[string, string]> } @@ -232,6 +217,7 @@ export interface SyncEngineOpts { path: string clientName?: string walPullBatchSize?: number + longPollTimeoutMs?: number tracing?: string tablesIgnore?: Array useTransform: boolean diff --git a/bindings/javascript/sync/packages/native/index.js b/bindings/javascript/sync/packages/native/index.js index 709ca74e4..cd543a959 100644 --- a/bindings/javascript/sync/packages/native/index.js +++ b/bindings/javascript/sync/packages/native/index.js @@ -508,7 +508,7 @@ if (!nativeBinding) { throw new Error(`Failed to load native binding`) } -const { Database, Statement, GeneratorHolder, JsDataCompletion, JsProtocolIo, JsProtocolRequestBytes, SyncEngine, DatabaseChangeTypeJs, SyncEngineProtocolVersion } = nativeBinding +const { Database, Statement, GeneratorHolder, JsDataCompletion, JsProtocolIo, JsProtocolRequestBytes, SyncEngine, SyncEngineChanges, DatabaseChangeTypeJs, SyncEngineProtocolVersion } = nativeBinding export { Database } export { Statement } export { GeneratorHolder } @@ -516,5 +516,6 @@ export { JsDataCompletion } export { JsProtocolIo } export { JsProtocolRequestBytes } export { SyncEngine } +export { SyncEngineChanges } export { DatabaseChangeTypeJs } export { SyncEngineProtocolVersion } diff --git a/bindings/javascript/sync/packages/native/package.json b/bindings/javascript/sync/packages/native/package.json index dcdc39fac..c7c52414f 100644 --- a/bindings/javascript/sync/packages/native/package.json +++ b/bindings/javascript/sync/packages/native/package.json @@ -31,7 +31,7 @@ "napi-artifacts": "napi artifacts --output-dir .", "tsc-build": "npm exec tsc", "build": "npm run napi-build && npm run tsc-build", - "test": "VITE_TURSO_DB_URL=http://b--a--a.localhost:10000 vitest --run", + "test": "VITE_TURSO_DB_URL=http://d--a--a.localhost:10000 vitest --run", "prepublishOnly": "npm run napi-dirs && npm run napi-artifacts && napi prepublish -t npm" }, "napi": { diff --git a/bindings/javascript/sync/packages/native/promise.test.ts b/bindings/javascript/sync/packages/native/promise.test.ts index cae58db11..fea253fef 100644 --- a/bindings/javascript/sync/packages/native/promise.test.ts +++ b/bindings/javascript/sync/packages/native/promise.test.ts @@ -160,7 +160,7 @@ test('checkpoint', async () => { await db1.checkpoint(); expect((await db1.stats()).mainWal).toBe(0); let revertWal = (await db1.stats()).revertWal; - expect(revertWal).toBeLessThan(4096 * 1000 / 100); + expect(revertWal).toBeLessThan(4096 * 1000 / 50); for (let i = 0; i < 1000; i++) { await db1.exec(`UPDATE q SET y = 'u${i}' WHERE x = 'k${i}'`); @@ -284,6 +284,119 @@ test('persistence-pull-push', async () => { } }) +test('update', async () => { + { + const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL, longPollTimeoutMs: 5000 }); + await db.exec("CREATE TABLE IF NOT EXISTS q(x TEXT PRIMARY KEY, y)"); + await db.exec("DELETE FROM q"); + await db.push(); + await db.close(); + } + const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL }); + await db.exec("INSERT INTO q VALUES ('1', '2')") + await db.push(); + await db.exec("INSERT INTO q VALUES ('1', '2') ON CONFLICT DO UPDATE SET y = '3'") + await db.push(); +}) + +test('concurrent-updates', async () => { + { + const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL, longPollTimeoutMs: 5000 }); + await db.exec("CREATE TABLE IF NOT EXISTS q(x TEXT PRIMARY KEY, y)"); + await db.exec("DELETE FROM q"); + await db.push(); + await db.close(); + } + const db1 = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL }); + async function pull(db) { + try { + await db.pull(); + } catch (e) { + // ignore + } finally { + setTimeout(async () => await pull(db), 0); + } + } + async function push(db) { + try { + await db.push(); + } catch (e) { + // ignore + } finally { + setTimeout(async () => await push(db), 0); + } + } + setTimeout(async () => await pull(db1), 0) + setTimeout(async () => await push(db1), 0) + for (let i = 0; i < 1000; i++) { + try { + await Promise.all([ + db1.exec(`INSERT INTO q VALUES ('1', 0) ON CONFLICT DO UPDATE SET y = ${i + 1}`), + db1.exec(`INSERT INTO q VALUES ('2', 0) ON CONFLICT DO UPDATE SET y = ${i + 1}`) + ]); + } catch (e) { + // ignore + } + await new Promise(resolve => setTimeout(resolve, 1)); + } +}) + +test('pull-push-concurrent', async () => { + { + const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL, longPollTimeoutMs: 5000 }); + await db.exec("CREATE TABLE IF NOT EXISTS q(x TEXT PRIMARY KEY, y)"); + await db.exec("DELETE FROM q"); + await db.push(); + await db.close(); + } + let pullResolve = null; + const pullFinish = new Promise(resolve => pullResolve = resolve); + let pushResolve = null; + const pushFinish = new Promise(resolve => pushResolve = resolve); + let stopPull = false; + let stopPush = false; + const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL }); + let pull = async () => { + try { + await db.pull(); + } catch (e) { + console.error('pull', e); + } finally { + if (!stopPull) { + setTimeout(pull, 0); + } else { + pullResolve() + } + } + } + let push = async () => { + try { + if ((await db.stats()).operations > 0) { + await db.push(); + } + } catch (e) { + console.error('push', e); + } finally { + if (!stopPush) { + setTimeout(push, 0); + } else { + pushResolve(); + } + } + } + setTimeout(pull, 0); + setTimeout(push, 0); + for (let i = 0; i < 1000; i++) { + await db.exec(`INSERT INTO q VALUES ('k${i}', 'v${i}')`); + } + await new Promise(resolve => setTimeout(resolve, 1000)); + stopPush = true; + await pushFinish; + stopPull = true; + await pullFinish; + console.info(await db.stats()); +}) + test('transform', async () => { { const db = await connect({ diff --git a/bindings/javascript/sync/packages/native/promise.ts b/bindings/javascript/sync/packages/native/promise.ts index 3d473c8a9..f00656b03 100644 --- a/bindings/javascript/sync/packages/native/promise.ts +++ b/bindings/javascript/sync/packages/native/promise.ts @@ -1,5 +1,5 @@ import { DatabasePromise, DatabaseOpts, NativeDatabase } from "@tursodatabase/database-common" -import { ProtocolIo, run, SyncOpts, RunOpts, DatabaseRowMutation, DatabaseRowStatement, DatabaseRowTransformResult, SyncEngineStats } from "@tursodatabase/sync-common"; +import { ProtocolIo, run, SyncOpts, RunOpts, DatabaseRowMutation, DatabaseRowStatement, DatabaseRowTransformResult, SyncEngineStats, SyncEngineGuards } from "@tursodatabase/sync-common"; import { Database as NativeDB, SyncEngine } from "#index"; import { promises } from "node:fs"; @@ -43,23 +43,27 @@ class Database extends DatabasePromise { runOpts: RunOpts; engine: any; io: ProtocolIo; + guards: SyncEngineGuards constructor(db: NativeDatabase, io: ProtocolIo, runOpts: RunOpts, engine: any, opts: DatabaseOpts = {}) { super(db, opts) this.runOpts = runOpts; this.engine = engine; this.io = io; + this.guards = new SyncEngineGuards(); } async sync() { - await run(this.runOpts, this.io, this.engine, this.engine.sync()); + await this.push(); + await this.pull(); } async pull() { - await run(this.runOpts, this.io, this.engine, this.engine.pull()); + const changes = await this.guards.wait(async () => await run(this.runOpts, this.io, this.engine, this.engine.wait())); + await this.guards.apply(async () => await run(this.runOpts, this.io, this.engine, this.engine.apply(changes))); } async push() { - await run(this.runOpts, this.io, this.engine, this.engine.push()); + await this.guards.push(async () => await run(this.runOpts, this.io, this.engine, this.engine.push())); } async checkpoint() { - await run(this.runOpts, this.io, this.engine, this.engine.checkpoint()); + await this.guards.checkpoint(async () => await run(this.runOpts, this.io, this.engine, this.engine.checkpoint())); } async stats(): Promise { return (await run(this.runOpts, this.io, this.engine, this.engine.stats())); @@ -83,7 +87,8 @@ async function connect(opts: SyncOpts): Promise { tablesIgnore: opts.tablesIgnore, useTransform: opts.transform != null, tracing: opts.tracing, - protocolVersion: 1 + protocolVersion: 1, + longPollTimeoutMs: opts.longPollTimeoutMs, }); const runOpts: RunOpts = { url: opts.url, diff --git a/bindings/javascript/sync/src/generator.rs b/bindings/javascript/sync/src/generator.rs index 2aae4f373..00ae9661e 100644 --- a/bindings/javascript/sync/src/generator.rs +++ b/bindings/javascript/sync/src/generator.rs @@ -5,7 +5,7 @@ use std::{ sync::{Arc, Mutex}, }; -use turso_sync_engine::types::ProtocolCommand; +use turso_sync_engine::types::{DbChangesStatus, ProtocolCommand}; pub const GENERATOR_RESUME_IO: u32 = 0; pub const GENERATOR_RESUME_DONE: u32 = 1; @@ -35,7 +35,12 @@ impl>> Generator } } -#[napi(discriminant = "type")] +#[napi] +pub struct SyncEngineChanges { + pub(crate) status: Box>, +} + +#[napi(discriminant = "type", object_from_js = false)] pub enum GeneratorResponse { IO, Done, @@ -47,6 +52,9 @@ pub enum GeneratorResponse { last_push_unix_time: Option, revision: Option, }, + SyncEngineChanges { + changes: SyncEngineChanges, + }, } #[napi] diff --git a/bindings/javascript/sync/src/lib.rs b/bindings/javascript/sync/src/lib.rs index e92603508..f851af991 100644 --- a/bindings/javascript/sync/src/lib.rs +++ b/bindings/javascript/sync/src/lib.rs @@ -6,7 +6,7 @@ pub mod js_protocol_io; use std::{ collections::HashMap, - sync::{Arc, Mutex, OnceLock, RwLock, RwLockReadGuard, RwLockWriteGuard}, + sync::{Arc, Mutex, OnceLock, RwLock, RwLockReadGuard}, }; use napi::bindgen_prelude::{AsyncTask, Either5, Null}; @@ -19,7 +19,7 @@ use turso_sync_engine::{ }; use crate::{ - generator::{GeneratorHolder, GeneratorResponse}, + generator::{GeneratorHolder, GeneratorResponse, SyncEngineChanges}, js_protocol_io::{JsProtocolIo, JsProtocolRequestBytes}, }; @@ -33,6 +33,7 @@ pub struct SyncEngine { path: String, client_name: String, wal_pull_batch_size: u32, + long_poll_timeout: Option, protocol_version: DatabaseSyncEngineProtocolVersion, tables_ignore: Vec, use_transform: bool, @@ -123,6 +124,7 @@ pub struct SyncEngineOpts { pub path: String, pub client_name: Option, pub wal_pull_batch_size: Option, + pub long_poll_timeout_ms: Option, pub tracing: Option, pub tables_ignore: Option>, pub use_transform: bool, @@ -147,6 +149,8 @@ impl SyncEngine { pub fn new(opts: SyncEngineOpts) -> napi::Result { // helpful for local debugging match opts.tracing.as_deref() { + Some("error") => init_tracing(LevelFilter::ERROR), + Some("warn") => init_tracing(LevelFilter::WARN), Some("info") => init_tracing(LevelFilter::INFO), Some("debug") => init_tracing(LevelFilter::DEBUG), Some("trace") => init_tracing(LevelFilter::TRACE), @@ -167,13 +171,16 @@ impl SyncEngine { } #[cfg(feature = "browser")] { - Arc::new(turso_node::browser::Opfs::new()?) + turso_node::browser::opfs() } }; Ok(SyncEngine { path: opts.path, client_name: opts.client_name.unwrap_or("turso-sync-js".to_string()), wal_pull_batch_size: opts.wal_pull_batch_size.unwrap_or(100), + long_poll_timeout: opts + .long_poll_timeout_ms + .map(|x| std::time::Duration::from_millis(x as u64)), tables_ignore: opts.tables_ignore.unwrap_or_default(), use_transform: opts.use_transform, #[allow(clippy::arc_with_non_send_sync)] @@ -196,6 +203,7 @@ impl SyncEngine { let opts = DatabaseSyncEngineOpts { client_name: self.client_name.clone(), wal_pull_batch_size: self.wal_pull_batch_size as u64, + long_poll_timeout: self.long_poll_timeout, tables_ignore: self.tables_ignore.clone(), use_transform: self.use_transform, protocol_version_hint: self.protocol_version, @@ -244,20 +252,10 @@ impl SyncEngine { Ok(self.protocol()?.take_request()) } - #[napi] - pub fn sync(&self) -> GeneratorHolder { - self.run(async move |coro, sync_engine| { - let mut sync_engine = try_write(sync_engine)?; - let sync_engine = try_unwrap_mut(&mut sync_engine)?; - sync_engine.sync(coro).await?; - Ok(None) - }) - } - #[napi] pub fn push(&self) -> GeneratorHolder { - self.run(async move |coro, sync_engine| { - let sync_engine = try_read(sync_engine)?; + self.run(async move |coro, guard| { + let sync_engine = try_read(guard)?; let sync_engine = try_unwrap(&sync_engine)?; sync_engine.push_changes_to_remote(coro).await?; Ok(None) @@ -266,8 +264,8 @@ impl SyncEngine { #[napi] pub fn stats(&self) -> GeneratorHolder { - self.run(async move |coro, sync_engine| { - let sync_engine = try_read(sync_engine)?; + self.run(async move |coro, guard| { + let sync_engine = try_read(guard)?; let sync_engine = try_unwrap(&sync_engine)?; let stats = sync_engine.stats(coro).await?; Ok(Some(GeneratorResponse::SyncEngineStats { @@ -282,20 +280,34 @@ impl SyncEngine { } #[napi] - pub fn pull(&self) -> GeneratorHolder { - self.run(async move |coro, sync_engine| { - let mut sync_engine = try_write(sync_engine)?; - let sync_engine = try_unwrap_mut(&mut sync_engine)?; - sync_engine.pull_changes_from_remote(coro).await?; + pub fn wait(&self) -> GeneratorHolder { + self.run(async move |coro, guard| { + let sync_engine = try_read(guard)?; + let sync_engine = try_unwrap(&sync_engine)?; + Ok(Some(GeneratorResponse::SyncEngineChanges { + changes: SyncEngineChanges { + status: Box::new(Some(sync_engine.wait_changes_from_remote(coro).await?)), + }, + })) + }) + } + + #[napi] + pub fn apply(&self, changes: &mut SyncEngineChanges) -> GeneratorHolder { + let status = changes.status.take().unwrap(); + self.run(async move |coro, guard| { + let sync_engine = try_read(guard)?; + let sync_engine = try_unwrap(&sync_engine)?; + sync_engine.apply_changes_from_remote(coro, status).await?; Ok(None) }) } #[napi] pub fn checkpoint(&self) -> GeneratorHolder { - self.run(async move |coro, sync_engine| { - let mut sync_engine = try_write(sync_engine)?; - let sync_engine = try_unwrap_mut(&mut sync_engine)?; + self.run(async move |coro, guard| { + let sync_engine = try_read(guard)?; + let sync_engine = try_unwrap(&sync_engine)?; sync_engine.checkpoint(coro).await?; Ok(None) }) @@ -378,18 +390,6 @@ fn try_read( Ok(sync_engine) } -fn try_write( - sync_engine: &RwLock>>, -) -> turso_sync_engine::Result>>> { - let Ok(sync_engine) = sync_engine.try_write() else { - let nasty_error = "sync_engine is busy".to_string(); - return Err(turso_sync_engine::errors::Error::DatabaseSyncEngineError( - nasty_error, - )); - }; - Ok(sync_engine) -} - fn try_unwrap<'a>( sync_engine: &'a RwLockReadGuard<'_, Option>>, ) -> turso_sync_engine::Result<&'a DatabaseSyncEngine> { @@ -401,15 +401,3 @@ fn try_unwrap<'a>( }; Ok(sync_engine) } - -fn try_unwrap_mut<'a>( - sync_engine: &'a mut RwLockWriteGuard<'_, Option>>, -) -> turso_sync_engine::Result<&'a mut DatabaseSyncEngine> { - let Some(sync_engine) = sync_engine.as_mut() else { - let error = "sync_engine must be initialized".to_string(); - return Err(turso_sync_engine::errors::Error::DatabaseSyncEngineError( - error, - )); - }; - Ok(sync_engine) -} diff --git a/bindings/javascript/yarn.lock b/bindings/javascript/yarn.lock index 5dc592472..f79e485bd 100644 --- a/bindings/javascript/yarn.lock +++ b/bindings/javascript/yarn.lock @@ -30,6 +30,13 @@ __metadata: languageName: node linkType: hard +"@drizzle-team/brocli@npm:^0.10.2": + version: 0.10.2 + resolution: "@drizzle-team/brocli@npm:0.10.2" + checksum: 10c0/3d8b99d680f0b14fea32b45c59b938b6665e0840cc67f04801b1aa3c6747da3c7d01c00e321645034fa100abdba7e0c20ce07cf46fc2ca769ee4cafd97562484 + languageName: node + linkType: hard + "@emnapi/core@npm:^1.4.5": version: 1.4.5 resolution: "@emnapi/core@npm:1.4.5" @@ -58,6 +65,26 @@ __metadata: languageName: node linkType: hard +"@esbuild-kit/core-utils@npm:^3.3.2": + version: 3.3.2 + resolution: "@esbuild-kit/core-utils@npm:3.3.2" + dependencies: + esbuild: "npm:~0.18.20" + source-map-support: "npm:^0.5.21" + checksum: 10c0/d856f5bd720814593f911d781ed7558a3f8ec1a39802f3831d0eea0d1306e0e2dc11b7b2443af621c413ec6557f1f3034a9a4f1472a4cb40e52cd6e3b356aa05 + languageName: node + linkType: hard + +"@esbuild-kit/esm-loader@npm:^2.5.5": + version: 2.6.5 + resolution: "@esbuild-kit/esm-loader@npm:2.6.5" + dependencies: + "@esbuild-kit/core-utils": "npm:^3.3.2" + get-tsconfig: "npm:^4.7.0" + checksum: 10c0/6894b29176eda62bdce0d458d57f32daed5cb8fcff14cb3ddfbc995cfe3e2fa8599f3b0b1af66db446903b30167f57069f27e9cf79a69cf9b41f557115811cde + languageName: node + linkType: hard + "@esbuild/aix-ppc64@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/aix-ppc64@npm:0.25.9" @@ -65,6 +92,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/android-arm64@npm:0.18.20" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/android-arm64@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/android-arm64@npm:0.25.9" @@ -72,6 +106,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-arm@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/android-arm@npm:0.18.20" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + "@esbuild/android-arm@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/android-arm@npm:0.25.9" @@ -79,6 +120,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/android-x64@npm:0.18.20" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + "@esbuild/android-x64@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/android-x64@npm:0.25.9" @@ -86,6 +134,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/darwin-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/darwin-arm64@npm:0.18.20" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/darwin-arm64@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/darwin-arm64@npm:0.25.9" @@ -93,6 +148,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/darwin-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/darwin-x64@npm:0.18.20" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@esbuild/darwin-x64@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/darwin-x64@npm:0.25.9" @@ -100,6 +162,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/freebsd-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/freebsd-arm64@npm:0.18.20" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/freebsd-arm64@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/freebsd-arm64@npm:0.25.9" @@ -107,6 +176,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/freebsd-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/freebsd-x64@npm:0.18.20" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/freebsd-x64@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/freebsd-x64@npm:0.25.9" @@ -114,6 +190,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-arm64@npm:0.18.20" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/linux-arm64@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/linux-arm64@npm:0.25.9" @@ -121,6 +204,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-arm@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-arm@npm:0.18.20" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + "@esbuild/linux-arm@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/linux-arm@npm:0.25.9" @@ -128,6 +218,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-ia32@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-ia32@npm:0.18.20" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + "@esbuild/linux-ia32@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/linux-ia32@npm:0.25.9" @@ -135,6 +232,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-loong64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-loong64@npm:0.18.20" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + "@esbuild/linux-loong64@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/linux-loong64@npm:0.25.9" @@ -142,6 +246,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-mips64el@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-mips64el@npm:0.18.20" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + "@esbuild/linux-mips64el@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/linux-mips64el@npm:0.25.9" @@ -149,6 +260,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-ppc64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-ppc64@npm:0.18.20" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + "@esbuild/linux-ppc64@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/linux-ppc64@npm:0.25.9" @@ -156,6 +274,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-riscv64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-riscv64@npm:0.18.20" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + "@esbuild/linux-riscv64@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/linux-riscv64@npm:0.25.9" @@ -163,6 +288,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-s390x@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-s390x@npm:0.18.20" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + "@esbuild/linux-s390x@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/linux-s390x@npm:0.25.9" @@ -170,6 +302,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-x64@npm:0.18.20" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + "@esbuild/linux-x64@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/linux-x64@npm:0.25.9" @@ -184,6 +323,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/netbsd-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/netbsd-x64@npm:0.18.20" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/netbsd-x64@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/netbsd-x64@npm:0.25.9" @@ -198,6 +344,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/openbsd-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/openbsd-x64@npm:0.18.20" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/openbsd-x64@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/openbsd-x64@npm:0.25.9" @@ -212,6 +365,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/sunos-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/sunos-x64@npm:0.18.20" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + "@esbuild/sunos-x64@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/sunos-x64@npm:0.25.9" @@ -219,6 +379,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/win32-arm64@npm:0.18.20" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/win32-arm64@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/win32-arm64@npm:0.25.9" @@ -226,6 +393,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-ia32@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/win32-ia32@npm:0.18.20" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + "@esbuild/win32-ia32@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/win32-ia32@npm:0.25.9" @@ -233,6 +407,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/win32-x64@npm:0.18.20" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@esbuild/win32-x64@npm:0.25.9": version: 0.25.9 resolution: "@esbuild/win32-x64@npm:0.25.9" @@ -1433,6 +1614,9 @@ __metadata: "@napi-rs/cli": "npm:^3.1.5" "@tursodatabase/database-common": "npm:^0.2.0-pre.3" "@types/node": "npm:^24.3.1" + better-sqlite3: "npm:^12.2.0" + drizzle-kit: "npm:^0.31.4" + drizzle-orm: "npm:^0.44.5" typescript: "npm:^5.9.2" vitest: "npm:^3.2.4" languageName: unknown @@ -1458,6 +1642,7 @@ __metadata: version: 0.0.0-use.local resolution: "@tursodatabase/sync-common@workspace:sync/packages/common" dependencies: + "@tursodatabase/database-common": "npm:^0.2.0-pre.3" typescript: "npm:^5.9.2" languageName: unknown linkType: soft @@ -1680,16 +1865,7 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^4.0.0": - version: 4.3.0 - resolution: "ansi-styles@npm:4.3.0" - dependencies: - color-convert: "npm:^2.0.1" - checksum: 10c0/895a23929da416f2bd3de7e9cb4eabd340949328ab85ddd6e484a637d8f6820d485f53933446f5291c3b760cbc488beb8e88573dd0f9c7daf83dccc8fe81b041 - languageName: node - linkType: hard - -"ansi-styles@npm:^5.0.0": +"ansi-styles@npm:^4.0.0, ansi-styles@npm:^5.0.0": version: 5.2.0 resolution: "ansi-styles@npm:5.2.0" checksum: 10c0/9c4ca80eb3c2fb7b33841c210d2f20807f40865d27008d7c3f707b7f95cab7d67462a565e2388ac3285b71cb3d9bb2173de8da37c57692a362885ec34d6e27df @@ -1733,6 +1909,13 @@ __metadata: languageName: node linkType: hard +"base64-js@npm:^1.3.1": + version: 1.5.1 + resolution: "base64-js@npm:1.5.1" + checksum: 10c0/f23823513b63173a001030fae4f2dabe283b99a9d324ade3ad3d148e218134676f1ee8568c877cd79ec1c53158dcf2d2ba527a97c606618928ba99dd930102bf + languageName: node + linkType: hard + "before-after-hook@npm:^4.0.0": version: 4.0.0 resolution: "before-after-hook@npm:4.0.0" @@ -1740,6 +1923,37 @@ __metadata: languageName: node linkType: hard +"better-sqlite3@npm:^12.2.0": + version: 12.2.0 + resolution: "better-sqlite3@npm:12.2.0" + dependencies: + bindings: "npm:^1.5.0" + node-gyp: "npm:latest" + prebuild-install: "npm:^7.1.1" + checksum: 10c0/842247e9bbb775f366ac91f604117112c312497e643bac21648d8b69f479763de0ac049b14b609d6d5ecaee50debcc09a854f682d3dc099a1d933fea92ce68d0 + languageName: node + linkType: hard + +"bindings@npm:^1.5.0": + version: 1.5.0 + resolution: "bindings@npm:1.5.0" + dependencies: + file-uri-to-path: "npm:1.0.0" + checksum: 10c0/3dab2491b4bb24124252a91e656803eac24292473e56554e35bbfe3cc1875332cfa77600c3bac7564049dc95075bf6fcc63a4609920ff2d64d0fe405fcf0d4ba + languageName: node + linkType: hard + +"bl@npm:^4.0.3": + version: 4.1.0 + resolution: "bl@npm:4.1.0" + dependencies: + buffer: "npm:^5.5.0" + inherits: "npm:^2.0.4" + readable-stream: "npm:^3.4.0" + checksum: 10c0/02847e1d2cb089c9dc6958add42e3cdeaf07d13f575973963335ac0fdece563a50ac770ac4c8fa06492d2dd276f6cc3b7f08c7cd9c7a7ad0f8d388b2a28def5f + languageName: node + linkType: hard + "brace-expansion@npm:^2.0.1": version: 2.0.2 resolution: "brace-expansion@npm:2.0.2" @@ -1749,6 +1963,23 @@ __metadata: languageName: node linkType: hard +"buffer-from@npm:^1.0.0": + version: 1.1.2 + resolution: "buffer-from@npm:1.1.2" + checksum: 10c0/124fff9d66d691a86d3b062eff4663fe437a9d9ee4b47b1b9e97f5a5d14f6d5399345db80f796827be7c95e70a8e765dd404b7c3ff3b3324f98e9b0c8826cc34 + languageName: node + linkType: hard + +"buffer@npm:^5.5.0": + version: 5.7.1 + resolution: "buffer@npm:5.7.1" + dependencies: + base64-js: "npm:^1.3.1" + ieee754: "npm:^1.1.13" + checksum: 10c0/27cac81cff434ed2876058d72e7c4789d11ff1120ef32c9de48f59eab58179b66710c488987d295ae89a228f835fc66d088652dffeb8e3ba8659f80eb091d55e + languageName: node + linkType: hard + "cac@npm:^6.7.14": version: 6.7.14 resolution: "cac@npm:6.7.14" @@ -1803,6 +2034,13 @@ __metadata: languageName: node linkType: hard +"chownr@npm:^1.1.1": + version: 1.1.4 + resolution: "chownr@npm:1.1.4" + checksum: 10c0/ed57952a84cc0c802af900cf7136de643d3aba2eecb59d29344bc2f3f9bf703a301b9d84cdc71f82c3ffc9ccde831b0d92f5b45f91727d6c9da62f23aef9d9db + languageName: node + linkType: hard + "chownr@npm:^3.0.0": version: 3.0.0 resolution: "chownr@npm:3.0.0" @@ -1828,22 +2066,6 @@ __metadata: languageName: node linkType: hard -"color-convert@npm:^2.0.1": - version: 2.0.1 - resolution: "color-convert@npm:2.0.1" - dependencies: - color-name: "npm:~1.1.4" - checksum: 10c0/37e1150172f2e311fe1b2df62c6293a342ee7380da7b9cfdba67ea539909afbd74da27033208d01d6d5cfc65ee7868a22e18d7e7648e004425441c0f8a15a7d7 - languageName: node - linkType: hard - -"color-name@npm:~1.1.4": - version: 1.1.4 - resolution: "color-name@npm:1.1.4" - checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95 - languageName: node - linkType: hard - "colorette@npm:^2.0.20": version: 2.0.20 resolution: "colorette@npm:2.0.20" @@ -1862,7 +2084,19 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.3.4, debug@npm:^4.4.0, debug@npm:^4.4.1": +"debug@npm:4": + version: 4.4.3 + resolution: "debug@npm:4.4.3" + dependencies: + ms: "npm:^2.1.3" + peerDependenciesMeta: + supports-color: + optional: true + checksum: 10c0/d79136ec6c83ecbefd0f6a5593da6a9c91ec4d7ddc4b54c883d6e71ec9accb5f67a1a5e96d00a328196b5b5c86d365e98d8a3a70856aaf16b4e7b1985e67f5a6 + languageName: node + linkType: hard + +"debug@npm:^4.3.4, debug@npm:^4.4.0, debug@npm:^4.4.1": version: 4.4.1 resolution: "debug@npm:4.4.1" dependencies: @@ -1874,6 +2108,15 @@ __metadata: languageName: node linkType: hard +"decompress-response@npm:^6.0.0": + version: 6.0.0 + resolution: "decompress-response@npm:6.0.0" + dependencies: + mimic-response: "npm:^3.1.0" + checksum: 10c0/bd89d23141b96d80577e70c54fb226b2f40e74a6817652b80a116d7befb8758261ad073a8895648a29cc0a5947021ab66705cb542fa9c143c82022b27c5b175e + languageName: node + linkType: hard + "deep-eql@npm:^5.0.1": version: 5.0.2 resolution: "deep-eql@npm:5.0.2" @@ -1881,6 +2124,13 @@ __metadata: languageName: node linkType: hard +"deep-extend@npm:^0.6.0": + version: 0.6.0 + resolution: "deep-extend@npm:0.6.0" + checksum: 10c0/1c6b0abcdb901e13a44c7d699116d3d4279fdb261983122a3783e7273844d5f2537dc2e1c454a23fcf645917f93fbf8d07101c1d03c015a87faa662755212566 + languageName: node + linkType: hard + "dequal@npm:^2.0.3": version: 2.0.3 resolution: "dequal@npm:2.0.3" @@ -1888,6 +2138,13 @@ __metadata: languageName: node linkType: hard +"detect-libc@npm:^2.0.0": + version: 2.1.0 + resolution: "detect-libc@npm:2.1.0" + checksum: 10c0/4d0d36c77fdcb1d3221779d8dfc7d5808dd52530d49db67193fb3cd8149e2d499a1eeb87bb830ad7c442294929992c12e971f88ae492965549f8f83e5336eba6 + languageName: node + linkType: hard + "dom-accessibility-api@npm:^0.5.9": version: 0.5.16 resolution: "dom-accessibility-api@npm:0.5.16" @@ -1895,6 +2152,115 @@ __metadata: languageName: node linkType: hard +"drizzle-kit@npm:^0.31.4": + version: 0.31.4 + resolution: "drizzle-kit@npm:0.31.4" + dependencies: + "@drizzle-team/brocli": "npm:^0.10.2" + "@esbuild-kit/esm-loader": "npm:^2.5.5" + esbuild: "npm:^0.25.4" + esbuild-register: "npm:^3.5.0" + bin: + drizzle-kit: bin.cjs + checksum: 10c0/5e345cb28b4b8f329ce5f851e47418ac2ee8189aecec85f566f7a6c309f3392613519a39c559618599bd1e63fb99f114b9d9d82fb9e411f1702425678f34d2c2 + languageName: node + linkType: hard + +"drizzle-orm@npm:^0.44.5": + version: 0.44.5 + resolution: "drizzle-orm@npm:0.44.5" + peerDependencies: + "@aws-sdk/client-rds-data": ">=3" + "@cloudflare/workers-types": ">=4" + "@electric-sql/pglite": ">=0.2.0" + "@libsql/client": ">=0.10.0" + "@libsql/client-wasm": ">=0.10.0" + "@neondatabase/serverless": ">=0.10.0" + "@op-engineering/op-sqlite": ">=2" + "@opentelemetry/api": ^1.4.1 + "@planetscale/database": ">=1.13" + "@prisma/client": "*" + "@tidbcloud/serverless": "*" + "@types/better-sqlite3": "*" + "@types/pg": "*" + "@types/sql.js": "*" + "@upstash/redis": ">=1.34.7" + "@vercel/postgres": ">=0.8.0" + "@xata.io/client": "*" + better-sqlite3: ">=7" + bun-types: "*" + expo-sqlite: ">=14.0.0" + gel: ">=2" + knex: "*" + kysely: "*" + mysql2: ">=2" + pg: ">=8" + postgres: ">=3" + sql.js: ">=1" + sqlite3: ">=5" + peerDependenciesMeta: + "@aws-sdk/client-rds-data": + optional: true + "@cloudflare/workers-types": + optional: true + "@electric-sql/pglite": + optional: true + "@libsql/client": + optional: true + "@libsql/client-wasm": + optional: true + "@neondatabase/serverless": + optional: true + "@op-engineering/op-sqlite": + optional: true + "@opentelemetry/api": + optional: true + "@planetscale/database": + optional: true + "@prisma/client": + optional: true + "@tidbcloud/serverless": + optional: true + "@types/better-sqlite3": + optional: true + "@types/pg": + optional: true + "@types/sql.js": + optional: true + "@upstash/redis": + optional: true + "@vercel/postgres": + optional: true + "@xata.io/client": + optional: true + better-sqlite3: + optional: true + bun-types: + optional: true + expo-sqlite: + optional: true + gel: + optional: true + knex: + optional: true + kysely: + optional: true + mysql2: + optional: true + pg: + optional: true + postgres: + optional: true + prisma: + optional: true + sql.js: + optional: true + sqlite3: + optional: true + checksum: 10c0/2f9bd8cc7395b3254574eb9e9c344b7cebd507ac61f1ee8783648ad3bb8a7983875f44c0eabedfd871496d7eae646dbc75111fa21de2c64d0c899fcea091e303 + languageName: node + linkType: hard + "eastasianwidth@npm:^0.2.0": version: 0.2.0 resolution: "eastasianwidth@npm:0.2.0" @@ -1937,6 +2303,15 @@ __metadata: languageName: node linkType: hard +"end-of-stream@npm:^1.1.0, end-of-stream@npm:^1.4.1": + version: 1.4.5 + resolution: "end-of-stream@npm:1.4.5" + dependencies: + once: "npm:^1.4.0" + checksum: 10c0/b0701c92a10b89afb1cb45bf54a5292c6f008d744eb4382fa559d54775ff31617d1d7bc3ef617575f552e24fad2c7c1a1835948c66b3f3a4be0a6c1f35c883d8 + languageName: node + linkType: hard + "env-paths@npm:^2.2.0": version: 2.2.1 resolution: "env-paths@npm:2.2.1" @@ -1970,7 +2345,18 @@ __metadata: languageName: node linkType: hard -"esbuild@npm:^0.25.0": +"esbuild-register@npm:^3.5.0": + version: 3.6.0 + resolution: "esbuild-register@npm:3.6.0" + dependencies: + debug: "npm:^4.3.4" + peerDependencies: + esbuild: ">=0.12 <1" + checksum: 10c0/77193b7ca32ba9f81b35ddf3d3d0138efb0b1429d71b39480cfee932e1189dd2e492bd32bf04a4d0bc3adfbc7ec7381ceb5ffd06efe35f3e70904f1f686566d5 + languageName: node + linkType: hard + +"esbuild@npm:^0.25.0, esbuild@npm:^0.25.4": version: 0.25.9 resolution: "esbuild@npm:0.25.9" dependencies: @@ -2059,6 +2445,83 @@ __metadata: languageName: node linkType: hard +"esbuild@npm:~0.18.20": + version: 0.18.20 + resolution: "esbuild@npm:0.18.20" + dependencies: + "@esbuild/android-arm": "npm:0.18.20" + "@esbuild/android-arm64": "npm:0.18.20" + "@esbuild/android-x64": "npm:0.18.20" + "@esbuild/darwin-arm64": "npm:0.18.20" + "@esbuild/darwin-x64": "npm:0.18.20" + "@esbuild/freebsd-arm64": "npm:0.18.20" + "@esbuild/freebsd-x64": "npm:0.18.20" + "@esbuild/linux-arm": "npm:0.18.20" + "@esbuild/linux-arm64": "npm:0.18.20" + "@esbuild/linux-ia32": "npm:0.18.20" + "@esbuild/linux-loong64": "npm:0.18.20" + "@esbuild/linux-mips64el": "npm:0.18.20" + "@esbuild/linux-ppc64": "npm:0.18.20" + "@esbuild/linux-riscv64": "npm:0.18.20" + "@esbuild/linux-s390x": "npm:0.18.20" + "@esbuild/linux-x64": "npm:0.18.20" + "@esbuild/netbsd-x64": "npm:0.18.20" + "@esbuild/openbsd-x64": "npm:0.18.20" + "@esbuild/sunos-x64": "npm:0.18.20" + "@esbuild/win32-arm64": "npm:0.18.20" + "@esbuild/win32-ia32": "npm:0.18.20" + "@esbuild/win32-x64": "npm:0.18.20" + dependenciesMeta: + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 10c0/473b1d92842f50a303cf948a11ebd5f69581cd254d599dd9d62f9989858e0533f64e83b723b5e1398a5b488c0f5fd088795b4235f65ecaf4f007d4b79f04bc88 + languageName: node + linkType: hard + "estree-walker@npm:^3.0.3": version: 3.0.3 resolution: "estree-walker@npm:3.0.3" @@ -2068,6 +2531,13 @@ __metadata: languageName: node linkType: hard +"expand-template@npm:^2.0.3": + version: 2.0.3 + resolution: "expand-template@npm:2.0.3" + checksum: 10c0/1c9e7afe9acadf9d373301d27f6a47b34e89b3391b1ef38b7471d381812537ef2457e620ae7f819d2642ce9c43b189b3583813ec395e2938319abe356a9b2f51 + languageName: node + linkType: hard + "expect-type@npm:^1.2.1": version: 1.2.2 resolution: "expect-type@npm:1.2.2" @@ -2112,6 +2582,13 @@ __metadata: languageName: node linkType: hard +"file-uri-to-path@npm:1.0.0": + version: 1.0.0 + resolution: "file-uri-to-path@npm:1.0.0" + checksum: 10c0/3b545e3a341d322d368e880e1c204ef55f1d45cdea65f7efc6c6ce9e0c4d22d802d5629320eb779d006fe59624ac17b0e848d83cc5af7cd101f206cb704f5519 + languageName: node + linkType: hard + "find-up@npm:^7.0.0": version: 7.0.0 resolution: "find-up@npm:7.0.0" @@ -2133,6 +2610,13 @@ __metadata: languageName: node linkType: hard +"fs-constants@npm:^1.0.0": + version: 1.0.0 + resolution: "fs-constants@npm:1.0.0" + checksum: 10c0/a0cde99085f0872f4d244e83e03a46aa387b74f5a5af750896c6b05e9077fac00e9932fdf5aef84f2f16634cd473c63037d7a512576da7d5c2b9163d1909f3a8 + languageName: node + linkType: hard + "fs-minipass@npm:^3.0.0": version: 3.0.3 resolution: "fs-minipass@npm:3.0.3" @@ -2180,6 +2664,22 @@ __metadata: languageName: node linkType: hard +"get-tsconfig@npm:^4.7.0": + version: 4.10.1 + resolution: "get-tsconfig@npm:4.10.1" + dependencies: + resolve-pkg-maps: "npm:^1.0.0" + checksum: 10c0/7f8e3dabc6a49b747920a800fb88e1952fef871cdf51b79e98db48275a5de6cdaf499c55ee67df5fa6fe7ce65f0063e26de0f2e53049b408c585aa74d39ffa21 + languageName: node + linkType: hard + +"github-from-package@npm:0.0.0": + version: 0.0.0 + resolution: "github-from-package@npm:0.0.0" + checksum: 10c0/737ee3f52d0a27e26332cde85b533c21fcdc0b09fb716c3f8e522cfaa9c600d4a631dec9fcde179ec9d47cca89017b7848ed4d6ae6b6b78f936c06825b1fcc12 + languageName: node + linkType: hard + "glob@npm:^10.2.2": version: 10.4.5 resolution: "glob@npm:10.4.5" @@ -2248,6 +2748,13 @@ __metadata: languageName: node linkType: hard +"ieee754@npm:^1.1.13": + version: 1.2.1 + resolution: "ieee754@npm:1.2.1" + checksum: 10c0/b0782ef5e0935b9f12883a2e2aa37baa75da6e66ce6515c168697b42160807d9330de9a32ec1ed73149aea02e0d822e572bca6f1e22bdcbd2149e13b050b17bb + languageName: node + linkType: hard + "imurmurhash@npm:^0.1.4": version: 0.1.4 resolution: "imurmurhash@npm:0.1.4" @@ -2255,6 +2762,20 @@ __metadata: languageName: node linkType: hard +"inherits@npm:^2.0.3, inherits@npm:^2.0.4": + version: 2.0.4 + resolution: "inherits@npm:2.0.4" + checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 + languageName: node + linkType: hard + +"ini@npm:~1.3.0": + version: 1.3.8 + resolution: "ini@npm:1.3.8" + checksum: 10c0/ec93838d2328b619532e4f1ff05df7909760b6f66d9c9e2ded11e5c1897d6f2f9980c54dd638f88654b00919ce31e827040631eab0a3969e4d1abefa0719516a + languageName: node + linkType: hard + "ip-address@npm:^10.0.1": version: 10.0.1 resolution: "ip-address@npm:10.0.1" @@ -2381,6 +2902,13 @@ __metadata: languageName: node linkType: hard +"mimic-response@npm:^3.1.0": + version: 3.1.0 + resolution: "mimic-response@npm:3.1.0" + checksum: 10c0/0d6f07ce6e03e9e4445bee655202153bdb8a98d67ee8dc965ac140900d7a2688343e6b4c9a72cfc9ef2f7944dfd76eef4ab2482eb7b293a68b84916bac735362 + languageName: node + linkType: hard + "minimatch@npm:^9.0.4": version: 9.0.5 resolution: "minimatch@npm:9.0.5" @@ -2390,6 +2918,13 @@ __metadata: languageName: node linkType: hard +"minimist@npm:^1.2.0, minimist@npm:^1.2.3": + version: 1.2.8 + resolution: "minimist@npm:1.2.8" + checksum: 10c0/19d3fcdca050087b84c2029841a093691a91259a47def2f18222f41e7645a0b7c44ef4b40e88a1e58a40c84d2ef0ee6047c55594d298146d0eb3f6b737c20ce6 + languageName: node + linkType: hard + "minipass-collect@npm:^2.0.1": version: 2.0.1 resolution: "minipass-collect@npm:2.0.1" @@ -2466,6 +3001,13 @@ __metadata: languageName: node linkType: hard +"mkdirp-classic@npm:^0.5.2, mkdirp-classic@npm:^0.5.3": + version: 0.5.3 + resolution: "mkdirp-classic@npm:0.5.3" + checksum: 10c0/95371d831d196960ddc3833cc6907e6b8f67ac5501a6582f47dfae5eb0f092e9f8ce88e0d83afcae95d6e2b61a01741ba03714eeafb6f7a6e9dcc158ac85b168 + languageName: node + linkType: hard + "mkdirp@npm:^3.0.1": version: 3.0.1 resolution: "mkdirp@npm:3.0.1" @@ -2505,6 +3047,13 @@ __metadata: languageName: node linkType: hard +"napi-build-utils@npm:^2.0.0": + version: 2.0.0 + resolution: "napi-build-utils@npm:2.0.0" + checksum: 10c0/5833aaeb5cc5c173da47a102efa4680a95842c13e0d9cc70428bd3ee8d96bb2172f8860d2811799b5daa5cbeda779933601492a2028a6a5351c6d0fcf6de83db + languageName: node + linkType: hard + "negotiator@npm:^1.0.0": version: 1.0.0 resolution: "negotiator@npm:1.0.0" @@ -2512,6 +3061,15 @@ __metadata: languageName: node linkType: hard +"node-abi@npm:^3.3.0": + version: 3.77.0 + resolution: "node-abi@npm:3.77.0" + dependencies: + semver: "npm:^7.3.5" + checksum: 10c0/3354289ccca052538f653968ead73d00785e5ab159ce3a575dbff465724dac749821e7c327ae6c4774f29994f94c402fbafc8799b172aabf4aa8a082a070b00a + languageName: node + linkType: hard + "node-gyp@npm:latest": version: 11.4.2 resolution: "node-gyp@npm:11.4.2" @@ -2543,6 +3101,15 @@ __metadata: languageName: node linkType: hard +"once@npm:^1.3.1, once@npm:^1.4.0": + version: 1.4.0 + resolution: "once@npm:1.4.0" + dependencies: + wrappy: "npm:1" + checksum: 10c0/5d48aca287dfefabd756621c5dfce5c91a549a93e9fdb7b8246bc4c4790aa2ec17b34a260530474635147aeb631a2dcc8b32c613df0675f96041cbb8244517d0 + languageName: node + linkType: hard + "os-tmpdir@npm:~1.0.2": version: 1.0.2 resolution: "os-tmpdir@npm:1.0.2" @@ -2669,6 +3236,28 @@ __metadata: languageName: node linkType: hard +"prebuild-install@npm:^7.1.1": + version: 7.1.3 + resolution: "prebuild-install@npm:7.1.3" + dependencies: + detect-libc: "npm:^2.0.0" + expand-template: "npm:^2.0.3" + github-from-package: "npm:0.0.0" + minimist: "npm:^1.2.3" + mkdirp-classic: "npm:^0.5.3" + napi-build-utils: "npm:^2.0.0" + node-abi: "npm:^3.3.0" + pump: "npm:^3.0.0" + rc: "npm:^1.2.7" + simple-get: "npm:^4.0.0" + tar-fs: "npm:^2.0.0" + tunnel-agent: "npm:^0.6.0" + bin: + prebuild-install: bin.js + checksum: 10c0/25919a42b52734606a4036ab492d37cfe8b601273d8dfb1fa3c84e141a0a475e7bad3ab848c741d2f810cef892fcf6059b8c7fe5b29f98d30e0c29ad009bedff + languageName: node + linkType: hard + "pretty-format@npm:^27.0.2": version: 27.5.1 resolution: "pretty-format@npm:27.5.1" @@ -2697,6 +3286,30 @@ __metadata: languageName: node linkType: hard +"pump@npm:^3.0.0": + version: 3.0.3 + resolution: "pump@npm:3.0.3" + dependencies: + end-of-stream: "npm:^1.1.0" + once: "npm:^1.3.1" + checksum: 10c0/ada5cdf1d813065bbc99aa2c393b8f6beee73b5de2890a8754c9f488d7323ffd2ca5f5a0943b48934e3fcbd97637d0337369c3c631aeb9614915db629f1c75c9 + languageName: node + linkType: hard + +"rc@npm:^1.2.7": + version: 1.2.8 + resolution: "rc@npm:1.2.8" + dependencies: + deep-extend: "npm:^0.6.0" + ini: "npm:~1.3.0" + minimist: "npm:^1.2.0" + strip-json-comments: "npm:~2.0.1" + bin: + rc: ./cli.js + checksum: 10c0/24a07653150f0d9ac7168e52943cc3cb4b7a22c0e43c7dff3219977c2fdca5a2760a304a029c20811a0e79d351f57d46c9bde216193a0f73978496afc2b85b15 + languageName: node + linkType: hard + "react-is@npm:^17.0.1": version: 17.0.2 resolution: "react-is@npm:17.0.2" @@ -2704,6 +3317,24 @@ __metadata: languageName: node linkType: hard +"readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0": + version: 3.6.2 + resolution: "readable-stream@npm:3.6.2" + dependencies: + inherits: "npm:^2.0.3" + string_decoder: "npm:^1.1.1" + util-deprecate: "npm:^1.0.1" + checksum: 10c0/e37be5c79c376fdd088a45fa31ea2e423e5d48854be7a22a58869b4e84d25047b193f6acb54f1012331e1bcd667ffb569c01b99d36b0bd59658fb33f513511b7 + languageName: node + linkType: hard + +"resolve-pkg-maps@npm:^1.0.0": + version: 1.0.0 + resolution: "resolve-pkg-maps@npm:1.0.0" + checksum: 10c0/fb8f7bbe2ca281a73b7ef423a1cbc786fb244bd7a95cbe5c3fba25b27d327150beca8ba02f622baea65919a57e061eb5005204daa5f93ed590d9b77463a567ab + languageName: node + linkType: hard + "retry@npm:^0.12.0": version: 0.12.0 resolution: "retry@npm:0.12.0" @@ -2795,6 +3426,13 @@ __metadata: languageName: unknown linkType: soft +"safe-buffer@npm:^5.0.1, safe-buffer@npm:~5.2.0": + version: 5.2.1 + resolution: "safe-buffer@npm:5.2.1" + checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 + languageName: node + linkType: hard + "safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0": version: 2.1.2 resolution: "safer-buffer@npm:2.1.2" @@ -2841,6 +3479,24 @@ __metadata: languageName: node linkType: hard +"simple-concat@npm:^1.0.0": + version: 1.0.1 + resolution: "simple-concat@npm:1.0.1" + checksum: 10c0/62f7508e674414008910b5397c1811941d457dfa0db4fd5aa7fa0409eb02c3609608dfcd7508cace75b3a0bf67a2a77990711e32cd213d2c76f4fd12ee86d776 + languageName: node + linkType: hard + +"simple-get@npm:^4.0.0": + version: 4.0.1 + resolution: "simple-get@npm:4.0.1" + dependencies: + decompress-response: "npm:^6.0.0" + once: "npm:^1.3.1" + simple-concat: "npm:^1.0.0" + checksum: 10c0/b0649a581dbca741babb960423248899203165769747142033479a7dc5e77d7b0fced0253c731cd57cf21e31e4d77c9157c3069f4448d558ebc96cf9e1eebcf0 + languageName: node + linkType: hard + "sirv@npm:^3.0.1": version: 3.0.2 resolution: "sirv@npm:3.0.2" @@ -2887,6 +3543,23 @@ __metadata: languageName: node linkType: hard +"source-map-support@npm:^0.5.21": + version: 0.5.21 + resolution: "source-map-support@npm:0.5.21" + dependencies: + buffer-from: "npm:^1.0.0" + source-map: "npm:^0.6.0" + checksum: 10c0/9ee09942f415e0f721d6daad3917ec1516af746a8120bba7bb56278707a37f1eb8642bde456e98454b8a885023af81a16e646869975f06afc1a711fb90484e7d + languageName: node + linkType: hard + +"source-map@npm:^0.6.0": + version: 0.6.1 + resolution: "source-map@npm:0.6.1" + checksum: 10c0/ab55398007c5e5532957cb0beee2368529618ac0ab372d789806f5718123cc4367d57de3904b4e6a4170eb5a0b0f41373066d02ca0735a0c4d75c7d328d3e011 + languageName: node + linkType: hard + "ssri@npm:^12.0.0": version: 12.0.0 resolution: "ssri@npm:12.0.0" @@ -2932,6 +3605,15 @@ __metadata: languageName: node linkType: hard +"string_decoder@npm:^1.1.1": + version: 1.3.0 + resolution: "string_decoder@npm:1.3.0" + dependencies: + safe-buffer: "npm:~5.2.0" + checksum: 10c0/810614ddb030e271cd591935dcd5956b2410dd079d64ff92a1844d6b7588bf992b3e1b69b0f4d34a3e06e0bd73046ac646b5264c1987b20d0601f81ef35d731d + languageName: node + linkType: hard + "strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": version: 6.0.1 resolution: "strip-ansi@npm:6.0.1" @@ -2950,6 +3632,13 @@ __metadata: languageName: node linkType: hard +"strip-json-comments@npm:~2.0.1": + version: 2.0.1 + resolution: "strip-json-comments@npm:2.0.1" + checksum: 10c0/b509231cbdee45064ff4f9fd73609e2bcc4e84a4d508e9dd0f31f70356473fde18abfb5838c17d56fb236f5a06b102ef115438de0600b749e818a35fbbc48c43 + languageName: node + linkType: hard + "strip-literal@npm:^3.0.0": version: 3.0.0 resolution: "strip-literal@npm:3.0.0" @@ -2959,6 +3648,31 @@ __metadata: languageName: node linkType: hard +"tar-fs@npm:^2.0.0": + version: 2.1.4 + resolution: "tar-fs@npm:2.1.4" + dependencies: + chownr: "npm:^1.1.1" + mkdirp-classic: "npm:^0.5.2" + pump: "npm:^3.0.0" + tar-stream: "npm:^2.1.4" + checksum: 10c0/decb25acdc6839182c06ec83cba6136205bda1db984e120c8ffd0d80182bc5baa1d916f9b6c5c663ea3f9975b4dd49e3c6bb7b1707cbcdaba4e76042f43ec84c + languageName: node + linkType: hard + +"tar-stream@npm:^2.1.4": + version: 2.2.0 + resolution: "tar-stream@npm:2.2.0" + dependencies: + bl: "npm:^4.0.3" + end-of-stream: "npm:^1.4.1" + fs-constants: "npm:^1.0.0" + inherits: "npm:^2.0.3" + readable-stream: "npm:^3.1.1" + checksum: 10c0/2f4c910b3ee7196502e1ff015a7ba321ec6ea837667220d7bcb8d0852d51cb04b87f7ae471008a6fb8f5b1a1b5078f62f3a82d30c706f20ada1238ac797e7692 + languageName: node + linkType: hard + "tar@npm:^7.4.3": version: 7.4.3 resolution: "tar@npm:7.4.3" @@ -3041,6 +3755,15 @@ __metadata: languageName: node linkType: hard +"tunnel-agent@npm:^0.6.0": + version: 0.6.0 + resolution: "tunnel-agent@npm:0.6.0" + dependencies: + safe-buffer: "npm:^5.0.1" + checksum: 10c0/4c7a1b813e7beae66fdbf567a65ec6d46313643753d0beefb3c7973d66fcec3a1e7f39759f0a0b4465883499c6dc8b0750ab8b287399af2e583823e40410a17a + languageName: node + linkType: hard + "typanion@npm:^3.14.0, typanion@npm:^3.8.0": version: 3.14.0 resolution: "typanion@npm:3.14.0" @@ -3114,6 +3837,13 @@ __metadata: languageName: node linkType: hard +"util-deprecate@npm:^1.0.1": + version: 1.0.2 + resolution: "util-deprecate@npm:1.0.2" + checksum: 10c0/41a5bdd214df2f6c3ecf8622745e4a366c4adced864bc3c833739791aeeeb1838119af7daed4ba36428114b5c67dcda034a79c882e97e43c03e66a4dd7389942 + languageName: node + linkType: hard + "vite-node@npm:3.2.4": version: 3.2.4 resolution: "vite-node@npm:3.2.4" @@ -3307,6 +4037,13 @@ __metadata: languageName: node linkType: hard +"wrappy@npm:1": + version: 1.0.2 + resolution: "wrappy@npm:1.0.2" + checksum: 10c0/56fece1a4018c6a6c8e28fbc88c87e0fbf4ea8fd64fc6c63b18f4acc4bd13e0ad2515189786dd2c30d3eec9663d70f4ecf699330002f8ccb547e4a18231fc9f0 + languageName: node + linkType: hard + "ws@npm:^8.18.2": version: 8.18.3 resolution: "ws@npm:8.18.3" diff --git a/core/storage/wal.rs b/core/storage/wal.rs index 3edf3f6d5..d6b111172 100644 --- a/core/storage/wal.rs +++ b/core/storage/wal.rs @@ -1639,11 +1639,41 @@ impl WalFile { } fn get_shared_mut(&self) -> parking_lot::RwLockWriteGuard<'_, WalFileShared> { - self.shared.write() + // WASM in browser main thread doesn't have a way to "park" a thread + // so, we spin way here instead of calling blocking lock + #[cfg(target_family = "wasm")] + { + loop { + let Some(lock) = self.shared.try_write() else { + std::hint::spin_loop(); + continue; + }; + return lock; + } + } + #[cfg(not(target_family = "wasm"))] + { + self.shared.write() + } } fn get_shared(&self) -> parking_lot::RwLockReadGuard<'_, WalFileShared> { - self.shared.read() + // WASM in browser main thread doesn't have a way to "park" a thread + // so, we spin way here instead of calling blocking lock + #[cfg(target_family = "wasm")] + { + loop { + let Some(lock) = self.shared.try_read() else { + std::hint::spin_loop(); + continue; + }; + return lock; + } + } + #[cfg(not(target_family = "wasm"))] + { + self.shared.read() + } } fn complete_append_frame(&mut self, page_id: u64, frame_id: u64, checksums: (u32, u32)) { diff --git a/sync/engine/src/database_replay_generator.rs b/sync/engine/src/database_replay_generator.rs index daa3b9f0f..02532d825 100644 --- a/sync/engine/src/database_replay_generator.rs +++ b/sync/engine/src/database_replay_generator.rs @@ -264,13 +264,12 @@ impl DatabaseReplayGenerator { let update = self.update_query(coro, table_name, &columns).await?; Ok(update) } else { - let columns = [true].repeat(after.len()); - let update = self.update_query(coro, table_name, &columns).await?; - Ok(update) + let upsert = self.upsert_query(coro, table_name, after.len()).await?; + Ok(upsert) } } DatabaseTapeRowChangeType::Insert { after } => { - let insert = self.insert_query(coro, table_name, after.len()).await?; + let insert = self.upsert_query(coro, table_name, after.len()).await?; Ok(insert) } } @@ -320,7 +319,7 @@ impl DatabaseReplayGenerator { is_ddl_replay: false, }) } - pub(crate) async fn insert_query( + pub(crate) async fn upsert_query( &self, coro: &Coro, table_name: &str, diff --git a/sync/engine/src/database_sync_engine.rs b/sync/engine/src/database_sync_engine.rs index 7176d7ede..0257ca629 100644 --- a/sync/engine/src/database_sync_engine.rs +++ b/sync/engine/src/database_sync_engine.rs @@ -1,5 +1,4 @@ use std::{ - cell::RefCell, collections::{HashMap, HashSet}, sync::{Arc, Mutex}, }; @@ -37,6 +36,7 @@ pub struct DatabaseSyncEngineOpts { pub tables_ignore: Vec, pub use_transform: bool, pub wal_pull_batch_size: u64, + pub long_poll_timeout: Option, pub protocol_version_hint: DatabaseSyncEngineProtocolVersion, } @@ -51,7 +51,7 @@ pub struct DatabaseSyncEngine { meta_path: String, changes_file: Arc>>>, opts: DatabaseSyncEngineOpts, - meta: RefCell, + meta: Mutex, client_unique_id: String, } @@ -147,7 +147,7 @@ impl DatabaseSyncEngine

{ tracing::info!("initialize database tape connection: path={}", main_db_path); let main_tape = DatabaseTape::new_with_opts(main_db, tape_opts); let changes_file = io.open_file(&changes_path, OpenFlags::Create, false)?; - let mut db = Self { + let db = Self { io, protocol, db_file, @@ -158,7 +158,7 @@ impl DatabaseSyncEngine

{ meta_path: format!("{main_db_path}-info"), changes_file: Arc::new(Mutex::new(Some(changes_file))), opts, - meta: RefCell::new(meta.clone()), + meta: Mutex::new(meta.clone()), client_unique_id: meta.client_unique_id.clone(), }; @@ -176,7 +176,7 @@ impl DatabaseSyncEngine

{ Ok(db) } - fn open_revert_db_conn(&mut self) -> Result> { + fn open_revert_db_conn(&self) -> Result> { let db = turso_core::Database::open_with_flags_bypass_registry( self.io.clone(), &self.main_db_path, @@ -191,10 +191,7 @@ impl DatabaseSyncEngine

{ Ok(conn) } - async fn checkpoint_passive( - &mut self, - coro: &Coro, - ) -> Result<(Option>, u64)> { + async fn checkpoint_passive(&self, coro: &Coro) -> Result<(Option>, u64)> { let watermark = self.meta().revert_since_wal_watermark; tracing::info!( "checkpoint(path={:?}): revert_since_wal_watermark={}", @@ -273,9 +270,13 @@ impl DatabaseSyncEngine

{ }) } - pub async fn checkpoint(&mut self, coro: &Coro) -> Result<()> { + pub async fn checkpoint(&self, coro: &Coro) -> Result<()> { let (main_wal_salt, watermark) = self.checkpoint_passive(coro).await?; + tracing::info!( + "checkpoint(path={:?}): passive checkpoint is done", + self.main_db_path + ); let main_conn = connect_untracked(&self.main_tape)?; let revert_conn = self.open_revert_db_conn()?; @@ -386,6 +387,7 @@ impl DatabaseSyncEngine

{ &file.value, &revision, self.opts.wal_pull_batch_size, + self.opts.long_poll_timeout, ) .await?; @@ -419,10 +421,17 @@ impl DatabaseSyncEngine

{ /// This method will **not** send local changed to the remote /// This method will block writes for the period of pull pub async fn apply_changes_from_remote( - &mut self, + &self, coro: &Coro, remote_changes: DbChangesStatus, ) -> Result<()> { + if remote_changes.file_slot.is_none() { + self.update_meta(coro, |m| { + m.last_pull_unix_time = remote_changes.time.secs; + }) + .await?; + return Ok(()); + } assert!(remote_changes.file_slot.is_some(), "file_slot must be set"); let changes_file = remote_changes.file_slot.as_ref().unwrap().value.clone(); let pull_result = self.apply_changes_internal(coro, &changes_file).await; @@ -447,7 +456,7 @@ impl DatabaseSyncEngine

{ Ok(()) } async fn apply_changes_internal( - &mut self, + &self, coro: &Coro, changes_file: &Arc, ) -> Result { @@ -652,7 +661,7 @@ impl DatabaseSyncEngine

{ /// Sync local changes to remote DB and bring new changes from remote to local /// This method will block writes for the period of sync - pub async fn sync(&mut self, coro: &Coro) -> Result<()> { + pub async fn sync(&self, coro: &Coro) -> Result<()> { // todo(sivukhin): this is bit suboptimal as both 'push' and 'pull' will call pull_synced_from_remote // but for now - keep it simple self.push_changes_to_remote(coro).await?; @@ -660,21 +669,14 @@ impl DatabaseSyncEngine

{ Ok(()) } - pub async fn pull_changes_from_remote(&mut self, coro: &Coro) -> Result<()> { + pub async fn pull_changes_from_remote(&self, coro: &Coro) -> Result<()> { let changes = self.wait_changes_from_remote(coro).await?; - if changes.file_slot.is_some() { - self.apply_changes_from_remote(coro, changes).await?; - } else { - self.update_meta(coro, |m| { - m.last_pull_unix_time = changes.time.secs; - }) - .await?; - } + self.apply_changes_from_remote(coro, changes).await?; Ok(()) } - fn meta(&self) -> std::cell::Ref<'_, DatabaseMetadata> { - self.meta.borrow() + fn meta(&self) -> std::sync::MutexGuard<'_, DatabaseMetadata> { + self.meta.lock().unwrap() } async fn update_meta( @@ -688,7 +690,7 @@ impl DatabaseSyncEngine

{ let completion = self.protocol.full_write(&self.meta_path, meta.dump()?)?; // todo: what happen if we will actually update the metadata on disk but fail and so in memory state will not be updated wait_all_results(coro, &completion).await?; - self.meta.replace(meta); + *self.meta.lock().unwrap() = meta; Ok(()) } } diff --git a/sync/engine/src/database_sync_operations.rs b/sync/engine/src/database_sync_operations.rs index daec39bc4..5197e04e0 100644 --- a/sync/engine/src/database_sync_operations.rs +++ b/sync/engine/src/database_sync_operations.rs @@ -166,6 +166,7 @@ pub async fn wal_pull_to_file( frames_file: &Arc, revision: &DatabasePullRevision, wal_pull_batch_size: u64, + long_poll_timeout: Option, ) -> Result { // truncate file before pulling new data let c = Completion::new_trunc(move |result| { @@ -195,7 +196,7 @@ pub async fn wal_pull_to_file( .await } DatabasePullRevision::V1 { revision } => { - wal_pull_to_file_v1(coro, client, frames_file, revision).await + wal_pull_to_file_v1(coro, client, frames_file, revision, long_poll_timeout).await } } } @@ -206,6 +207,7 @@ pub async fn wal_pull_to_file_v1( client: &C, frames_file: &Arc, revision: &str, + long_poll_timeout: Option, ) -> Result { tracing::info!("wal_pull: revision={revision}"); let mut bytes = BytesMut::new(); @@ -214,7 +216,7 @@ pub async fn wal_pull_to_file_v1( encoding: PageUpdatesEncodingReq::Raw as i32, server_revision: String::new(), client_revision: revision.to_string(), - long_poll_timeout_ms: 0, + long_poll_timeout_ms: long_poll_timeout.map(|x| x.as_millis() as u32).unwrap_or(0), server_pages: BytesMut::new().into(), client_pages: BytesMut::new().into(), }; @@ -805,12 +807,11 @@ pub async fn push_logical_changes( }), DatabaseTapeOperation::RowChange(change) => { let replay_info = generator.replay_info(coro, &change).await?; - let change_type = (&change.change).into(); match change.change { DatabaseTapeRowChangeType::Delete { before } => { let values = generator.replay_values( &replay_info, - change_type, + replay_info.change_type, change.id, before, None, @@ -827,7 +828,7 @@ pub async fn push_logical_changes( DatabaseTapeRowChangeType::Insert { after } => { let values = generator.replay_values( &replay_info, - change_type, + replay_info.change_type, change.id, after, None, @@ -848,7 +849,7 @@ pub async fn push_logical_changes( } => { let values = generator.replay_values( &replay_info, - change_type, + replay_info.change_type, change.id, after, Some(updates), @@ -869,7 +870,7 @@ pub async fn push_logical_changes( } => { let values = generator.replay_values( &replay_info, - change_type, + replay_info.change_type, change.id, after, None, @@ -1359,7 +1360,7 @@ pub async fn wait_proto_message( Error::DatabaseSyncEngineError(format!("unable to deserialize protobuf message: {e}")) })?; let _ = bytes.split_to(message_length + prefix_length); - tracing::debug!( + tracing::trace!( "wait_proto_message: elapsed={:?}", std::time::Instant::now().duration_since(start_time) ); diff --git a/sync/engine/src/database_tape.rs b/sync/engine/src/database_tape.rs index b98cd0847..b8dfdb820 100644 --- a/sync/engine/src/database_tape.rs +++ b/sync/engine/src/database_tape.rs @@ -10,7 +10,7 @@ use crate::{ database_sync_operations::WAL_FRAME_HEADER, errors::Error, types::{ - Coro, DatabaseChange, DatabaseTapeOperation, DatabaseTapeRowChange, + Coro, DatabaseChange, DatabaseChangeType, DatabaseTapeOperation, DatabaseTapeRowChange, DatabaseTapeRowChangeType, ProtocolCommand, }, wal_session::WalSession, @@ -584,7 +584,7 @@ impl DatabaseReplaySession { cached.stmt.reset(); let values = self.generator.replay_values( &cached.info, - change_type, + DatabaseChangeType::Delete, change.id, before, None, @@ -600,7 +600,7 @@ impl DatabaseReplaySession { cached.stmt.reset(); let values = self.generator.replay_values( &cached.info, - change_type, + DatabaseChangeType::Insert, change.id, after, None, @@ -643,7 +643,7 @@ impl DatabaseReplaySession { table, columns ); - let info = self.generator.insert_query(coro, table, columns).await?; + let info = self.generator.upsert_query(coro, table, columns).await?; let stmt = self.conn.prepare(&info.query)?; self.cached_insert_stmt .insert(key.clone(), CachedStmt { stmt, info });